【问题标题】:Why is my while loop not working in paintComponent?为什么我的 while 循环在paintComponent 中不起作用?
【发布时间】:2015-08-23 23:29:43
【问题描述】:

当我运行此代码时,我只看到一个空白(白色)面板,我想知道原因。

这是我的代码:

Graph.java

public class Graph extends JPanel {
    private static final long serialVersionUID = -397959590385297067L;
    int screen=-1;
    int x=10;
    int y=10;
    int dx=1;
    int dy=1;       
    boolean shouldrun=true;
    imageStream imget=new imageStream();

        protected void Loader(Graphics g){

            g.setColor(Color.black);
            g.fillRect(0,0,x,y);
            x=x+1;
            y=y+2;

        }


        @Override
        protected void paintComponent(Graphics g){
            super.paintComponent(g);
                while(shouldrun){
                    Loader(g);   
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }    
                }   
        }
}

【问题讨论】:

标签: java swing jpanel paintcomponent


【解决方案1】:

永远不要在Event Dispatch Thread 上拨打Thread.sleep()!!!

这会导致实际重绘屏幕并使控件响应停止执行任何事情的线程。

For animations, use a Timer。不必担心自己编写 while 循环,只需告诉 Timer 每隔一段时间触发一次,并在该计时器内更改 xy 的值。比如:

// this is an **inner** class of Graph
public class TimerActionListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        x += dx;
        y += dy;
    }
}

// snip
private final Timer yourTimer;

public Graph() {
    yourTimer = new Timer(2000, new TimerActionListener());
    timer.start();
}
@Override
protected void paintComponent(Graphics g){
    super.paintComponent(g);
    g.setColor(Color.black);
    g.fillRect(0,0,x,y);
}

【讨论】:

  • 是的,他说的是! 1+
  • 它不是动画,想法是在游戏中设置关卡、加载屏幕和菜单。我想要一个循环来根据整数屏幕重新运行图形。
  • @DanjahSoftProgrammer 事件调度线程会自动为您完成循环的工作。 您不必担心让它反复重绘,因为 Swing 为您做的就像魔术​​一样! 此代码与您提供的代码非常相似;您在 Loader 方法中调用了 x=x+1,除了使用 Timer 而不是 while 循环之外,这也是同样的事情。
  • @DanjahSoftProgrammer 如果您不打算制作动画,那么您实际上不需要循环或计时器。您可以简单地触发带有条件或一些侦听器的下一级屏幕。
【解决方案2】:

你永远不会在循环中改变 shouldrun 的状态——所以它永远不会结束。

另外,永远不要在绘画方法中调用Thread.sleep(...)。此方法用于绘画,永远不能休眠,否则 GUI 会休眠,会被冻结。

【讨论】:

  • 哦,我明白了。是的,它永远不会结束。但是我应该如何让它迭代?在主代码中重新绘制?...忽略这个
【解决方案3】:

首先,您的paintComponent 方法应该只处理所有的绘画而不是其他任何事情(如果可能的话)。你不应该在paintComponent中实现你的程序循环。

空白屏幕可能由多种原因引起。您可以通过注释掉代码的某些部分并运行它来轻松地手动调试它。看看是不是还是空白。

至少从我在这里看到的情况来看,您的paintComponent 会给您带来问题。

如果你想要一个动画,你可以:

  1. 使用摆动计时器

  2. 在新线程(不是事件调度线程)中创建循环。您的循环将如下所示:

如下:

while(running){
    update();
    render();
    try(
        Thread.sleep(1000/fps);
    )catch(InterruptedException ie){
        ie.printStackTrace();
    }
}

注意:要为动画制作适当的循环,您需要的还不止这些。

【讨论】:

  • “如果可能的话”它真的应该只是绘画,否则代码存在重大缺陷。
  • @durron597 看看这个大学给的样本? ntu.edu.sg/home/ehchua/programming/java/…
  • @durron597 最简单的方法是使用计时器,但如果程序/游戏变得复杂,最好创建一个线程并在该线程中运行游戏循环,而不是在 EDT 中执行所有操作不是吗?所以从这个角度来看,Java 动画必须只使用摇摆计时器来完成并不是那么绝对。
  • @user3437460 我同意老练的游戏开发者不应该使用Timer,而应该编写自己的可变帧率游戏循环,但这就是超出此问题范围和 OP 当前技能水平的原因。
  • @durron597 我没有直接告诉他哪个更好,而是选择告诉他(和未来的用户)可能的选择。他们会选择对他们更好的东西。我只是不想给他一个错误的印象,认为挥杆计时器是唯一可能的选择。 :)
猜你喜欢
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 2022-01-26
  • 2022-12-12
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
  • 2020-01-08
相关资源
最近更新 更多