【问题标题】:Why doesn't repaint() work when called by a method of an object of the same class?当被同一类的对象的方法调用时,为什么 repaint() 不起作用?
【发布时间】:2017-04-17 21:06:37
【问题描述】:

在我为我的类构建的程序中,我有一个扩展 Swing JPanel 并实现 MouseListener 的类,为此我使用两个实例化 - 一个用作 JPanel,另一个用作该 JPanel 的鼠标侦听器.

但是当我在窗口中单击时,repaint() 鼠标侦听器中的 MouseClicked 方法无法调用第一个对象的 paintComponent() 方法。例如:

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

public class TestPanel extends JPanel implements MouseListener{
    static boolean black;
    static TestPanel test = new TestPanel();

    public void mouseExited(MouseEvent e){}
    public void mousePressed(MouseEvent e){}
    public void mouseReleased(MouseEvent e){}
    public void mouseEntered(MouseEvent e){}
    public void mouseClicked(MouseEvent e){ //Expected behavior: the square turns black immediately
        System.out.println("CLICK!");
        black = true;
        test.repaint(); //this fails
        try{
            Thread.sleep(3000);
        }catch(Exception ex){}
    }

    public void paintComponent(Graphics g){
         super.paintComponent(g);
         Graphics2D g2d = (Graphics2D) g;
         System.out.println("Painting...");
         g2d.setColor(Color.white);
         if(black){
             g2d.setColor(Color.black);
         }
         g2d.fillRect(0, 0, 200, 200);
    }

    public static void main(String[] args) throws InterruptedException{
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.addMouseListener(new TestPanel());
        test.setPreferredSize(new Dimension(200, 200));
        frame.add(test);
        frame.pack();
        frame.setVisible(true);
        while (true){
            black = false;
            test.repaint();
            Thread.sleep(100);
        }
    }
}

如果您观察单击时发生的情况,则在单击注册后屏幕会保持白色 3 秒,直到循环再次启动,即鼠标侦听器中的 repaint() 调用不起作用。为什么会这样?

我猜如果我为对象创建不同的类会起作用,但我很好奇为什么它不能以这种方式起作用。

【问题讨论】:

  • 不要阻塞 EDT(事件调度线程)。发生这种情况时,GUI 将“冻结”。有关详细信息和修复,请参阅Concurrency in Swing。如果您想延迟效果,请将其安排在基于 Timer 的单次 Swing 上。
  • 没有多个线程有没有办法做到这一点?到目前为止,我的程序只使用一个线程。
  • “没有多线程有没有办法做到这一点?” Swing Timer 在 EDT 上运行..
  • 这很奇怪,当我在 main 方法中执行完全相同的操作时,它工作正常。我只是在外部方法中遇到了这个问题。
  • 这没什么奇怪的——从 main 方法运行的代码没有在 Swing 事件线程上运行。但这不是解决您的问题的安全解决方案,因为这会引入其他间歇性问题的风险,因为您正在从 Swing 事件线程运行一些 Swing 代码。至于"...isn't really what I had in mind..."——很难猜出你的想法。您引入延迟的主要目的是什么?如果您需要设置延迟,请使用 Swing Timer。如果没有,那你想做什么?

标签: java swing paint


【解决方案1】:

为此,我使用了两个实例化——一个用作 JPanel,另一个用作该 JPanel 的鼠标侦听器。

没有必要这样做。您只需要一个 TestPanel 类的实例。

TestPanel 类的构造函数中添加:

addMouseListener( this);

去掉TestPanel类的静态变量。

那么你的 main 方法中的代码应该是这样的:

    //test.addMouseListener(new TestPanel());
    //test.setPreferredSize(new Dimension(200, 200));
    //frame.add(test);
    frame.add( new TestPanel() );  

此外,TestPanel 类应覆盖 getPreferredSize() 方法以返回面板的 Dimension。

阅读 Custom Painting 上的 Swing 教程中的部分,以获取带有 MouseListener 的工作示例。

【讨论】:

  • 我检查了你的答案,至少在最新版本的 java 中,它给出了编译器错误......
  • 你是对的,它简化了它,但是 repaint() 在 MouseClicked() 中不起作用的基本问题仍然相同。似乎无论我尝试什么,我都无法让 repaint() 在该函数中实际工作。
  • @MoldYeller,是的,它有效!!!阅读教程并下载工作示例并自行测试。然后从示例中的工作代码开始并进行修改。在对您的问题的第一条评论中,您还被告知要摆脱 Thread.sleep()。由于您尚未更新代码,因此我不知道您是否正确实施了我提出的建议。
【解决方案2】:

AWT 线程负责调用 MouseListener 和重绘。 在 repaint();方法,AWT线程被告知调用paint(); 只需使用不同的线程调用它。一般来说,用 AWT 线程做任何密集的事情是个坏主意。它已经做了很多事情,花费太多时间会弄乱你的 GUI。

根据您的需要,这可能有效:

new Thread(()->{repaint();}).start();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2019-10-14
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多