有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java进行循环迭代,等待repaint()方法完成

在寻找了很多类似问题的答案后,我仍然没有找到一个适合我需要的解决方案

基本上,我有一个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());
}

共 (2) 个答案

  1. # 1 楼答案

    你试过线程的方法吗。睡眠(毫秒)??? 例如,我习惯于在我的代码中这样做:

         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();
                }
            });
    
  2. # 2 楼答案

    问题是,您的长时间运行的代码可能会在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
    }