在搜索了大量有关类似问题的答案之后,我仍然找不到符合我需求的解决方案。
基本上,我有一个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());
}
答案 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();
}
});