简体   繁体   English

使用带有actionPerformed的repaint()方法

[英]using repaint() method with actionPerformed

How to use the repaint() method when a button is pressed and Graphics p has to re-paint everything from scratch? 按下按钮时如何使用repaint()方法,Graphics p必须从头开始重新绘制所有内容?

Thanks. 谢谢。

  import javax.swing.Box;
  import javax.swing.JButton;
  import javax.swing.JTextField;
  import java.awt.*;
  import java.awt.event.*;
  import javax.swing.*;

  class fares extends JPanel{

    private static final long serialVersionUID = 1L;
    public static int xaxis1,xaxis2,yaxis3,yaxis4;

public ControlsB(square) {

    final JButton btn1 = new JButton("Resize");

    final Box b = Box.createHorizontalBox();
    b.add(new JLabel("Please enter range:  "));
    Box b0 = Box.createVerticalBox();//create a vertical box to stack the controls

    Box b1 = Box.createHorizontalBox(); // create a horizontal box for the x-axis

    //x-axis
    b1.add(new JLabel("mark "));
    b1.add(new JLabel("for"));

    f1.setMaximumSize(new Dimension(100,30));

    b1.add(f1);
    b1.add(new JLabel("till"));

    f2.setMaximumSize(new Dimension(100,30));
    b1.add(f2);

    //y-axis
    //this code is not in use at the moment

    f4.setMaximumSize(new Dimension(100,30));
    b2.add(f4);

    b0.add(b1);

    add(b);

    btn1.addActionListener(new ActionListener(){

        public void actionPerformed(ActionEvent event){

            f = Integer.parseInt(f1.getText());

            invalidate();
            validate();
            paint(p);//this is not working...
        }
    });
 b.add(btn1);
  }
}

This is the code that has to be called and repainted: 这是必须调用和重新绘制的代码:

import java.awt.*;

import javax.swing.*;

class Graph extends JPanel {

public static Graphics p;
private static final long serialVersionUID = 1L;
public static int f;
public static int g;

@Override
public Dimension getPreferredSize()
{   
    return (new Dimension(560,560));
}

public void paintComponent(Graphics p) {

    super.paintComponent(p);

    Graphics2D graph = (Graphics2D)p;

    Dimension appletSize = this.getSize();
    int appletHeight = (int)(appletSize.height);
    int appletWidth = appletSize.width;

    //change -ve num to +ve
    int g3 = Math.abs(g);

    int a1 = g3 + f;
    int b1 = a1;


    int d = (appletWidth / a1);
    int e = (appletHeight / b1);

    //draw y-axis numbers 
    //(+ve)
    while(f != 0){
        String s = String.valueOf(f);

        m = m + b;
        f = f - 1;
    }
    //(-ve)
    m2 = y;
    while(f2 != g-1)
        m2 = m2 + b;
        f2 = f2 - 1;
    }
    //draw x-axis numbers.
    //(-ve)
    while(g != 0){
        String hy = String.valueOf(g);

        n = n + a;
        g = g + 1;
    }
    //(+ve)
    n2 = x + a;
    while(g2 != g3+1){
        String w = String.valueOf(g2);
        n2 = n2 + a;
        g2 = g2 + 1;
    }

    BasicStroke aLine2 = new BasicStroke(1.0F,
                                         BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
    graph.setStroke(aLine2);

    //notch on numbers and grid lines
    //left to right, top to bottom notches
    int v2 = -5;
    int v5 = 0;
    while(i <= a1-1){
        p.setColor(Color.lightGray);//lightgray line
        a = a + d;
        b = b + e;
        i = i + 1;
    }

  }
}

At the moment the resize button works, but I need to resize my window in order for the graph to respond to the inputs given. 目前调整大小按钮工作,但我需要调整窗口大小,以便图形响应给定的输入。 Basically when resizing the graph is being redrawn / repainted... now I need this to be done automatically. 基本上在重新调整图形大小时正在重新绘制/重新绘制...现在我需要自动完成此操作。

