Windows缩放

k0pti3hp  于 2023-02-16  发布在  Windows
关注(0)|答案(7)|浏览(398)

Windows 8/10已经开始包含一个滑块,用于调整GUI元素的大小,右键单击桌面-〉显示屏。对于一个使用笔记本电脑4k屏幕的同事来说,它是250%,而另一个同事使用相同分辨率的4k 28”屏幕,它是150%。
我如何以编程方式读取该值?我需要调整一些图形,使其在所有屏幕上看起来都一样。
我正在用Java开发一个Eclipse RCP应用程序,但是通过JNI使用C或C++的方法也可以工作,我已经四处寻找了,但是没有找到任何东西。

vnjpjtjt

vnjpjtjt1#

java.awt.Toolkit.getDefaultToolkit().getScreenResolution()参见API
以每英寸点数为单位返回屏幕分辨率。
假设你的100%是96像素,你可以计算你的缩放因子。

8ljdwjyq

8ljdwjyq2#

下面的工作对我来说。你需要得到窗口实际设备(多显示器环境)和计算它的约束尺寸和显示模式尺寸。

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

lnlaulya3#

也许here中的answer可以帮助您:

[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%
}
gojuced7

gojuced74#

虽然问题询问的是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);
    }
}
a64a0gku

a64a0gku5#

采用@seth-kitchen使用JNA的示例,这是可能的,即使在较老的JDK(如Java8)上也是如此。

**注意:**此技术的JNA部分在JDK 11上不能很好地工作。代码中的注解解释了它将如何回退到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))来增强它以获得当前窗口的显示。

1wnzp6jl

1wnzp6jl6#

此功能适用于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();
}
tjrkku2a

tjrkku2a7#

下面是一个“一行程序”,它应该可以为您提供比例因子:

double scale = java.awt.GraphicsEnvironment
    .getLocalGraphicsEnvironment()
    .getDefaultScreenDevice() // or cycle your getScreenDevices()
    .getDefaultConfiguration()
    .getDefaultTransform()
    .getScaleX();

如果您已经有一个java.awt.组件,您可以使用以下代码:

double scale = myComponent.getGraphicsConfiguration().getDefaultTransform().getScaleX();

(基于本文)

相关问题