循环迭代等待 repaint() 方法完成

Make a loop iteration wait for the repaint() method to complete

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

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

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

我想做的是通过在当前事件点画一条线来显示算法的当前 "position"。 当算法找到新的交叉点时,我也想展示它们。 我确实在 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());
}

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

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

有关此的更多信息,请阅读 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
}

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

     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();
            }
        });