It's hard to tell what's wrong based on snippets of code, but it appears that your graph is drawn on the Graph object, called graph (please correct me if I'm wrong), and you appear to be trying to repaint (or paint -- never call that directly!) your ControlsB panel. 基于代码片段很难分辨出什么是错误的,但看起来您的图形是在Graph对象上绘制的,称为图形(如果我错了请纠正我),并且您似乎正在尝试重绘(或绘制 - - 永远不要直接调用它!)你的ControlsB面板。 If so, then you may be calling methods on the wrong object. 如果是这样,那么您可能正在调用错误对象上的方法。 Perhaps you need to do something like: 也许你需要做一些事情:

// graph is final so it may be used in an inner class
public ControlsB(Box box2, final Graph graph) {

     // .....

      btn1.addActionListener(new ActionListener(){

        public void actionPerformed(ActionEvent event){

            f = Integer.parseInt(f1.getText());
            g = Integer.parseInt(f2.getText());
            System.out.println(f + "  " + g);

            // invalidate();
            // validate();
            //  paint(p); ***** NEVER do this

            graph.repaint();
        }
    });
}

Also: 也:

  • Never call paint(...) directly on a component except in very special circumstances (this isn't it). 除非在非常特殊的情况下,否则不要直接在组件上调用paint(...) (这不是它)。
  • Never try to hold on to a components Graphics object and draw with it as this will often lead to a NullPointerException occurring, and it surely won't work. 永远不要试图抓住组件Graphics对象并使用它进行绘制,因为这通常会导致NullPointerException发生,并且肯定不会起作用。
  • Do read up on how to do drawing in Swing in the standard Swing tutorials. 请阅读标准Swing教程中如何在Swing中进行绘图。 You would likely learn much from doing this. 你可能会从这方面学到很多东西。
  • Again, if you don't get a decent answer soon, consider creating and posting an sscce . 同样,如果您很快得不到合适的答案,请考虑创建和发布sscce

帮助图

Changes made : 做出的改变:

- Inside the GraphApplet class, these two lines have been changed - 在GraphApplet类中,这两行已被更改

Box box2 = new Box(BoxLayout.Y_AXIS); // Changed
// Added one more argument, while making Object.
ControlsB b = new ControlsB(box2, graph);//horizontal
  • Inside Graph Class, setValues(...) method has been added. 在Graph Class中,添加了setValues(...)方法。

- -

public void setValues(int x, int y)
{
    xstart = x;
    ystart = y;
    repaint();
}
  • Inside Graph class, scope of variables xstart and ystart has been changed to Instance/Class Graph类中,变量xstartystart范围已更改为Instance/Class

- Inside ControlB Class - 内部ControlB类

refineButton = new JButton("Refine");
buttonBox.add(refineButton);
refineButton.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent ae)
    {
        int x = Integer.parseInt(f1.getText());
        int y = Integer.parseInt(f3.getText());
        /*
         * Calling a method of Graph Class (setValues)
         * and passing the values that we had got from
         * the respective JTextFields.
         */
        graph.setValues(x, y);          }
    });
}

Here watch this code example, modified your previous example a bit to give you one idea how to make this work. 在这里观看这个代码示例,稍微修改了您之前的示例,以便您了解如何使其工作。 Have a look at the image attached, only use these three thingies, enter some integer values in the pointed JTextField s and then click on Refine JButton , you will see how to repaint. 看看附加的图像,只使用这三个东西,在指向的JTextField输入一些整数值,然后点击Refine JButton ,你会看到如何重绘。 Since I really don't know how the logic works, hence won't be able to say how you can optimize your code, though to give you one idea, here it is : 由于我真的不知道逻辑是如何工作的,因此无法说明如何优化代码,虽然给你一个想法,这里是:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;

public class GraphApplet extends JApplet
{
    private static final long serialVersionUID = 1L;

