当前位置: 代码迷 >> java >> frame.repaint()不起作用
  详细解决方案

frame.repaint()不起作用

热度:121   发布时间:2023-07-16 17:29:57.0

这是我直接从“ 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);

}
}

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

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

}
}

这将满足您的要求。

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

public class SimpleGui3C implements ActionListener {

    static JFrame frame = null;  // changed here...

    public static void main(String[] args) {
        frame = new JFrame();  // changed here....
        SimpleGui3C gui = new SimpleGui3C();
        gui.go();
    }

    public void go() {
        MyDrawPanel drawPanel = new MyDrawPanel();
        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);
    }
}

go()方法中...每次通过JFrame frame = new JFrame();创建新对象JFrame frame = new JFrame(); 因此,每次单击都会在屏幕上显示一个新框架...

通过在main()方法中创建对象,我们每次仅在同一jframe对象上调用repaint()方法,而不创建新对象。...

希望能有所帮助...

在处理Swing ,应牢记一些麻烦。 当我查看您使用的代码时,我想将其指出给您,使其走在正确的轨道上。

  1. 基于Swing的应用程序从其各自的线程(称为EventDispatcherThread ( EDT )而不是直接从main线程启动。 有关该主题的更多信息,请参见
  2. 尽量不要在paintComponent ( ... )方法内执行任何计算,而是在其他位置执行这些计算,而只需调用repaint ()
  3. paintComponent ( ... )的访问说明符是protected而不是public ,因此,在重写超类的方法时,请尽量不要更改方法的访问权限,直到没有必要为止。
  4. JPanel上绘制时,只需在JPanel实例上调用repaint () ,而不是顶层容器的
  5. 当扩展任何JComponenet/JPanel ,请始终尝试覆盖该JComponent/JPanelgetPreferredSize () ,因为许多布局将返回0 ,如果未指定任何布局,则不会进行绘制。
  6. 请记住要调用super.paintComponent ( g ) ,作为paintComponent ( ... )的第一行。 添加了注释以使内容更加清晰。
  7. 代替在JFrame上设置大小,而是尝试调用pack () ,如中所述,以获得附带的好处。 打包方法调整框架的大小,以便其所有内容均等于或大于其首选大小。 打包的另一种方法是通过调用setSize或setBounds(也设置帧位置)显式建立帧大小。 通常,使用pack优于调用setSize,因为pack由框架布局管理器负责框架大小,并且布局管理器擅长调整平台依赖性和其他影响组件大小的因素。

根据以上几点,这是经过修改的代码(刚刚在DrawPanel添加了一个名为setValues ()的方法,在DrawPanel方法中完成了计算,并称为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);
    }
}
  相关解决方案