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

时间:2015-04-23 19:08:56

标签: java swing awt paintcomponent repaint

在搜索了大量有关类似问题的答案之后,我仍然找不到符合我需求的解决方案。

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

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

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

的问题是,当我叫循环内的MapPanel重绘()方法,它等待结束整个循环的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 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

您是否尝试使用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();
            }
        });