如果监视器关闭,AWT/Swing 是否会取消绘画操作?
我遇到了 Swing 问题,该问题仅在计算机显示器关闭时出现,但我的 Swing 应用程序继续在后台运行。似乎只要显示器关闭,Swing/AWT 就会取消所有绘制操作,从而导致 GUI 中出现许多显示问题,一旦显示器重新打开,这些问题就会显现出来。
例如,当我使用自定义 JNI 函数关闭监视器并随后打开一个简单的消息对话框时,当监视器重新打开时,该消息对话框为空白:
但在下次重新绘制后它会正确绘制:
是这样吗Swing 的预期行为?有没有办法指示 Swing 在显示器关闭的情况下继续绘制到屏幕上?
编辑:这是一个 SSCCE:
package test;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class App {
public static void main(String[] args) throws Throwable {
System.out.println("***** Please turn off the monitor in the next 70 seconds *****");
Thread.sleep(1000L * 70);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(null, "Test");
}
});
}
}
我正在使用 64 位 Windows 7 Home Premium SP1 和 64 位 Java 1.6.0_24。
编辑2:这是我体验“取消绘画操作”效果的另一个程序:
package test;
import static com.mycompany.Util.turnOffMonitors;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class DialogTest extends JDialog {
private final JLabel label;
public DialogTest() {
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
label = new JLabel("Test", JLabel.CENTER);
label.setOpaque(true);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(BorderLayout.CENTER, label);
this.setPreferredSize(new Dimension(200, 110));
pack();
setLocationRelativeTo(null);
setVisible(true);
Thread t = new Thread() {
@Override
public void run() {
turnOffMonitors();
try {
Thread.sleep(3000L);
} catch (InterruptedException ex) { }
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
label.setBackground(Color.YELLOW);
}
});
}
};
t.start();
}
public static void main(String[] args) throws Throwable {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DialogTest();
}
});
}
}
在显示器关闭之前,我看到:
显示器关闭后,背景中的标签背景颜色变为黄色。然后我移动鼠标以重新打开显示器。该对话框在视觉上没有变化。只有在我强制重新绘制(例如,通过 ALT-TABbing)后,我才会看到黄色:
编辑 3: 向 Oracle 报告为 错误 ID 7049597。
I am experiencing a problem with Swing that only occurs when the computer monitor is powered off, but my Swing application continues to run in the background. It seems that whenever the monitor is off, Swing/AWT cancels all painting operations, leading to a number of display issues in the GUI that are visible as soon as the monitor turns back on.
For example, when I turn off the monitor using a custom JNI function and subsequently open a simple message dialog, the message dialog is blank when the monitor turns back on:
But it paints correctly after the next repaint:
Is this the expected behavior of Swing? Is there a way to instruct Swing to continue drawing to the screen even if the monitor is powered off?
EDIT: Here is an SSCCE:
package test;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class App {
public static void main(String[] args) throws Throwable {
System.out.println("***** Please turn off the monitor in the next 70 seconds *****");
Thread.sleep(1000L * 70);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showMessageDialog(null, "Test");
}
});
}
}
I am using 64-bit Windows 7 Home Premium SP1 and 64-bit Java 1.6.0_24.
EDIT 2: Here is another program with which I experience the effect of "canceled painting operations":
package test;
import static com.mycompany.Util.turnOffMonitors;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class DialogTest extends JDialog {
private final JLabel label;
public DialogTest() {
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
label = new JLabel("Test", JLabel.CENTER);
label.setOpaque(true);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(BorderLayout.CENTER, label);
this.setPreferredSize(new Dimension(200, 110));
pack();
setLocationRelativeTo(null);
setVisible(true);
Thread t = new Thread() {
@Override
public void run() {
turnOffMonitors();
try {
Thread.sleep(3000L);
} catch (InterruptedException ex) { }
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
label.setBackground(Color.YELLOW);
}
});
}
};
t.start();
}
public static void main(String[] args) throws Throwable {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DialogTest();
}
});
}
}
Before the monitor shuts off, I see:
With the monitor off, the label background color is changed to yellow in the background. I then move the mouse to turn the monitor back on. The dialog is visually unchanged. It is only after I force a repaint (by ALT-TABbing, for example) do I see the yellow:
EDIT 3: Reported to Oracle as Bug ID 7049597.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用您的示例,我在我的(非 Windows)平台上没有看到这一点。您可以尝试下面的示例,该示例应在唤醒时的
WINDOW_ACTIVATED
和睡眠时的WINDOW_DEACTIVATED
之间交替。如果是这样,您可以在windowActivated()
中扩展JDialog
和repaint()
。Using your example, I don't see this on my (non-Windows) platform. You might try the example below, which should alternate between
WINDOW_ACTIVATED
on wake andWINDOW_DEACTIVATED
on sleep. If so, you could extendJDialog
andrepaint()
inwindowActivated()
.这个问题可能更多地与屏幕打开时的重新绘制方式有关,而不是与屏幕关闭时发生的情况有关。您可以通过运行屏幕录像机进行检查。
The problem probably has more to do with how it repaints when the screen comes on rather than what happens while it's off. You could check by running a screen recorder.