循环迭代等待 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();
}
});
在很多关于类似问题的帖子中搜索了答案后,我仍然没有找到适合我需要的解决方案。
基本上,我有一个 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();
}
});