在双显示器配置中,将JFrame显示在特定屏幕上

50

我有一个双显示器的配置,如果找到了特定的显示器,我希望在其中一个显示器上运行我的GUI。 我试图创建我的JFrame窗口并传递一个屏幕设备的GraphicConfiguration对象,但它不起作用,框架仍然显示在主屏幕上。

我该如何设置窗口必须显示在哪个屏幕上?

12个回答

45
public static void showOnScreen( int screen, JFrame frame )
{
    GraphicsEnvironment ge = GraphicsEnvironment
        .getLocalGraphicsEnvironment();
    GraphicsDevice[] gs = ge.getScreenDevices();
    if( screen > -1 && screen < gs.length )
    {
        gs[screen].setFullScreenWindow( frame );
    }
    else if( gs.length > 0 )
    {
        gs[0].setFullScreenWindow( frame );
    }
    else
    {
        throw new RuntimeException( "No Screens Found" );
    }
}

8
这与“全屏模式”有什么关系呢?如果我不需要使用全屏模式呢? - Dims
1
@Dims,我给出了一个新的答案,不会强制全屏。 - ryvantage
在我的垂直双显示器设置上,这个方法对我来说不起作用。虽然两个显示器都被GraphicsDevices检测到了,但是框架总是显示在主屏幕上。 - Mahm00d

40
我修改了@Joseph-gordon的答案,以实现在不强制全屏的情况下实现此目的。
public static void showOnScreen( int screen, JFrame frame ) {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gd = ge.getScreenDevices();
    if( screen > -1 && screen < gd.length ) {
        frame.setLocation(gd[screen].getDefaultConfiguration().getBounds().x, frame.getY());
    } else if( gd.length > 0 ) {
        frame.setLocation(gd[0].getDefaultConfiguration().getBounds().x, frame.getY());
    } else {
        throw new RuntimeException( "No Screens Found" );
    }
}

在这段代码中,我假设getDefaultConfiguration()永远不会返回null。如果这不是真的,请有人纠正我。但是,这段代码可以将您的JFrame移动到所需的屏幕上。


6
仅当设备未垂直对齐时,此解决方案才有效。请将 frame.getY() 替换为 gd[0].getDefaultConfiguration().getBounds().y + frame.getY() 以解决此问题。 - Ercksen
1
这个解决方案(包括@Ercksen的评论)很好,但窗口略微偏离中心。为了修复它,请在showOnScreen(SCREEN_ID,frame)调用结束后或之后调用frame.setExtendedState(frame.getExtendedState()| JFrame.MAXIMIZED_BOTH); - shan
1
那个 int screen 是用来干嘛的?它是用来表示第一台监视器和第二台监视器的 0 和 1 的索引代码吗? - gumuruh

5

我修改了@Joseph-gordon和@ryvantage的答案,以实现在不强制全屏、固定屏幕配置的情况下,在所选屏幕上居中显示:

public void showOnScreen(int screen, JFrame frame ) {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gd = ge.getScreenDevices();
    int width = 0, height = 0;
    if( screen > -1 && screen < gd.length ) {
        width = gd[screen].getDefaultConfiguration().getBounds().width;
        height = gd[screen].getDefaultConfiguration().getBounds().height;
        frame.setLocation(
            ((width / 2) - (frame.getSize().width / 2)) + gd[screen].getDefaultConfiguration().getBounds().x, 
            ((height / 2) - (frame.getSize().height / 2)) + gd[screen].getDefaultConfiguration().getBounds().y
        );
        frame.setVisible(true);
    } else {
        throw new RuntimeException( "No Screens Found" );
    }
}

第5行对“display”的引用未定义。这是指什么? - Chris K
这在垂直设置下对我来说完美运作。 - Mahm00d

4
在阅读了JFrame.setLocationRelativeTo的文档之后,发现一个更为简洁的解决方案:在第二个屏幕上显示。
public void moveToScreen() {
    setVisible(false);
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] screens = ge.getScreenDevices();
    int n = screens.length;
    for (int i = 0; i < n; i++) {
        if (screens[i].getIDstring().contentEquals(settings.getScreen())) {
            JFrame dummy = new JFrame(screens[i].getDefaultConfiguration());
            setLocationRelativeTo(dummy);
            dummy.dispose();
        }
    }
    setVisible(true);
}

这个函数可以用来在屏幕之间切换应用程序窗口


