Windows缩放

时间:2015-09-15 13:04:59

标签: java c++ windows

Windows 8/10已经开始包含一个滑块,用于缩放GUI元素的数量,右键单击桌面 - >显示。对于拥有笔记本电脑4k屏幕的同事来说,它是250%,而另一位同事在4k 28英寸屏幕上使用相同的分辨率则为150%。

如何以编程方式读取该值?我需要调整一些图形,使其在所有屏幕上看起来都一样。

我在Java RCP应用程序上使用Java,但是通过JNI使用C或C ++的方式也适用。我一直在四处寻找但找不到任何东西。

5 个答案:

答案 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)

也许来自answerhere可能会对您有所帮助:

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