【问题标题】:using repaint() method with actionPerformed使用带有 actionPerformed 的 repaint() 方法
【发布时间】:2012-06-23 04:23:29
【问题描述】:

当一个按钮被按下并且图形 p 必须从头开始重新绘制所有内容时,如何使用 repaint() 方法?

谢谢。

  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);
  }
}

这是必须调用和重新绘制的代码:

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;
    }

  }
}

目前调整大小按钮有效,但我需要调整窗口大小以使图表响应给定的输入。基本上在调整图形大小时正在重新绘制/重新绘制......现在我需要自动完成。

【问题讨论】:

  • 摆脱您的 Graphics 变量 p,因为您永远不应该尝试抓住组件的 Graphics 对象并使用它进行绘制。如果它不会导致 NullPointerException 发生,它将根本不起作用。如果您没有很快得到合适的答案,请考虑创建并发布sscce

标签: java swing repaint graphics2d japplet


【解决方案1】:

根据代码的 sn-ps 很难判断出了什么问题,但您的图表似乎是在名为 graph 的 Graph 对象上绘制的(如果我错了,请纠正我),而且您似乎正在尝试重新绘制(或绘制——永远不要直接调用它!)你的 ControlsB 面板。如果是这样,那么您可能在错误的对象上调用方法。或许您需要执行以下操作:

// 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();
        }
    });
}

还有:

  • 切勿直接在组件上调用paint(...),除非在非常特殊的情况下(不是这样)。
  • 切勿试图抓住组件 Graphics 对象并使用它进行绘制,因为这通常会导致 NullPointerException 发生,而且肯定不会起作用。
  • 请阅读标准 Swing 教程中有关如何在 Swing 中进行绘图的内容。您可能会从中学到很多东西。
  • 同样,如果您没有很快得到一个体面的答案,请考虑创建并发布sscce

【讨论】:

    【解决方案2】:

    所做的更改:

    - 在GraphApplet 类中,这两行已更改

    Box box2 = new Box(BoxLayout.Y_AXIS); // Changed
    // Added one more argument, while making Object.
    ControlsB b = new ControlsB(box2, graph);//horizontal
    
    • Graph Class 内部,已添加setValues(...) 方法。

    -

    public void setValues(int x, int y)
    {
        xstart = x;
        ystart = y;
        repaint();
    }
    
    • Graph 类中,变量xstartystart 的范围有 已改为Instance/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);          }
        });
    }
    

    在这里观看此代码示例,稍微修改您之前的示例,让您了解如何使其工作。看一下附图,只用这三个东西,在指向的JTextFields 中输入一些整数值,然后点击Refine JButton,你会看到如何重绘。由于我真的不知道逻辑是如何工作的,因此无法说出如何优化代码,尽管给你一个想法,这里是:

    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));
        }
    }
    

    【讨论】:

      【解决方案3】:

      恭喜,你偶然发现了重绘的微妙之处:) http://www.oracle.com/technetwork/java/painting-140037.html#paint_process 有一个很好的解释。总结如下:

      • 如果您在 JFrame 或 JApplet 等重量级组件上调用 repaint(),它将立即重新绘制。
      • 如果您在 JComponent 上调用 repaint(),它会根据重绘管理器的决定“安排”在未来某个时间点进行重绘(这意味着您无法控制它)。

      因此,在 JApplet 中调用 repaint() 方法,您应该会在单击按钮后立即看到更改。

      【讨论】:

        【解决方案4】:

        您是否尝试过使用p.repaint()p.update(p.getGraphics()) 而不是paint(p)

        我已经很久没有使用 Swing 了,我也记不清它的具体表现了。一件确定的事情是,您必须知道何时是调用paintupdatevalidate 的好时机,以及如何正确使用EventDispatcherThread (EDT)。否则你的应用程序会看起来像很多 java swing 应用程序:一个充满 UI 错误的废话......

        我不是说 Swing 是垃圾,我是说如果你不知道它是如何工作的,那么你的 UI 就是垃圾。

        【讨论】:

          猜你喜欢
          • 2011-02-22
          • 1970-01-01
          • 2013-04-21
          • 1970-01-01
          • 2013-03-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-27
          相关资源
          最近更新 更多