6
设置是指用来配置或调整计算机软件、应用程序或设备的选项和参数,以满足用户的特定需求。 - Machado
这可能是一些设置解析器的输出,其中有一个名为screen的字符串字段。 - rhbvkleef
界面与框架是否需要定位? - undefined

2

每个人都在基于其他风格做出他们自己的风味,我也加入了我的意见,因为其他人对于窗口在选定屏幕上的位置进行了限制。

它是最好的选择。它允许你在另一个屏幕上设置位置。

public void setLocation( int screen, double x, double y ) {
        GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice[]    d = g.getScreenDevices();

        if ( screen >= d.length ) {
                screen = d.length - 1;
        }

        Rectangle bounds = d[screen].getDefaultConfiguration().getBounds();
        
        // Is double?
        if ( x == Math.floor(x) && !Double.isInfinite(x) ) {
                x *= bounds.x;  // Decimal -> percentage
        }
        if ( y == Math.floor(y) && !Double.isInfinite(y) ) {
                y *= bounds.y;  // Decimal -> percentage
        }

        x = bounds.x      + x;
        y = jframe.getY() + y;

        if ( x > bounds.x) x = bounds.x;
        if ( y > bounds.y) y = bounds.y;

        // If double we do want to floor the value either way 
        jframe.setLocation((int)x, (int)y);
}

例子:

setLocation(2, 200, 200);

Even允许您传递屏幕位置的百分比!

setLocation(2, 0.5, 0);     // Place on right edge from the top down if combined with setSize(50%, 100%);

屏幕必须大于0,我相信这是一个严格的要求!

要放在最后,只需使用Integer.MAX_VALUE.调用即可。


2

似乎在每个屏幕上创建了一些框架。 - undefined

1

基于 @ryvantage 的答案,我进行了改进,使其显示在屏幕中央:

private static void showOnScreen( int screen, Window frame ) {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gd = ge.getScreenDevices();
    GraphicsDevice graphicsDevice;
    if( screen > -1 && screen < gd.length ) {
        graphicsDevice = gd[screen];
    } else if( gd.length > 0 ) {
        graphicsDevice = gd[0];
    } else {
        throw new RuntimeException( "No Screens Found" );
    }
    Rectangle bounds = graphicsDevice.getDefaultConfiguration().getBounds();
    int screenWidth = graphicsDevice.getDisplayMode().getWidth();
    int screenHeight = graphicsDevice.getDisplayMode().getHeight();
    frame.setLocation(bounds.x + (screenWidth - frame.getPreferredSize().width) / 2,
            bounds.y + (screenHeight - frame.getPreferredSize().height) / 2);
    frame.setVisible(true);
}

1

我的经验是将桌面扩展到多个显示器上,而不是将这些显示器配置为独立的(X11)显示。如果您不想这样做,那么这个方法不适用。

我的解决方案有点取巧:我调用了 Toolkit.getScreenSize() 方法,判断是否处于多显示器环境中(通过比较高度和宽度,并假设宽度大于两倍的高度表示多显示器),然后设置窗口的初始 X 和 Y 位置。


谢谢您的建议。我使用jframe.setBounds(graphicConfiguration.getBounds())解决了问题。 - blow

0

Vicky的回答包含了正确的指针。它是通过new JFrame(GraphicsConfiguration gc)实现的。

你可以这样做:

GraphicsDevice otherScreen = getOtherScreen(this);
JFrame frameOnOtherScreen = new JFrame(otherScreen.getDefaultConfiguration());

private GraphicsDevice getOtherScreen(Component component) {
    GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
    if (graphicsEnvironment.getScreenDevices().length == 1) {
        // if there is only one screen, return that one
        return graphicsEnvironment.getScreenDevices()[0];
    }

    GraphicsDevice theWrongOne = component.getGraphicsConfiguration().getDevice();
    for (GraphicsDevice dev : graphicsEnvironment.getScreenDevices()) {
        if (dev != theWrongOne) {
            return dev;
        }
    }

    return null;
}

0

如果您想将其设置为左屏幕的中心:

int halfScreen = (int)(screenSize.width/2);
                frame.setLocation((halfScreen - frame.getSize().width)/2, (screenSize.height - frame.getSize().height)/2);

如果您想将其设置为屏幕右侧的中心:

int halfScreen = (int)(screenSize.width/2);
                frame.setLocation((halfScreen - frame.getSize().width)/2 + halfScreen, (screenSize.height - frame.getSize().height)/2);

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