如果监视器关闭,AWT/Swing 是否会取消绘画操作?

发布于 2024-11-10 10:06:52 字数 3146 浏览 2 评论 0原文

我遇到了 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();
            }
        });
    }
}

在显示器关闭之前,我看到:

显示器关闭前 DialogTest 对话框的屏幕截图

显示器关闭后,背景中的标签背景颜色变为黄色。然后我移动鼠标以重新打开显示器。该对话框在视觉上没有变化。只有在我强制重新绘制(例如,通过 ALT-TABbing)后,我才会看到黄色:

Screenshot of the 对话框DialogTest,其中主标签具有黄色背景

编辑 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:

Blank message dialog

But it paints correctly after the next repaint:

Correctly painted message dialog

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:

Screenshot of the dialog of DialogTest before the monitor shuts off

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:

Screenshot of the dialog of DialogTest where the main label has a yellow background

EDIT 3: Reported to Oracle as Bug ID 7049597.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柏林苍穹下 2024-11-17 10:06:52

然后我启动了程序并停止了
移动鼠标/打字。一后
分钟,屏幕关闭。我
又等了20秒才移动
老鼠。显示器重新打开并
我看到一个空白消息对话框。

使用您的示例,我在我的(非 Windows)平台上没有看到这一点。您可以尝试下面的示例,该示例应在唤醒时的 WINDOW_ACTIVATED 和睡眠时的 WINDOW_DEACTIVATED 之间交替。如果是这样,您可以在 windowActivated() 中扩展 JDialogrepaint()

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;

/** @see http://stackoverflow.com/questions/6163606 */
public class DialogEventTest extends JDialog {

    public DialogEventTest() {
        this.setLayout(new GridLayout(0, 1));
        this.add(new JLabel("Dialog event test.", JLabel.CENTER));
        this.add(new JButton(new AbstractAction("Close") {

            @Override
            public void actionPerformed(ActionEvent e) {
                DialogEventTest.this.setVisible(false);
                DialogEventTest.this.dispatchEvent(new WindowEvent(
                    DialogEventTest.this, WindowEvent.WINDOW_CLOSING));
            }
        }));
    }

    private static class WindowHandler extends WindowAdapter {

        @Override
        public void windowActivated(WindowEvent e) {
            System.out.println(e);
        }

        @Override
        public void windowDeactivated(WindowEvent e) {
            System.out.println(e);
        }
    }

    private void display() {
        this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.addWindowListener(new WindowHandler());
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new DialogEventTest().display();
            }
        });
    }
}

I then started the program and stopped
moving the mouse/typing. After one
minute, the screen turned off. I
waited another 20 seconds to move the
mouse. The monitor turned back on and
I saw a blank message dialog.

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 and WINDOW_DEACTIVATED on sleep. If so, you could extend JDialog and repaint() in windowActivated().

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;

/** @see http://stackoverflow.com/questions/6163606 */
public class DialogEventTest extends JDialog {

    public DialogEventTest() {
        this.setLayout(new GridLayout(0, 1));
        this.add(new JLabel("Dialog event test.", JLabel.CENTER));
        this.add(new JButton(new AbstractAction("Close") {

            @Override
            public void actionPerformed(ActionEvent e) {
                DialogEventTest.this.setVisible(false);
                DialogEventTest.this.dispatchEvent(new WindowEvent(
                    DialogEventTest.this, WindowEvent.WINDOW_CLOSING));
            }
        }));
    }

    private static class WindowHandler extends WindowAdapter {

        @Override
        public void windowActivated(WindowEvent e) {
            System.out.println(e);
        }

        @Override
        public void windowDeactivated(WindowEvent e) {
            System.out.println(e);
        }
    }

    private void display() {
        this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        this.addWindowListener(new WindowHandler());
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new DialogEventTest().display();
            }
        });
    }
}
灵芸 2024-11-17 10:06:52

这个问题可能更多地与屏幕打开时的重新绘制方式有关,而不是与屏幕关闭时发生的情况有关。您可以通过运行屏幕录像机进行检查。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文