【问题标题】:Make a loop iteration wait for the repaint() method to complete进行循环迭代等待 repaint() 方法完成
【发布时间】:2015-07-02 03:52:08
【问题描述】:

在搜索了很多类似问题的答案后,我仍然没有找到适合我需求的解决方案。

基本上,我有一个 while 循环,我想在该循环的另一次迭代开始之前等待 repaint() 方法完成。

更详细地说,我在扩展JComponentMapPanel 类的paintComponent 方法中绘制了一些片段。 然后,当用户单击按钮时,算法开始搜索从“上部”段开始的交叉点(使用端点作为事件点)。 这个算法基本上就是我所说的while循环,它在这个while循环中调用另一种算法,在每次迭代时发送一个事件点(这些事件点是按顺序发送的,从上到下)。

我想做的是通过在当前事件点画一条线来显示算法的当前“位置”。 当算法找到新的交叉点时,我也想展示它们。 我确实绘制了 paintComponent() 方法中需要的东西。

问题是,当我在循环内调用 MapPanel 的 repaint() 方法时,它会等待整个循环结束,然后再更新 UI(我发现了很多关于它为什么这样做但不是关于如何在我的特定情况下解决此问题)。

好的,我已经完成了解释,这是实际的算法:

private void findIntersection(ArrayList<Segment> segments){
    QTree Q=new QTree();
    for (Segment s : segments){
        Q.initialise(s);
    }
    TreeT T=new TreeT();
    while (Q.getRoot()!=null){
        Point p = Q.maxEventPoint(Q.getRoot());
        Q.delete(p.getX(), p.getY());
        mapPanel.setSweeplinePosition(p.getY());
        handleEventPoint(p, T, Q);
        mapPanel.repaint()
        //should wait here for repaint() to complete
    }
        System.out.println("all intersections found, found " + mapPanel.getIntersections().size());
}

【问题讨论】:

  • 使用timerworker thread
  • 你在哪个线程运行这个方法?
  • 请查看编辑以回答。

标签: java swing awt paintcomponent repaint


【解决方案1】:

问题在于,您的长时间运行的代码可能会在 Swing 事件线程上被调用,该操作会阻止事件线程执行其操作,包括绘制 GUI。

该解决方案可能与您在搜索中找到的类似,但我们不知道为什么您不能在您的程序中使用它,即在 SwingWorker 后台线程中执行 while 循环,以发布使用 SwingWorker 的发布/处理方法对的临时结果,然后使用临时数据绘制图形。

有关更多信息,请阅读Concurrency in Swing


例如

private void findIntersection(final ArrayList<Segment> segments) {
  final SwingWorker<Void, Double> myWorker = new SwingWorker<Void, Double>() {

     @Override
     protected Void doInBackground() throws Exception {
        QTree Q = new QTree();
        for (Segment s : segments) {
           Q.initialise(s);
        }
        TreeT T = new TreeT();
        while (Q.getRoot() != null) {
           Point p = Q.maxEventPoint(Q.getRoot());
           Q.delete(p.getX(), p.getY());
           publish(p.getY()); // push data to process method

           // take care that this method below does not
           // make Swing calls
           handleEventPoint(p, T, Q);
        }
        return null;
     }

     @Override
     protected void process(List<Double> chunks) {
        for (Double yValue : chunks) {
           // this is called on the EDT (Swing event dispatch thread)
           mapPanel.setSweeplinePosition(yValue);
           mapPanel.repaint();
        }
     }
  };
  myWorker.addPropertyChangeListener(new PropertyChangeListener() {

     @Override
     public void propertyChange(PropertyChangeEvent evt) {
        // get notified when Worker is done
        if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
           // TODO: any clean up code for when worker is done goes here
           try {
              myWorker.get(); // must call to trap exceptions that occur inside worker
           } catch (InterruptedException e) {
              e.printStackTrace();
           } catch (ExecutionException e) {
              e.printStackTrace();
           }
        }
     }
  });
  myWorker.execute(); // execute worker
}

【讨论】:

  • 非常感谢,这实际上与我发现的不完全一样(类似但无法正常工作)。
【解决方案2】:

您是否尝试过使用 Thread.sleep(milliseconds) 方法??? 例如,我习惯在我的代码中做这样的事情:

     btnNewButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        pca.setIcon(new ImageIcon("icon.png"));
                        for(int i=0; i<4; i++) {
                        try{Thread.sleep(700);} catch(InterruptedException er){} 
                        x+=20;
                        p.repaint();
                    }}
                }).start();
            }
        });

【讨论】:

  • 我首先使用了一个简单的 Thread.sleep() (现在我在 doInBackground() 方法中使用它)但问题是 Thread.sleep() 阻止线程执行任何东西,并且由于在线程忙或休眠时不会执行 repaint() 执行,因此在算法结束之前没有 GUI 刷新。这就是为什么我需要像 SwingWorker 这样的东西来让算法等待 repaint() 执行。据我现在(认为我)理解,您的示例之所以有效,是因为您在新线程中调用 repaint(),而不是因为您使用的是 Thread.sleep() :p
  • 是的,你是对的。我注意到在算法结束之前没有刷新 GUI,所以我把 repaint() 放在一个线程中;)如你所见,我是一个初学者,我试图用我所拥有的知识来解决我的问题。 ..如果有更正确的解决方案,我准备好了...
猜你喜欢
  • 2018-02-08
  • 2014-10-25
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 2022-12-10
  • 2015-08-20
  • 1970-01-01
  • 2020-11-18
相关资源
最近更新 更多