JPanel设计问题

4

我有一个表单,在鼠标点击事件上画椭圆。这对我很有效。圆圈被绘制出来了。但是当我最小化表单并再次将其最大化时,面板会刷新并且圆圈会被删除(即面板变成空白)。

代码如下: 我有一个JFrame,在上面有一个名为jPanel1的Jpanel,在此面板上绘制圆圈。

private void jPanel1MouseClicked(java.awt.event.MouseEvent evt) {
        count += 1;
        if (count <= clients) {
            drawCircle(evt.getX() - (radius / 2), evt.getY() - (radius / 2));
        }
    }

    public void drawCircle(int x, int y) {
        Graphics g = jPanel1.getGraphics();
        g.drawOval(x - radius, y - radius, 2 * radius, 2 * radius);
        g.setColor(Color.BLACK);
        g.fillOval(x - radius, y - radius, 2 * radius, 2 * radius);
    }

1
最重要的是不要使用getGraphics()(正如答案中已经提到的那样,这里再次强调 :))。 - kleopatra
3个回答

7
在这种情况下,不仅需要覆盖JPanel的paintComponent方法,还需要存储关于要绘制的圆形的信息。您可以使用存储的信息在paintComponent调用期间绘制屏幕上的所有圆形。
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import javax.swing.*;



public class TempProject extends JPanel{
    /** Stores info about circles  */
    public ArrayList<CircleInfo> circles = new ArrayList<CircleInfo>();

    /** fields that were in example code */
    public int count = 0;
    public final int radius = 20;
    public final int clients = 20;

    public TempProject(){

        addMouseListener(new MouseAdapter(){

            @Override
            public void mouseClicked(MouseEvent evt) {
                count += 1;
                if (count <= clients) {
                        // Store info about the circle to draw
                    circles.add(new CircleInfo(evt.getX() - (radius / 2), evt.getY() - (radius / 2), radius));
                        // Tell swing to repaint asap
                    repaint();
                }
            }});
    }

    @Override
    public void paintComponent(Graphics g ) {
            super.paintComponent(g);

            //Iterates through saved circles and paints them
        for(CircleInfo circle : circles){
            g.drawOval(circle.x - circle.radius, circle.y - circle.radius, 2 * circle.radius, 2 * circle.radius);
            g.setColor(Color.BLACK);
            g.fillOval(circle.x - circle.radius, circle.y - circle.radius, 2 * circle.radius, 2 * circle.radius);
        }
    }

    public static void main(String args[])    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                frame.setContentPane(new TempProject());  
                frame.setPreferredSize(new Dimension(400, 300));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    /** Simple class for storing Circle info */
    public static class CircleInfo{
        int x = 0;
        int y = 0;
        int radius = 0;

        public CircleInfo(int x, int y, int radius){
            this.x = x; this.y = y; this.radius = radius;
        }
    }

}

@AndrewThompson 在看到你在另一个答案中的评论之前,我忘记添加 super.paintComponent 了 :P 真是糊涂!感谢你让我保持诚实! - Nick Rippe
很高兴我能在那种微小的方式下提供帮助。 - Andrew Thompson
@NickRippe 真的是一个非常好的回答。它真的非常有帮助。 - Azuu

3

您不需要在JPanelpaintComponent方法之外显式调用绘制函数。

相反,您应该扩展JPanel并将drawCircle代码放在paintComponent方法中:

public class DrawCircleClass extends JPanel
{
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawOval(x - radius, y - radius, 2 * radius, 2 * radius);
        g.setColor(Color.BLACK);
        g.fillOval(x - radius, y - radius, 2 * radius, 2 * radius);
    }

}

当组件需要重新绘制时(例如最大化最小化的窗口后),Swing会自动调用paintComponent方法。


当我点击绘制第二个圆时,第一个圆将不可见。jPanel被重新设计了。 - Azuu
找到解决方法了。我在paintComponent()方法中编写了super.PaintComponent()方法,这就是为什么它一直被重新设计的原因。 - Azuu
需要注意的是,如果您不保存圆形信息并从中重新绘制,则在调整大小时仍会出现丢失圆形的问题(请参见我的答案中的示例)。不过您可能已经解决了这个问题。 - Nick Rippe
1
代码应该调用super.paintComponent(g)。如果没有它就能“工作”,那么它是有问题的。 - Andrew Thompson

2
所有的绘图必须在面板的paint方法中完成。因此,您必须在面板中重写此方法并将绘图代码放在那里。

当然你是指 _paintComponent_(而不是 paint) :-) - kleopatra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接