    public void init(){

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                Container conn = getContentPane();
                conn.setLayout(new BorderLayout());

                Graph graph = new Graph();//graph
                conn.add(graph,BorderLayout.CENTER);

                Box box1 = new Box(BoxLayout.X_AXIS);
                ControlsA a = new ControlsA(box1);//vertical
                conn.add(a,BorderLayout.EAST);

                Box box2 = new Box(BoxLayout.Y_AXIS); // Changed
                // Added one more argument, while making Object.
                ControlsB b = new ControlsB(box2, graph);//horizontal
                conn.add(b,BorderLayout.SOUTH);
            }
        });
    }
}

class Graph extends JPanel {

    private static final long serialVersionUID = 1L;
    private int xstart;
    private int ystart;

    public Graph(){
        this.setBackground(Color.yellow);
    }

    @Override
    public Dimension getPreferredSize()
    {   
        return (new Dimension(460,560));
    }

    /*
     * Added this method, which will call
     * repaint(), everytime it is been
     * called from anywhere. Moreover
     * the variables used inside 
     * paintComponent(...) method xstart
     * and ystart, have been changed to 
     * instance variables of the Graph Class.
     */
    public void setValues(int x, int y)
    {
        xstart = x;
        ystart = y;
        repaint();
    }

    @Override
    public void paintComponent(Graphics p) 
    {

        super.paintComponent(p);

        Graphics2D graph = (Graphics2D)p;

        Dimension appletSize = this.getSize();
        int appletHeight = (int)(appletSize.height);
        int appletWidth = appletSize.width;

        this.setBackground(Color.yellow);//set background color.

        int x,y,y1,x1,a,b,p1x,p1y,p2x,p2y;

        //line co-ordinates
        //the numbers represent the number of boxes on the graph
        // Made these two variables as Instance Variables
        //int xstart = 10;
        //int ystart = 5;

        int xfinish = 2;
        int yfinish = 8;

        //other variables
        int i = 0;
        int i2 = 0;
        int m = 0;
        int n = 0;
        int m2 = 0;
        int n2 = 0;
        int f2 = 0;
        int g2 = 1;

        //ranges
        int f = 5;
        int g = -5;

        //change -ve num to +ve
        int g3 = Math.abs(g);

        int a1 = g3 + f;
        int b1 = a1;

        y1 = (appletHeight);
        x1 = (appletWidth);
        y = (appletHeight / 2);
        x = (appletWidth / 2);
        a = (appletWidth / a1);
        b = (appletHeight / b1);

        int d = (appletWidth / a1);
        int e = (appletHeight / b1);

        /**
        to determine the
        ammount of pixles there
        is in each box of the
        graph, both y-axis and 
        x-axis
        */
        int xbox = x1 / 10;
        int ybox = y1 / 10;

        //line variables
        //the xstart, ystart, etc represent the number of boxes

        //top point of the line on the graph
        p1x = xbox * xstart;//start x
        p1y = ybox * ystart;//start y

        //lowwer point of the line on the graph
        p2x = xbox * xfinish;//finish x
        p2y = ybox * yfinish;//finish y

        //draw y-axis numbers 
        //(+ve)
        while(f != 0){
            String s = String.valueOf(f);
            p.drawString(s,(x + 5),m + 13);
            m = m + b;
            f = f - 1;
        }
        //(-ve)
        m2 = y;
        while(f2 != g-1){
            String u = String.valueOf(f2);
            p.drawString(u,(x + 5),m2 - 3);
            m2 = m2 + b;
            f2 = f2 - 1;
        }
        //draw x-axis numbers.
        //(-ve)
        while(g != 0){
            String t = String.valueOf(g);
            p.drawString(t,n,y - 5);
            n = n + a;
            g = g + 1;
        }
        //(+ve)
        n2 = x + a;
        while(g2 != g3+1){
            String vw = String.valueOf(g2);
            p.drawString(vw,n2 -10,y - 5);
            n2 = n2 + a;
            g2 = g2 + 1;
        }

        BasicStroke aLine2 = new BasicStroke(1.0F,
                 BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine2);

        //notch on numbers and grid lines
        //left to right, top to bottom notches
        int v2 = -5;
        int v5 = 0;
        while(i <= a1-1){
            p.setColor(Color.lightGray);//lightgray line
            p.drawLine(a,0,a,y1);//vertical lightgray
            p.drawLine(0,b,x1,b);//horizontal lightgray
            a = a + d;
            b = b + e;
            i = i + 1;
        }
        //notches
        while(i2 <= a1){
            p.setColor(Color.blue);//notch color
            p.drawString("x",v2+2,y+3);//xaxis
                p.drawString("x",x-4,v5+4);//yaxis
            v5 = v5 + e;
            v2 = v2 + d;
            i2 = i2 + 1;
        }

        //draws the border of the graph
        p.setColor(Color.black);
        Rectangle2D.Float rect = new Rectangle2D.Float(0,0,x1,y1);
        BasicStroke aLine = new BasicStroke(2.5F, 
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine);
        graph.draw(rect);

        //draw cross
        BasicStroke aLine3 = new BasicStroke(2.5F,
                BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine3);
        p.drawLine(x,0,x,y1); //vertical line
        p.drawLine(0,y,x1,y); //horizontal line

        //display the value of graph width and graph height
        String aw = String.valueOf(x1);
        p.drawString("Graph Width = ", 50,90);
        p.drawString(aw,150,90);
        p.drawString("Graph Height = ", 50,110);
        String ah = String.valueOf(y1);
        p.drawString(ah,156,110);

        //draw line on graph

        BasicStroke aLine4 = new BasicStroke(1.5F,
            BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        graph.setStroke(aLine4);
        p.setColor(Color.red);

        if(p1x <= x1 && p2x <= x1 && p1y <= y1 && p2y <= y1){
            p.drawLine(p1x,p1y,p2x,p2y);
            Color c = new Color(0,0,0);
            p.setColor(c);
            p.drawString("X", p1x-4,p1y+4);
            p.drawString("X", p2x-4,p2y+4);
        }           
        else{
            p.setColor(Color.black);
            p.drawRect(48,34,223,35);
            p.setColor(Color.white);
            p.fillRect(49,35,222,34);
            p.setColor(Color.red);
            p.drawString("Wrong co-ordinates!!!", 50,50);
            p.drawString("Values exceede applet dimensions.", 50,65);
        }
    }
}

class ControlsA extends JPanel
{

