简体   繁体   English

为什么当同一类的对象的方法调用repaint()时不起作用?

[英]Why doesn't repaint() work when called by a method of an object of the same class?

In a program I'm building for my class I have the same class extending a Swing JPanel and implementing MouseListener, for which I use two instantiations - one to function as a JPanel, and the other as a mouse listener for that JPanel. 在为我的班级构建的程序中,我有一个相同的类扩展了Swing JPanel并实现了MouseListener,为此我使用了两个实例化-一个实例化为JPanel,另一个实例化为该JPanel的鼠标侦听器。

But when I click in the window, repaint() the MouseClicked method in the mouse listener fails to call the first object's paintComponent() method. 但是,当我单击窗口时,鼠标侦听器中的MouseClicked方法repaint()无法调用第一个对象的paintComponent()方法。 For example: 例如:

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

If you watch what happens on a click, the screen stays white for the 3 seconds after the click is registered, until the loop starts up again, ie, the repaint() call in the mouse listener didn't work. 如果您观察单击后发生的情况,则在单击记录后3秒钟内,屏幕将保持白色,直到循环再次启动,即鼠标侦听器中的repaint()调用无效。 Why does this happen? 为什么会这样?

I'm guessing it would work if I made different classes for the objects, but I'm mostly curious as to why it doesn't work this way. 我猜想如果为对象创建不同的类会起作用,但是我最好奇为什么它不能这样工作。

for which I use two instantiations - one to function as a JPanel, and the other as a mouse listener for that JPanel. 为此,我使用了两种实例化-一种用作JPanel,另一种用作该JPanel的鼠标侦听器。

There is no need to do that. 不需要这样做。 All you need is a single instance of the TestPanel class. 您只需要一个TestPanel类的实例TestPanel

In the constructor of your TestPanel class you just add: 在您的TestPanel类的构造函数中,只需添加:

addMouseListener( this);

The get rid of the static variable for the TestPanel class. 除去TestPanel类的静态变量。

Then the code in your main method should look something like: 然后,您的main方法中的代码应类似于:

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

Also, the TestPanel class should override the getPreferredSize() method to return the Dimension of your panel. 另外, TestPanel类应重写getPreferredSize()方法以返回面板的Dimension。

Read the section from the Swing tutorial on Custom Painting for a working example with a MouseListener . 阅读有关定制绘画的Swing教程中的部分,以获取使用MouseListener的工作示例。

The AWT thread is responsible for calling MouseListener and for repaint. AWT线程负责调用MouseListener并进行重新绘制。 Inside the repaint(); 在repaint()内部; method, the AWT thread is told to call the paint(); 方法,告诉AWT线程调用paint();。 Just call it using a different thread. 只需使用其他线程即可调用它。 In general, it is a bad idea to do anything intensive with the AWT thread. 通常,对AWT线程进行任何密集的工作都是一个坏主意。 It already does a lot, taking too much of its time will mess your GUI up. 它已经做了很多事情,花费太多时间会使您的GUI混乱。

Depending on your needs, this might work: 根据您的需求,这可能会起作用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM