adamsun
adamsun

Reputation:

How to detect the current display with Java?

I have 2 displays connected, so I can either launch my Java application on the primary or the secondary display.

The question is: How can I know which display contains my app window, i.e., is there a way to detect the current display with Java?

Upvotes: 18

Views: 14679

Answers (6)

Sam Ginrich
Sam Ginrich

Reputation: 21

Slightly different use case: If you want to know the primary display before you create a window somewhere and "display" technically means a java.awt.GraphicsDevice, the corresponding java.awt.GraphicsConfiguration should be

java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration()

A sorted list of GraphicsConfiguration-s is given by

public static GraphicsConfiguration[] getConfigurations()
{
    final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    final GraphicsDevice def = ge.getDefaultScreenDevice(); 

    final List<GraphicsConfiguration> cfgs = new ArrayList<GraphicsConfiguration>();
    cfgs.add(def.getDefaultConfiguration());

    for (final GraphicsDevice gd : ge.getScreenDevices())
    {
        if (gd!=def)
        {
            cfgs.add(gd.getDefaultConfiguration());             
        }
    }
    final GraphicsConfiguration[] res = cfgs.toArray(new GraphicsConfiguration[cfgs.size()]);
    return res;
}

where the default display is the first in the list.

Upvotes: 0

Alexander Zuban
Alexander Zuban

Reputation: 151

This works for me

    public static GraphicsDevice getWindowDevice(Window window) {
    Rectangle bounds = window.getBounds();
    return asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()).stream()

            // pick devices where window located
            .filter(d -> d.getDefaultConfiguration().getBounds().intersects(bounds))

            // sort by biggest intersection square
            .sorted((f, s) -> Long.compare(//
                    square(f.getDefaultConfiguration().getBounds().intersection(bounds)),
                    square(s.getDefaultConfiguration().getBounds().intersection(bounds))))

            // use one with the biggest part of the window
            .reduce((f, s) -> s) //

            // fallback to default device
            .orElse(window.getGraphicsConfiguration().getDevice());
}

public static long square(Rectangle rec) {
    return Math.abs(rec.width * rec.height);
}

Upvotes: 2

Wolf
Wolf

Reputation: 912

Nate's solution seem to work in most, but not all cases, as I had to experience. perplexed mentions he had problems when monitors got connected, I had issues with "Win+Left" and "Win+Right" key commands. My solution to the problem looks like this (maybe the solution has problems on it's own, but at least this works better for me than Nate's solution):

GraphicsDevice myDevice = myFrame.getGraphicsConfiguration().getDevice();
for(GraphicsDevice gd:GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()){
    if(frame.getLocation().getX() >= gd.getDefaultConfiguration().getBounds().getMinX() &&
        frame.getLocation().getX() < gd.getDefaultConfiguration().getBounds().getMaxX() &&
        frame.getLocation().getY() >= gd.getDefaultConfiguration().getBounds().getMinY() &&
        frame.getLocation().getY() < gd.getDefaultConfiguration().getBounds().getMaxY())
        myDevice=gd;
}

Upvotes: 3

perplexed
perplexed

Reputation: 442

The method proposed by Nate does not work when another monitor has just been added to the system and the user repositions the Java window into that monitor. This is a situation my users frequently face, and the only way around it for me has been to restart java.exe to force it to reenumerate the monitors.

The main issue is myWindow.getGraphicsConfiguration().getDevice() always returns the original device where the Java Applet or app was started. You would expect it to show the current monitor, but my own experience (a very time consuming and frustrating one) is that simply relying on myWindow.getGraphicsConfiguration().getDevice() is not foolproof. If someone has a different approach that's more reliable, please let me know.

Performing the match for screens (using the allScreen[i].equals(myScreen) call) then continues to return the original monitor where the Applet was invoked, and not the new monitor where it might have gotten repositioned.

Upvotes: 7

Nate
Nate

Reputation: 16898

java.awt.Window is the base class of all top level windows (Frame, JFrame, Dialog, etc.) and it contains the getGraphicsConfiguration() method that returns the GraphicsConfiguration that window is using. GraphicsConfiguration has the getGraphicsDevice() method which returns the GraphicsDevice that the GraphicsConfiguration belongs to. You can then use the GraphicsEnvironment class to test this against all GraphicsDevices in the system, and see which one the Window belongs to.

Window myWindow = ....
// ...
GraphicsConfiguration config = myWindow.getGraphicsConfiguration();
GraphicsDevice myScreen = config.getDevice();
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
// AFAIK - there are no guarantees that screen devices are in order... 
// but they have been on every system I've used.
GraphicsDevice[] allScreens = env.getScreenDevices();
int myScreenIndex = -1;
for (int i = 0; i < allScreens.length; i++) {
    if (allScreens[i].equals(myScreen))
    {
        myScreenIndex = i;
        break;
    }
}
System.out.println("window is on screen" + myScreenIndex);

Upvotes: 30

Related Questions