I want to center my JFrame in a 4K Screen (3840x2400) with 250% scaling for Java 11. This screen is a secondary screen in Windows and placed left to the my main screen (Full HD, 1920x1080, 100% scaling). I have no another screens in my system.
I have following code to do it:
/**
* Locates the given window at the center of its current graphics device.
*
* @param aWindow window to center.
*/
public static void center(Window aWindow) { // window was created with a correct GraphicsConfiguration
final Dimension paneSize = aWindow.getSize();
Rectangle screenBounds = aWindow.getGraphicsConfiguration().getBounds();
subtractInsets(aWindow.getGraphicsConfiguration(), screenBounds);
aWindow.setLocation(screenBounds.x + (screenBounds.width - paneSize.width) / 2,
screenBounds.y + (screenBounds.height - paneSize.height) / 2);
}
private static void subtractInsets(GraphicsConfiguration display, Rectangle bounds) {
Insets ins = Toolkit.getDefaultToolkit().getScreenInsets(display);
bounds.x += ins.left;
bounds.y += ins.top;
bounds.width -= ins.left + ins.right;
bounds.height -= ins.top + ins.bottom;
}
When I run this code on Open JDK (Temurin) this code works correctly. And when I print my screen bounds i get java.awt.Rectangle[x=-1536,y=0,width=1536,height=960]. But when I run it on Oracle JDK my window goes placed on both screens (ugly) and when I print my screen bounds i get java.awt.Rectangle[x=-3840,y=0,width=1536,height=960].
I've found a solution, that works for both cases. Here is it:
/**
* Locates the given window at the center of its current graphics device.
*
* @param aWindow window to center.
*/
public static void center(Window aWindow) {
final Dimension paneSize = aWindow.getSize();
Rectangle screenBounds = aWindow.getGraphicsConfiguration().getBounds();
updateBoundsForDisplayIfRequired(screenBounds, aWindow.getGraphicsConfiguration());
subtractInsets(aWindow.getGraphicsConfiguration(), screenBounds);
aWindow.setLocation(screenBounds.x + (screenBounds.width - paneSize.width) / 2,
screenBounds.y + (screenBounds.height - paneSize.height) / 2);
}
private static void subtractInsets(GraphicsConfiguration display, Rectangle bounds) {
Insets ins = Toolkit.getDefaultToolkit().getScreenInsets(display);
bounds.x += ins.left;
bounds.y += ins.top;
bounds.width -= ins.left + ins.right;
bounds.height -= ins.top + ins.bottom;
}
private static void updateBoundsForDisplayIfRequired(@Nonnull Rectangle bounds, @Nonnull GraphicsConfiguration display) {
if (isOracleVM()) {
bounds.x = (int) Math.round(bounds.x * display.getDefaultTransform().getScaleX());
bounds.y = (int) Math.round(bounds.y * display.getDefaultTransform().getScaleY());
bounds.width = (int) Math.round(bounds.width * display.getDefaultTransform().getScaleX());
bounds.height = (int) Math.round(bounds.height * display.getDefaultTransform().getScaleY());
}
}
/**
* Checks whether we are in the Oracle VM. Some AWT features works different with Oracle vs. Open JDK.
*
* @return true if we are in oracle VM.
*/
public static boolean isOracleVM() {
return System.getProperty("java.vendor", "").contains("Oracle");
}
But I'm not sure whether it's a correct solution for all screen combinations and VMs. Can somebody verify/improve my code?