窗口缩放
Windows scaling
Windows 8/10已经开始包含一个滑块,用于显示GUI元素应该缩放多少,右键单击桌面->显示。一个同事用4k屏幕的笔记本电脑是250%,而另一个同事用同样分辨率的4k 28英寸屏幕是150%。
如何以编程方式读取该值?我需要调整一些图形,让它在所有屏幕上看起来都一样。
我在Eclipse RCP应用程序上使用Java,但是通过JNI使用C或c++的方法也可以工作。
java.awt.Toolkit.getDefaultToolkit().getScreenResolution()
参见API
以每英寸点为单位返回屏幕分辨率。
假设你的100%是96像素,你可以计算你的缩放系数
以下内容适合我。你需要获得窗口实际设备(多显示器环境),并计算它的绑定尺寸与显示模式尺寸。
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);
}
也许这里的答案可以帮助你:
[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%
}
虽然这个问题问的是Windows的伸缩,但被接受的解决方案在运行JDK11的Linux上不能正常工作。
下面的技术使用JNA来检测Linux上的屏幕比例因子,这与公开Gtk (Gimp Toolkit)库的Linux桌面兼容。
该代码片段包含几个Gtk版本相关的解决方案,因为Gtk API暴露的缩放信息已经更改了几次。此外,对于特定的用例(同一桌面上的混合标准和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);
}
}
采用@seth-kitchen使用JNA的示例,这是可能的,即使在Java 8等较旧的jdk上也是如此。
注意:该技术的JNA部分在JDK11上不能很好地工作。代码中的注释解释了它将如何回退到Toolkit
技术。
public static double 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 (double)logical/actual;
}
}
return Toolkit.getDefaultToolkit().getScreenResolution() / 96.0d;
}
为了简单起见,上面的解决方案获取默认显示。您可以通过查找当前窗口句柄(通过Native.getComponentPointer(Component)
或通过User32.INSTANCE.FindWindow(...)
的标题),然后使用CreateaCompatibleDC(GetDC(window))
来增强它以获得当前窗口的显示。
这里有一个" one liner ";这应该会给你比例因子:
double scale = java.awt.GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getDefaultScreenDevice() // or cycle your getScreenDevices()
.getDefaultConfiguration()
.getDefaultTransform()
.getScaleX();
如果您已经有一个java.awt。组件,你可以用这个代替:
double scale = myComponent.getGraphicsConfiguration().getDefaultTransform().getScaleX();
(基于本文)
这适用于macOS和Windows与Java 17
public static Window getWindow(Component component) {
return component instanceof Window ? (Window) component : getWindow(component.getParent());
}
@Override
public synchronized void paintComponent(Graphics g) {
super.paintComponent(g);
float displayScaling = (float) getWindow(this).getGraphicsConfiguration().getDefaultTransform().getScaleX();
}
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 计算缩放多边形的比例,得到给定的多边形面积
- QwtPlot具有相等的轴和自动缩放
- 如何在directx/c++中进行平移/缩放操作
- 在Qt中实现无限可缩放的画布
- SDL2 调整窗口大小后如何缩放鼠标坐标?
- 如何在C++中使用TCP窗口缩放来提高AWS S3的吞吐量
- 如何在 direct2d 中使用随其窗口重新缩放的效果绘制图像
- 使用 Win32 将 GDI 绘制大小缩放为窗口大小
- 当窗口大小更改时,如何自动缩放QT中的图表
- Qt 5 缩放整个窗口
- 在窗口中获取缩放百分比
- 如何在窗口中缩放屏幕
- Windows 7中的TCP窗口缩放
- 设置SO_RCVBUF会降低窗口缩放因子
- 使用 C++ 在窗口中进行硬件加速图像缩放
- Windows上的TCP窗口缩放
- OpenGL中的缩放窗口
- Qt QLabel缩放图像与窗口
- 窗口缩放