    private static final long serialVersionUID = 1L;

    public ControlsA (Box a) 
    {

        a = Box.createVerticalBox();
        a.add(new JLabel("Please enter the values below:"));
        a.add(new JLabel("a"));
        JTextField g1 = new JTextField("0.0");
        g1.setMaximumSize(new Dimension(100,30));
        a.add(g1);
        a.add(new JLabel("b"));
        JTextField g2 = new JTextField("0.0");
        g2.setMaximumSize(new Dimension(100,30));
        a.add(g2);
        a.add(new JLabel("c"));
        JTextField g3 = new JTextField("0.0");
        g3.setMaximumSize(new Dimension(100,30));
        a.add(g3);
        a.add(new JLabel("d"));
        JTextField g4 = new JTextField("0.0");
        g4.setMaximumSize(new Dimension(100,30));
        a.add(g4);
        a.add(new JButton("Plot"));
        a.add(new JButton("Refine"));
        add(a);
    }

    @Override
    public Dimension getPreferredSize()
    {   
        return (new Dimension(200,100));
    }
}

class ControlsB extends JPanel
{

    private static final long serialVersionUID = 1L;
    private Graph graph;
    private JButton refineButton;

    public ControlsB (Box b, Graph g) {

        graph = g;
        b = Box.createVerticalBox();
        Box boxUpper = new Box(BoxLayout.X_AXIS);
        boxUpper.add(new JLabel("Please enter range:  "));
        b.add(boxUpper);
        Box boxX = new Box(BoxLayout.X_AXIS);
        boxX.add(new JLabel(" x-axis "));
        boxX.add(new JLabel("from"));
        // Added final keyword.
        final JTextField f1 = new JTextField("-5");
        f1.setMaximumSize(new Dimension(100,30));
        boxX.add(f1);
        boxX.add(new JLabel(" to "));
        JTextField f2 = new JTextField("5");
        f2.setMaximumSize(new Dimension(100,30));
        boxX.add(f2);
        b.add(boxX);
        //b.add(new JLabel(".   "));
        Box boxY = new Box(BoxLayout.X_AXIS);
        boxY.add(new JLabel("y-axis "));
        boxY.add(new JLabel("from"));
        // Added final keyword.
        final JTextField f3 = new JTextField("5");
        f3.setMaximumSize(new Dimension(100,30));
        boxY.add(f3);
        boxY.add(new JLabel("to"));
        JTextField f4 = new JTextField("-5");
        f4.setMaximumSize(new Dimension(100,30));
        boxY.add(f4);
        b.add(boxY);
        Box buttonBox = new Box(BoxLayout.X_AXIS);
        buttonBox.add(new JButton("Plot"));
        /* 
         * Made this an instance variable,
         * and added ActionListener to it.
         */
        refineButton = new JButton("Refine");
        buttonBox.add(refineButton);
        refineButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                int x = Integer.parseInt(f1.getText());
                int y = Integer.parseInt(f3.getText());
                /*
                 * Calling a method of Graph Class (setValues)
                 * and passing the values that we had got from
                 * the respective JTextFields.
                 */
                graph.setValues(x, y);
            }
        });
        b.add(buttonBox);       
        add(b);
    }

    @Override
    public Dimension getPreferredSize()
    {   
        return (new Dimension(200,100));
    }
}

