Search code examples
javaswingscreendragmultiple-monitors

Application turns black when dragged from a 4k monitor to a FullHD monitor


My notebook has a 4k display. My external monitor is 1920. When I drag my Java Swing app window from the 4k display onto the external monitor it gets completely black except for the window frame. It doesn't matter whether I maximize it on the external monitor or not.

Here is the HelloWorldSwing example I got from Oracle.com. It shows the exact same behaviour.

import javax.swing.*;        

public class HelloWorldSwing {
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("HelloWorldSwing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Add the ubiquitous "Hello World" label.
        JLabel label = new JLabel("Hello World");
        frame.getContentPane().add(label);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

It looks like a bug in Swing. Anyway, I have to find a solution/work-around. Any ideas?

I'm running jdk/jre 1.8.0 121.


Solution

  • I found a solution. Basically I added a component listener to my main frame and listen on move events. Whenever the frame is moved I check on which display it is located. As soon as the frame has been moved to another display I set it invisible, then set new bounds located on the "new" display, set the extended state to maximized and finally make the frame visible again.

    For the last minutes I wildly dragged windows from one display to another all while jumping for joy. If you also want that much fun in your life, here is the code:

    mainFrame.addComponentListener(new ComponentListener()
        {
            @Override
            public void componentMoved(ComponentEvent evt)
            {
                GraphicsConfiguration conf = mainFrame.getGraphicsConfiguration();
                GraphicsDevice curDisplay = conf.getDevice();
                GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
    
                GraphicsDevice[] allDisplays = env.getScreenDevices();
                for (int i = 0; i < allDisplays.length; i++)
                {
                    if (allDisplays[i].equals(curDisplay))
                    {
                        //the window has been dragged to another display
                        if (i != _currentDisplayIndex)
                        {
                            final Rectangle sb = conf.getBounds();
    
                            mainFrame.setVisible(false);
                            //it is important to set the bounds somewhere on the new display before setting the extended state to maximized
                            mainFrame.setBounds(sb.x, sb.y, 1000, 800);
                            mainFrame.setExtendedState(Frame.MAXIMIZED_BOTH);
                            mainFrame.setVisible(true);
    
                            _currentDisplayIndex = i;
                        }
                    }
                }
    
            }
    
            @Override
            public void componentShown(ComponentEvent evt)
            {
            }
    
            @Override
            public void componentResized(ComponentEvent evt)
            {
            }
    
            @Override
            public void componentHidden(ComponentEvent evt)
            {
            }
        });
    

    Yippie!

    Side note: I tried to take a screenshot of the black window earlier. However, the screenshot isn't black, but just normally shows all swing components. That makes me believe, that it is not only a swing issue, but also some sort of a windows/display driver issue. Pressing "printscreen" doesn't trigger anything in java (I guess), but only refreshes the display.