繁体   English   中英

绘画方法在回旋中不起作用

[英]paint method not working inside while loop in swing

我有两节课。 我尝试移动圈子。 当我在Game.java中键入break语句时,它会为我画一个不动的圆圈。 没关系。 然而,当我想移动圆(删除break它显示什么,我不知道如何调试,我发现了程序不会paint方法里面,当我使用,而不用。 break;语句。
谁能告诉我如何调试这样的问题。 提前致谢

App.java

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class App extends JFrame {

    App() {

        JFrame jf = new JFrame(); 
        JPanel jp = new JPanel();
        jf.add(jp);
        jp.setLayout(new BorderLayout()); 
        jf.setSize(500, 500);
        jf.setTitle("Chain Reactor Game");
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);

        Game game = new Game();
        jp.add(game, BorderLayout.CENTER);

        MenuBar menuBar = new MenuBar();
        jf.setJMenuBar(menuBar.createMenuBar());
    }

    public static void main(String[] args) {

        /*
         * oracle recommendation to run swing applications in special thread    
         * they suggest it during thread implementation
         */

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new App();          
            }
        });
    }
}

Game.java

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;

import javax.swing.JPanel;

public class Game extends JPanel {

    private static final long serialVersionUID = 1L;
    int x = 0;
    int y = 0;

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        System.out.println("im goint to filloval now");
        g2d.fillOval(x, y, 30, 30);
    }
    public Game() {

        while(true) {

            moveBall();
            repaint();
            try {
                System.out.println("inside thread");
                Thread.sleep(2000);
            } 
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        break;     // if i delete this line it not drawing. Why is that ?

        }
    }
    private void moveBall() {
        x = x + 1;
        y = y + 1;
    }
}

您需要从Swing事件线程中获得while循环,因为它绑住了线程,从而阻止了Swing执行其绘图功能或用户交互。 您基本上是在踩Swing事件线程,这违反了Swing并发规则。 使用Swing Timer代替为此类事情构建的简单动画。

让我们分解代码...

程序从这里开始...

public static void main(String[] args) {

    /*
     * oracle recommendation to run swing applications in special thread    
     * they suggest it during thread implementation
     */

    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            new App();          
        }
    });
}

很好,它可以在“事件调度线程”的上下文中启动GUI,如初始线程中所述 ...

接下来,构建App ...

App() {

    JFrame jf = new JFrame(); 
    JPanel jp = new JPanel();
    jf.add(jp);
    jp.setLayout(new BorderLayout()); 
    jf.setSize(500, 500);
    jf.setTitle("Chain Reactor Game");
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setVisible(true);

    Game game = new Game();
    jp.add(game, BorderLayout.CENTER);

    MenuBar menuBar = new MenuBar();
    jf.setJMenuBar(menuBar.createMenuBar());
}

好的,这个“似乎”可以,但是如果我们仔细看一下Game

public Game() {

    while(true) {

        moveBall();
        repaint();
        try {
            System.out.println("inside thread");
            Thread.sleep(2000);
        } 
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    break;     // if i delete this line it not drawing. Why is that ?

    }
}

嗯,这是一个问题... while是在事件调度线程的上下文中执行的,但EDT用于处理事件并帮助安排重绘,任何阻止EDT的事情都将阻止它进行绘画等用户界面

首先看一下Swing中的并发性

现在,这里有一个问题22,Swing是一个单线程框架,并且不是线程安全的,这意味着您可以执行长时间运行/阻止过程,但是您也无法从事件调度线程之外更新UI。

一种简单的解决方案是用javax.swing.Timer替换while-loop

public Game() {
    javax.swing.Timer timer = new javax.swing.Timer(2000, new javax.swing.ActionListener() {
        public void actionPerformed(javax.swing.ActionEvent evt) {
            moveBall();
            repaint();
        }
    });
    timer.start();
}

看看如何使用Swing计时器了解更多详细信息...

附带说明一下,通常建议使用paintComponentpaint上执行自定义paint 绘画是一系列复杂的方法调用,您可以做的任何防止将其拧紧的方法都可以使头发固定在位。

有关更多详细信息,请查看AWT中的绘画以及“摇摆执行自定义绘画”

当您离开break; 在你有一个无限循环。 它永远不会结束,这意味着Game game = new Game(); 将永远不会返回,这意味着将Game添加到JPanel的下一行将永远不会运行,这就是屏幕上什么都没画的原因。 为了使它起作用,您需要创建GUI,然后执行绘图。

使它起作用的一种方法是创建一个新的Thread来执行连续绘制:

public Game() {
    (new Thread() {
        public void run() {
            draw();
        }
     ).start();
 }

private void draw() {
    while(true) {
        moveBall();
        repaint();
        try {
            System.out.println("inside thread");
            Thread.sleep(2000);
        } 
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

或者,由于要在Swing线程上设置GUI,因此可以在主线程上运行图形。

暂无
暂无

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

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