Congrats, you just stumbled upon the subtleties of repaint :) There is a quite nice explanation at http://www.oracle.com/technetwork/java/painting-140037.html#paint_process . 恭喜,你只是偶然发现了重绘的微妙之处:) http://www.oracle.com/technetwork/java/painting-140037.html#paint_process有一个很好的解释。 Here is the summary: 以下是摘要:

  • If you call repaint() on a heavyweight component like JFrame or JApplet, it will repaint immediately. 如果在JFrame或JApplet等重量级组件上调用repaint(),它将立即重新绘制。
  • If you call repaint() on a JComponent, it will "schedule" the repainting to occur at some point in the future as decided by the Repaint Manager (which means, you have no control over it). 如果你在一个JComponent上调用repaint(),它将“调度”重绘在将来的某个时刻发生,如Repaint Manager所决定的(这意味着你无法控制它)。

So, call the repaint() method in JApplet and you should see the changes as soon as you click the button. 因此,在JApplet中调用repaint()方法,您应该在单击按钮后立即看到更改。

Have you tried instead of paint(p) to use p.repaint() or p.update(p.getGraphics()) ? 您是否尝试使用p.repaint()p.update(p.getGraphics())而不是paint(p) p.update(p.getGraphics())

I have not done Swing for ages and I can't remember exactly how it's behaving. 我没有完成Swing多年,我不记得它是如何表现的。 One sure thing is that you have to be aware of when it is the good time to call paint , update or validate and how to use correctly the EventDispatcherThread (EDT). 可以肯定的是,您必须知道何时是调用paintupdatevalidate以及如何正确使用EventDispatcherThread(EDT)的好时机。 Otherwise your application will look like a lot of java swing applications : a crap filled of UI bugs... 否则你的应用程序将看起来像很多java swing应用程序:一堆填充的UI错误......

I don't say Swing is crap, I say that if you don't know how it works, your UI will be a crap. 我不是说Swing是废话,我说如果你不知道它是如何工作的,你的UI将是一个垃圾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM