我有一个Frame
全是一种颜色,但角落里有一些文字。我设置颜色,实际从显示器读取颜色,然后根据这些测量值进行一些计算。
问题是,调用repaint()
会导致在我进行测量后Frame
绘制。我假设这是由于委托给 EDT,但由于在实际绘画工作之前/期间发生的测量,我得到了不正确的结果。repaint()
我最初的想法是让一个侦听器完成绘制,但我重新绘制以更新文本的频率比我为颜色所做的要频繁得多,而且我不想听这些事件。在进行测量之前,我如何才能等待实际的绘画任务完成?
惊人的你能找到...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
PaintEvent pe = (PaintEvent) event;
String type = "";
if (pe.getID() == PaintEvent.PAINT) {
type = "PAINT";
} else if (pe.getID() == PaintEvent.PAINT_FIRST) {
type = "PAINT_FIRST";
} else if (pe.getID() == PaintEvent.PAINT_LAST) {
type = "PAINT_LAST";
} else if (pe.getID() == PaintEvent.UPDATE) {
type = "UPDATE";
}
System.out.println(type + "; pe.UpdateRec = " + pe.getUpdateRect() + "; pe.component = " + pe.getComponent());
}
}, AWTEvent.PAINT_EVENT_MASK);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
现在,因为重绘请求可以快速思考,所以我很想在最后一个请求完成后不久触发一个小的“延迟”......
private Timer updateTimer;
// ...
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
updateTimer = new Timer(250, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Update compulations here...
}
});
updateTimer.setRepeats(false);
updateTimer.setCoalesce(true);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
updateTimer.restart();
}
}, AWTEvent.PAINT_EVENT_MASK);
}
}
这个想法是在最后一次重绘请求和开始编译之间至少允许 250 毫秒。你可能想玩弄一下这些值,看看什么适合你......
更新
你也可以试试JComponent.paintImmediately
立即绘制此组件中的指定区域及其与该区域重叠的所有后代。
很少需要调用此方法。在大多数情况下,调用 repaint 会更有效,这会延迟实际的绘制,并且可以将多余的请求合并到单个绘制调用中。如果在调度当前事件时需要更新显示,则此方法很有用。
我知道这是一个旧线程,但如果有人正在寻找答案,SwingUtilities有一个名为invokeAndWait(Runnable)的方法,它在 AWT 调度线程上与当前线程同步运行任务。请注意,如果您需要在事件调度线程内完成,则无法完成此操作。