如何使用Java检测当前的显示器?

17

我有两个显示器连接,因此我可以在主显示器或次显示器上启动我的Java应用程序。

问题是:如何知道哪个显示器包含我的应用程序窗口,即是否有一种方法可以使用Java检测当前显示器?

6个回答

29

java.awt.Window 是所有顶层窗口(Frame、JFrame、Dialog等)的基类,其中包含 getGraphicsConfiguration() 方法,该方法返回窗口正在使用的GraphicsConfiguration。GraphicsConfiguration 有一个 getGraphicsDevice() 方法,它返回 GraphicsConfiguration 所属于的GraphicsDevice。您可以使用 GraphicsEnvironment 类来将其与系统中的所有 GraphicsDevices 进行比较,从而确定窗口属于哪个设备。

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);

7
Nate提出的方法在系统添加了另一个监视器并且用户将Java窗口重新定位到该监视器时将无法正常工作。这是我的用户经常遇到的情况,唯一的解决办法是重新启动java.exe来强制重新枚举监视器。
主要问题是myWindow.getGraphicsConfiguration().getDevice()总是返回启动Java Applet或应用程序的原始设备。您期望它显示当前监视器,但是我自己的经验(非常耗时和令人沮丧)表明,简单地依赖myWindow.getGraphicsConfiguration().getDevice()并不是绝对可靠的。如果有人有更可靠的方法,请告诉我。
使用allScreen[i].equals(myScreen)调用执行屏幕匹配,然后继续返回调用Applet的原始监视器,并不是可能重新定位的新监视器。

请检查我的答案...它可能对您有帮助。 - Wolf

3

Nate的解决方案在大多数情况下似乎是有效的,但并非所有情况都如此,我也遇到了一些问题。perplexed提到连接显示器时出现问题,我则在使用“Win+Left”和“Win+Right”键命令时遇到了问题。我的解决方案如下(也许这个解决方案本身存在问题,但至少对我来说比Nate的解决方案更好):

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;
}

1
您可以通过使用 Rectangle.contains 大幅简化和澄清该代码。 - toolforger
猜测(仅此而已),这种方法并不总是奏效,因为坐标系统可能存在多次,而非只是延伸到其他显示器。至少,在我看过的一些显卡中,用户可以进行此类设置。 - Dreamspace President


1
这对我有效。
    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);
}

0
稍微不同的用例:如果您想在某个地方创建窗口之前知道主显示器,而“显示器”在技术上意味着一个java.awt.GraphicsDevice,则相应的java.awt.GraphicsConfiguration应该是什么。

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

按顺序排列的GraphicsConfiguration-s列表如下:

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;
}

默认显示为列表中的第一个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接