Windows 8/10已经开始包含一个滑块,用于缩放GUI元素的数量,右键单击桌面 - >显示。对于拥有笔记本电脑4k屏幕的同事来说,它是250%,而另一位同事在4k 28英寸屏幕上使用相同的分辨率则为150%。
如何以编程方式读取该值?我需要调整一些图形,使其在所有屏幕上看起来都一样。
我在Java RCP应用程序上使用Java,但是通过JNI使用C或C ++的方式也适用。我一直在四处寻找但找不到任何东西。
答案 0 :(得分:1)
java.awt.Toolkit.getDefaultToolkit().getScreenResolution()
参见API
以每英寸点数返回屏幕分辨率。
假设您的100%是96像素,您就可以计算出缩放比例。
答案 1 :(得分:1)
即使在Java 8等较旧的JDK上,也可以通过JNA采用@ seth-kitchen的示例。
注意:该技术的JNA部分在JDK11上无法正常工作。代码中的注释说明了它如何回退到Toolkit
技术。
public static int getScaleFactor() {
WinDef.HDC hdc = GDI32.INSTANCE.CreateCompatibleDC(null);
if (hdc != null) {
int actual = GDI32.INSTANCE.GetDeviceCaps(hdc, 10 /* VERTRES */);
int logical = GDI32.INSTANCE.GetDeviceCaps(hdc, 117 /* DESKTOPVERTRES */);
GDI32.INSTANCE.DeleteDC(hdc);
// JDK11 seems to always return 1, use fallback below
if (logical != 0 && logical/actual > 1) {
return logical/actual;
}
}
return (int)(Toolkit.getDefaultToolkit().getScreenResolution() / 96.0);
}
为简单起见,上述解决方案获取默认显示。您可以通过找到当前窗口句柄(通过Native.getComponentPointer(Component)
或使用User32.INSTANCE.FindWindow(...)
按标题)然后使用CreateaCompatibleDC(GetDC(window))
来增强它,以显示当前窗口。
答案 2 :(得分:0)
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
VERTRES = 10,
DESKTOPVERTRES = 117,
// http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
}
private float getScalingFactor()
{
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();
int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
return ScreenScalingFactor; // 1.25 = 125%
}
答案 3 :(得分:0)
尽管该问题询问有关Windows扩展的问题,但是可接受的解决方案在运行JDK11的Linux上无法正常工作。
以下技术使用JNA来检测Linux上的屏幕比例因子,该因子与公开Gtk(Gimp工具包)库的Linux桌面兼容。
由于暴露缩放信息的Gtk API已多次更改,因此该代码段包含一些与Gtk版本相关的解决方法。此外,由于扩展特定于监视器,因此对于特定用例(同一台式机上的混合标准监视器和HiDPI监视器),信息可能不准确。
警告:如果Java在以后的版本中解决了此问题(或者Gtk更改了其API),则必须更新此解决方案。此外,该解决方案仅需要Linux组件:需要(包括)反射才能成功进行交叉编译。
用法:GtkUtilities.getScaleFactor()
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import java.lang.reflect.Method;
public class GtkUtilities {
/**
* Initializes Gtk2/3 and returns the desktop scaling factor, usually 1.0 or 2.0
*/
public static double getScaleFactor() {
GTK gtkHandle = getGtkInstance();
if (gtkHandle != null && gtkHandle.gtk_init_check(0, null)) {
System.out.println("Initialized Gtk");
if (gtkHandle instanceof GTK2) {
return getGtk2ScaleFactor((GTK2)gtkHandle);
} else {
return getGtk3ScaleFactor((GTK3)gtkHandle);
}
} else {
System.err.println("An error occurred initializing the Gtk library");
}
return 0;
}
private static GTK getGtkInstance() {
System.out.println("Finding preferred Gtk version...");
switch(getGtkMajorVersion()) {
case 2:
return GTK2.INSTANCE;
case 3:
return GTK3.INSTANCE;
default:
System.err.println("Not a compatible Gtk version");
}
return null;
}
/**
* Get the major version of Gtk (e.g. 2, 3)
* UNIXToolkit is unavailable on Windows or Mac; reflection is required.
* @return Major version if found, zero if not.
*/
private static int getGtkMajorVersion() {
try {
Class toolkitClass = Class.forName("sun.awt.UNIXToolkit");
Method versionMethod = toolkitClass.getDeclaredMethod("getGtkVersion");
Enum versionInfo = (Enum)versionMethod.invoke(toolkitClass);
Method numberMethod = versionInfo.getClass().getDeclaredMethod("getNumber");
int version = ((Integer)numberMethod.invoke(versionInfo)).intValue();
System.out.println("Found Gtk " + version);
return version;
} catch(Throwable t) {
System.err.println("Could not obtain GtkVersion information from UNIXToolkit: {}", t.getMessage());
}
return 0;
}
private static double getGtk2ScaleFactor(GTK2 gtk2) {
Pointer display = gtk2.gdk_display_get_default();
System.out.println("Gtk 2.10+ detected, calling \"gdk_screen_get_resolution\"");
Pointer screen = gtk2.gdk_display_get_default_screen(display);
return gtk2.gdk_screen_get_resolution(screen) / 96.0d;
}
private static double getGtk3ScaleFactor(GTK3 gtk3) {
Pointer display = gtk3.gdk_display_get_default();
int gtkMinorVersion = gtk3.gtk_get_minor_version();
if (gtkMinorVersion < 10) {
System.err.println("Gtk 3.10+ is required to detect scaling factor, skipping.");
} else if (gtkMinorVersion >= 22) {
System.out.println("Gtk 3.22+ detected, calling \"gdk_monitor_get_scale_factor\"");
Pointer monitor = gtk3.gdk_display_get_primary_monitor(display);
return gtk3.gdk_monitor_get_scale_factor(monitor);
} else if (gtkMinorVersion >= 10) {
System.out.println("Gtk 3.10+ detected, calling \"gdk_screen_get_monitor_scale_factor\"");
Pointer screen = gtk3.gdk_display_get_default_screen(display);
return gtk3.gdk_screen_get_monitor_scale_factor(screen, 0);
}
return 0;
}
/**
* Gtk2/Gtk3 wrapper
*/
private interface GTK extends Library {
// Gtk2.0+
boolean gtk_init_check(int argc, String[] argv);
Pointer gdk_display_get_default();
Pointer gdk_display_get_default_screen (Pointer display);
}
private interface GTK3 extends GTK {
GTK3 INSTANCE = Native.loadLibrary("gtk-3", GTK3.class);
// Gtk 3.0+
int gtk_get_minor_version ();
// Gtk 3.10-3.21
int gdk_screen_get_monitor_scale_factor (Pointer screen, int monitor_num);
// Gtk 3.22+
Pointer gdk_display_get_primary_monitor (Pointer display);
int gdk_monitor_get_scale_factor (Pointer monitor);
}
private interface GTK2 extends GTK {
GTK2 INSTANCE = Native.loadLibrary("gtk-x11-2.0", GTK2.class);
// Gtk 2.1-3.0
double gdk_screen_get_resolution(Pointer screen);
}
}
答案 4 :(得分:0)
以下对我有用。您需要获取窗口实际设备(用于多显示器环境)并计算其绑定尺寸再加上显示模式尺寸。
public static double getWindowScale(Window window) {
GraphicsDevice device = getWindowDevice(window);
return device.getDisplayMode().getWidth() / (double) device.getDefaultConfiguration().getBounds().width;
}
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);
}