frame.repaint() 不起作用

plu*_*ava 1 java swing awt actionlistener

这是我直接从“Head First Java”获得的来源,但无论我做什么,我似乎都无法使其工作,而且我不知道我可能会错过什么

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class SimpleGui3C implements ActionListener {

    JFrame frame;

    public static void main(String[] args) {

        SimpleGui3C gui = new SimpleGui3C();
        gui.go();
    }

public void go() {

    MyDrawPanel drawPanel = new MyDrawPanel();

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton button = new JButton("Change colors");
    button.addActionListener(this);

    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
    frame.setSize(300, 300);
    frame.setVisible(true);
}

public void actionPerformed(ActionEvent event) {


    frame.repaint();
    }
}

class MyDrawPanel extends JPanel {

    public void paintComponent(Graphics g) {

        g.setColor(Color.white);
        g.fillRect(0, 0, 300, 300);

    int red = (int) (Math.random() * 255);
    int green = (int) (Math.random() * 255);
    int blue = (int) (Math.random() * 255);

    Color randomColor = new Color(red, green, blue);
    g.setColor(randomColor);
    g.fillOval(70, 70, 100, 100);

}
}
Run Code Online (Sandbox Code Playgroud)

我试图找到另一种方法来做到这一点,它不涉及重新绘制,而是在事件发生时创建 MyDrawPanel 的新实例,但它仍然不起作用,因为我没有找到正确清除面板的方法,到目前为止我发现的唯一黑客就是这样做,但这不是我想要实现的......

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class SimpleGui3C implements ActionListener {

    JFrame frame;

    public static void main(String[] args) {

    SimpleGui3C gui = new SimpleGui3C();
    gui.go();
}

public void go() {

    MyDrawPanel drawPanel = new MyDrawPanel();

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JButton button = new JButton("Change colors");
    button.addActionListener(this);

    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
    frame.setSize(300, 300);
    frame.setVisible(true);
}

    public void actionPerformed(ActionEvent event) {
        go();
    }
}



class MyDrawPanel extends JPanel {

    int red;
    int green;
    int blue;

    public MyDrawPanel() {

    this.red = (int) (Math.random() * 255);
    this.green = (int) (Math.random() * 255);
    this.blue = (int) (Math.random() * 255);
}

public void paintComponent(Graphics g) {

    g.setColor(Color.white);
    g.fillRect(0, 0, 300, 300);

    Color randomColor = new Color(this.red, this.green, this.blue);
    g.setColor(randomColor);
    g.fillOval(70, 70, 100, 100);

}
}
Run Code Online (Sandbox Code Playgroud)

nIc*_*cOw 5

在处理事情的时候Swing,人们应该记住一些事情。当我查看您使用的代码时,我想向您指出,以使其走上正确的道路。

  1. Swing基于应用程序的应用程序从它们自己各自的线程(称为 )启动,EventDispatcherThread ( EDT )而不是直接从 main 启动。有关该主题的更多信息可以在Swing 中的并发上找到
  2. 尽量不要在paintComponent ( ... )方法内部执行任何计算,而是在其他地方执行这些计算,然后简单地调用repaint ()
  3. paintComponent ( ... )isprotected和 not的访问说明符public,因此在重写超类的方法时,尽量不要更改方法访问权限,除非不必要。
  4. 当您在 a 上绘图时,只需在 的实例上JPanel调用,而不是顶层容器的repaint ()JPanel
  5. 当一个人扩展任何一个时JComponenet/JPanel,总是尝试覆盖上述的布局JComponent/JPanel,如果没有指定,getPreferredSize ()将返回尽可能多的布局0,因此不会进行任何绘制。
  6. 一定要记得打电话super.paintComponent ( g ),作为里面的第一行paintComponent ( ... )。为了更加清晰,添加了评论。
  7. 不要在 上设置 size JFrame,而是尝试调用pack (),如Java 文档中所述,以获得附带的好处。pack 方法调整框架的大小,以便其所有内容都等于或大于其首选大小。pack 的替代方法是通过调用 setSize 或 setBounds(这也设置帧位置)显式建立帧大小。一般来说,使用 pack 比调用 setSize 更好,因为 pack 让框架布局管理器负责框架大小,而布局管理器擅长调整平台依赖性和影响组件大小的其他因素。

这是修改后的代码(只是在里面添加了一个方法DrawPanel,称为setValues (),在其中完成计算并被repaint ()调用),基于以上几点:

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

public class SimpleGui implements ActionListener {

    private MyDrawPanel drawPanel;

    public static void main(String[] args) {
        Runnable r = new Runnable () {
            @Override
            public void run () {
                new SimpleGui ().go ();
            }
        };
        EventQueue.invokeLater ( r );
    }

    public void go() {
        drawPanel = new MyDrawPanel();

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
        JButton button = new JButton( "Change colors" );
        button.addActionListener( this );

        frame.add( drawPanel, BorderLayout.CENTER );
        frame.add( button, BorderLayout.PAGE_END );
        frame.pack ();
        frame.setLocationByPlatform ( true );
        frame.setVisible(true);
    }

    public void actionPerformed(ActionEvent event) {
        drawPanel.setValues ();
    }
}

class MyDrawPanel extends JPanel {

    private int width = 300;
    private int height = 300;

    private int red;
    private int green;
    private int blue;

    private Color randomColor;

    /*
     * Make this one customary habbit,
     * of overriding this method, when
     * you extends a JPanel/JComponent,
     * to define it's Preferred Size.
     * Now in this case we want it to be 
     * as big as the Image itself.
     */
    @Override
    public Dimension getPreferredSize () {
        return new Dimension ( width, height );
    }

    public void setValues () {
        red = ( int ) ( Math.random() * 255 );
        green = ( int) ( Math.random() * 255 );
        blue = ( int ) ( Math.random() * 255 );

        randomColor = new Color( red, green, blue );

        repaint ();
    }

    /*
     * This is where the actual Painting
     * Code for the JPanel/JComponent goes.
     * Here the first line super.paintComponent(...),
     * means we want the JPanel to be drawn the usual 
     * Java way first (this usually depends on the opaque
     * property of the said JComponent, if it's true, then
     * it becomes the responsibility on the part of the
     * programmer to fill the content area with a fully
     * opaque color. If it is false, then the programmer
     * is free to leave it untouched. So in order to 
     * overcome the hassle assoicated with this contract,
     * super.paintComponent(g) is used, since it adheres
     * to the rules, and performs the same task, depending
     * upon whether the opaque property is true or false),
     * then later on we will add our image to it, by 
     * writing the other line, g.drawImage(...).
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent ( g );

        g.setColor(randomColor);
        g.fillOval(70, 70, 100, 100);
    }
}
Run Code Online (Sandbox Code Playgroud)