摇绘法

Swing paint method

我在 JPanel 中的绘画方法有问题。 首先,我创建了一个扩展 JFrame 的 class。 然后我创建一个扩展面板的 class 并从这个 class 创建一个对象并添加到框架。

我想通过按键盘上的右键 (VK_RIGHT) 在 2 秒内在面板上绘制小矩形。 (这意味着清除矩形并在新位置绘制。我的问题是:我不能执行定时绘制方法和重绘方法。我希望每两秒矩形继续进行 5 次(逐步)但矩形只进行一次.

我的代码是:

Panel

import java.awt.Color;

import java.awt.Graphics;

import javax.swing.JPanel;

public class Panel extends JPanel{

    private int x;
    private int y;
    public Panel()
    {
        x=100;
        y=100;
        this.setBackground(Color.RED);
    }

    //--------------------------------

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

        g.setColor(Color.BLACK);

        g.fillRect(x, y, 20, 20);
    }

    //--------------------------------

    @Override
    public void repaint()
    {
        super.repaint();

        x+=20;
    }

    //--------------------------------
}

Frame

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import javax.swing.JFrame;

public class Frame extends JFrame {

    private Panel p;

    public Frame()
    {
        super("Test");
        this.setBounds(1200, 300, 400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        p=new Panel();
        this.add(p);


        this.addKeyListener(new KeyLis());
    }

    //----------------------------------

    public static void main(String[] args) {

        Frame a=new Frame();

        a.setVisible(true);
    }

    //-----------------------------------

    private class KeyLis implements KeyListener
    {

        @Override
        public void keyPressed(KeyEvent arg0) {

            if(arg0.getKeyCode() == KeyEvent.VK_RIGHT)
            {
                for(int i=0;i<5;i++)
                {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    p.repaint();
                }
            }
        }
        //---------------
        @Override
        public void keyReleased(KeyEvent arg0) {
            // TODO Auto-generated method stub

        }
        //---------------
        @Override
        public void keyTyped(KeyEvent arg0) {
            // TODO Auto-generated method stub

        }
        //---------------
    }
    //-----------------------------------------
}

您的问题主要是 KeyListener 中的 for-loop,它阻塞了事件调度线程,阻止了更新。

简单的解决方案是使用 Swing Timer,它在后台等待,在 EDT 上触发滴答,确保安全地更新 ui 并定期安排更新。

有关详细信息,请参阅 Concurrency in Swing and How to use Swing Timers

如果出于某种原因,您发现 Swing Timer 难以理解,您也可以尝试使用 SwingWorker,这将允许您使用后台线程循环,但是它提供了在 EDT 上下文中更新状态的方法。

有关详细信息,请参阅 Worker Threads and SwingWorker

建议

作为一般规则覆盖 paintComponent 而不是 paint。有关详细信息,请参阅 Performing Custom Painting

不要使用 repaint 来更新你的状态,你可能不是唯一调用它的人,而是创建一个可以在视图和你的关键控制器之间共享的模型。

请参阅 Model-View-Controller and Observer Pattern 了解一些想法

我也不鼓励使用 KeyListener 并改用键绑定 API

有关详细信息,请参阅 How to Use Key Bindings

如果您准备使用线程:

将您的 KeyPressed 事件更改为:

        @Override
        public void keyPressed(KeyEvent arg0) {

            if (arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
                PaintThread th = new PaintThread(p);
                th.start();
            }
        }

创建了一个话题:

import java.util.logging.Level;
import java.util.logging.Logger;

public class PaintThread extends Thread{

    Panel panel;

    PaintThread(Panel panel){
        this.panel = panel;
    }

    @Override
    public void run() {
        for(int i = 0; i<5; i++){
            try {
                this.sleep(1000);
                panel.repaint();
            } catch (InterruptedException ex) {
                Logger.getLogger(PaintThread.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

}