简体   繁体   English

使用 repaint() 在添加到 JFrame 的 JPanel 上绘图

[英]Using repaint() to draw on JPanel which is added to JFrame

Attempting to draw my rectangle across the screen horizontally in realtime.试图在屏幕上实时水平绘制我的矩形。 When I run this I get nothing but the JFrame.当我运行它时,我只得到 JFrame。 I'm not sure what I am missing aside from maybe some type of threading freeze to redraw the shape maybe?我不确定除了某种类型的线程冻结以重绘形状之外我还缺少什么?

public class ScreenTest extends JFrame {
    
    int rectY = 50;
    
    public ScreenTest()
    {
        setSize(300,200);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        
    }
    
    private class DrawPanel extends JPanel {
        
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.GREEN);
            g.fillRect(80, rectY, 50, 50);
       }
    }
    
    public void Draw()
    {
        DrawPanel test = new DrawPanel();
        add(test);
        
        while (rectY < 200)
        {
            rectY = rectY + 10;
            test.repaint();
        }

    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ScreenTest myWindow = new ScreenTest(); 
        myWindow.Draw();
    }
    
}

Swing is single threaded and not thread safe. Swing 是单线程的,不是线程安全的。

What this means is, you should not perform any kind of long running or blocking operations within the "Event Dispatching Thread", as this will stop the UI from been painted or responding to new events.这意味着,您不应在“事件调度线程”中执行任何类型的长时间运行或阻塞操作,因为这将阻止 UI 被绘制或响应新事件。

It also means you should not update the UI, or any state the UI relies on, from outside the context of the Event Dispatching Thread.这也意味着您不应从事件调度线程的上下文之外更新 UI 或 UI 所依赖的任何 state。

Your code "is" working, but because the while-loop can run so fast, it's completing before the window is realised on the screen (visible and updatable).您的代码“正在”工作,但是因为while-loop可以运行得如此之快,所以它在 window 在屏幕上实现之前完成(可见且可更新)。 Swing is also optimised, so all the repaint calls are likely been consolidated into a single repaint pass. Swing 也进行了优化,因此所有repaint调用都可能合并到一个重绘通道中。

A better solution might to start with Swing `Timer, which acts as a pseudo repeating loop, but which is called on within the context of the Event Dispatching Thread.更好的解决方案可能从 Swing `Timer 开始,它充当伪重复循环,但在事件调度线程的上下文中调用。

Start by taking a look at Concurrency in Swing andHow to Use Swing Timers for more details.首先查看Swing 中的并发以及如何使用 Swing 计时器以了解更多详细信息。

Runnable Example可运行示例

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class ScreenTest extends JFrame {

    public ScreenTest() {
        setSize(300, 200);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);

    }

    private class DrawPanel extends JPanel {

        int rectY = 50;
        private Timer timer;

        // This is just convince 
        @Override
        public void addNotify() {
            super.addNotify();
            timer = new Timer(25, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    rectY += 1;
                    repaint();
                }
            });
            // Otherwise it disappears to fast
            timer.setInitialDelay(1000);
            timer.start();
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            timer.stop();
            timer = null;
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.GREEN);
            g.fillRect(80, rectY, 50, 50);
        }
    }

    public void Draw() {
        DrawPanel test = new DrawPanel();
        add(test);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                ScreenTest myWindow = new ScreenTest();
                myWindow.Draw();
            }
        });
    }

}

it is working but is so fast that you can't see it, you need to make the loop which changes the Y coordinate slower with a delay.它正在工作,但速度太快以至于你看不到它,你需要使改变 Y 坐标的循环变慢并延迟。 to solve it i used Thread.sleep() in the while loop:为了解决这个问题,我在 while 循环中使用了 Thread.sleep():

package paquete;

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

public class ScreenTest extends JFrame {

    int rectY = 50;

    public ScreenTest()
    {
        setSize(300,200);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);

    }

    private class DrawPanel extends JPanel {

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.GREEN);
            g.fillRect(80, rectY, 50, 50);
        }
    }

    public void Draw() throws InterruptedException {
        DrawPanel test = new DrawPanel();
        add(test);

        while (rectY < 200)
        {
            rectY = rectY + 10;
            Thread.sleep(100);
            test.repaint();
        }

    }

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        ScreenTest myWindow = new ScreenTest();
        myWindow.Draw();
    }

}

i hope this helps you, you can change the duration changing the number inside the argument of Thread.sleep()我希望这对您有所帮助,您可以更改持续时间,更改 Thread.sleep() 参数中的数字

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

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