GraphicalEnvironment does not update screen devices after switching off second screen

浪尽此生 提交于 2019-12-02 12:21:51

问题


I have two monitors
I write very small Swing Java code to collect info of all screen devices combine changing display mode with one or two display screen by setting Display in Control Panel. And code like below:

import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;


public class Main {

    public static void main(String[] args) {
        final JFrame frame = new JFrame("Demo get info screen devices");
        JButton button = new JButton("Print info screen devices");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                printInfoAllScreenDevices();
            }
        });
        frame.add(button);
        frame.setSize(500, 300);
        frame.setVisible(true);
    }
    private static void printInfoAllScreenDevices() {
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[] graphicsDevices = ge.getScreenDevices();
        System.out.println("Number of screen devices:" + graphicsDevices.length);
    }
} 

First I start program with two screens and then I click to button ("Print info screen devices"). In output shows

Number of screen devices:2

Correct!
Next I changed to one display mode. Finally, click button again and result still 2. Actually only 1 screen device.
I check that GraphicsEnvironment.getLocalGraphicsEnvironment() create a instance like singleton. It means can not update? One more thing, I don't want close programe and open again.
How can I get right information of screen devices like this case?
And I also want Java will decide which class (extend GraphicsEnvironment) provide info of screen devices, depend on operation system.
Thanks for your advance!


回答1:


It may be tricky. But from a quick look at the source code, you might try some reflection.

Disclaimer: Many things can go wrong when using reflection. You should be aware of the fact that you are relying on unspecified behavior here. If the underlying implementation changes, then the following example program might no longer work...

...although I consider this as "unlikely", at least

The following is an example showing how this might work:

import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class GraphicsEnvironmentTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("Demo get info screen devices");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton button = new JButton("Print info screen devices");
        button.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent e)
            {
                printInfoAllScreenDevices();
            }
        });
        frame.add(button);
        frame.setSize(500, 300);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static void printInfoAllScreenDevices() 
    {
        GraphicsDevice graphicsDevices[] = getGraphicsDevices();
        System.out.println("Found "+graphicsDevices.length+" devices:");
        for (int i=0; i<graphicsDevices.length; i++)
        {
            System.out.println(graphicsDevices[i]);
        }
    }

    /**
     * Queries the local graphics environment for the available graphics
     * devices. This uses reflection internally. If anything goes wrong
     * with the reflective call, a RuntimeException will be thrown.
     * 
     * @return The available graphics devices.
     * @throws RuntimeException If the reflective calls fail
     */
    private static GraphicsDevice[] getGraphicsDevices() 
    {
        GraphicsEnvironment graphicsEnvironment = 
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        Class<?> c = graphicsEnvironment.getClass();
        Method getNumScreensMethod = null;
        boolean getNumScreensMethodWasAccessible = false; 
        Method makeScreenDeviceMethod = null;
        boolean makeScreenDeviceMethodWasAccessible = false;
        try
        {
            getNumScreensMethod = 
                c.getDeclaredMethod("getNumScreens");
            getNumScreensMethodWasAccessible =
                getNumScreensMethod.isAccessible();
            getNumScreensMethod.setAccessible(true);

            makeScreenDeviceMethod = 
                c.getDeclaredMethod("makeScreenDevice", int.class);
            makeScreenDeviceMethodWasAccessible =
                makeScreenDeviceMethod.isAccessible();
            makeScreenDeviceMethod.setAccessible(true);

            int numScreens = 
                (Integer) getNumScreensMethod.invoke(graphicsEnvironment);
            GraphicsDevice graphicsDevices[] = new GraphicsDevice[numScreens];
            for (int i = 0; i < numScreens; i++)
            {
                Object object = 
                    makeScreenDeviceMethod.invoke(graphicsEnvironment, i);
                graphicsDevices[i] = (GraphicsDevice) object;
            }
            return graphicsDevices;
        }
        catch (NoSuchMethodException e)
        {
            throw new RuntimeException(e);
        }
        catch (SecurityException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (InvocationTargetException e)
        {
            throw new RuntimeException(e);
        }
        finally
        {
            if (getNumScreensMethod != null)
            {
                getNumScreensMethod.setAccessible(
                    getNumScreensMethodWasAccessible);
            }
            if (makeScreenDeviceMethod != null)
            {
                makeScreenDeviceMethod.setAccessible(
                    makeScreenDeviceMethodWasAccessible);
            }
        }
    }

}


来源:https://stackoverflow.com/questions/26912360/graphicalenvironment-does-not-update-screen-devices-after-switching-off-second-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!