简体   繁体   English

MacOS BigSur 自动缩放 Java16/Swing 应用程序 window 用于 5K 视网膜显示屏

[英]MacOS BigSur auto-scales Java16/Swing app window for 5K Retina display

Our interactive math-ed app is designed using Swing JFrames, and was developed for 2560p (Mac) and 1920p (Win) displays, ie, using native pixel-coordinates for graphics output and mouse-input-processing.我们的交互式数学应用程序使用 Swing JFrames 设计,并针对 2560p (Mac) 和 1920p (Win) 显示器开发,即使用图形 output 的原生像素坐标和鼠标输入处理。

iMac Retina 5K testing -- BIG SURPRISE. iMac Retina 5K 测试——大惊喜。 The app window's normal width is 1/2 screen width.应用程序窗口的正常宽度是屏幕宽度的 1/2。 I was fully expecting a problem when running on a hi-rez (5120p) iMac -- 1/4 screen-width, But NO.我完全预料到在 hi-rez (5120p) iMac 上运行时会出现问题——1/4 屏幕宽度,但没有。 it renders 1/2 screen wide.它呈现 1/2 屏幕宽。

Looking into where the program polls the system for display device bounds:查看程序在何处轮询系统以获取显示设备边界:

    GraphicsDevice[] deviceList = getLocalGraphicsEnvironment.getScreenDevices()

    GraphicsConfiguration[] gc = deviceList[0].getConfigurations();

    Rectangle deviceBounds = gc[0].getBounds(); 

I see that it comes back as [ 0, 0, 2560, 1440 ] even though the MacOS System Report says [5120 x 2880 ].我看到它返回为 [0, 0, 2560, 1440],即使 MacOS 系统报告显示 [5120 x 2880]。

Futhermore, the MouseEvent coordinates fed as input to the app are "halved" so as to agree with the deviceBounds.此外,作为应用程序输入的 MouseEvent 坐标被“减半”,以便与 deviceBounds 一致。

I can't find any explanation for these test results.我找不到对这些测试结果的任何解释。 Needless to say, I'm elated that the app runs perfectly on the 5K Retina iMac without modifications.不用说,我很高兴该应用程序无需修改即可在 5K 视网膜 iMac 上完美运行。

However, I really need to understand who is auto-scaling-down the native graphics environment.但是,我真的需要了解是谁在自动缩小本机图形环境。 Is this something the MacOS does?这是 MacOS 的功能吗? Something Java16 does for Swing apps? Java16 为 Swing 个应用做了什么? Or, something the Java16 MacOS JRE does for Swing apps?或者,Java16 MacOS JRE 为 Swing 应用程序做了什么? 4th possibility?第四种可能?

tl;dr tl;博士

You asked:你问:

I really need to understand who is auto-scaling-down the native graphics environment.我真的需要了解谁在自动缩小本机图形环境。

  • The macOS scales the screen, providing a logical versus physical screen resolution to apps. macOS 缩放屏幕,为应用程序提供逻辑与物理屏幕分辨率。
  • Java 2D , Java AWT , and Java Swing respect and leverage that scaling. Java 2DJava AWTJava Swing尊重并利用这种缩放。

Details细节

Caveat: I am not an expert in how Swing graphics work, but I may be able to give you a basic picture (pun intended.) of what is going on.警告:不是Swing 图形如何工作的专家,但我可以给你一个基本的图片(双关语)。


To simplify the story, you can think of there being logical pixels versus physical pixels.为了简化这个故事,您可以考虑存在逻辑像素与物理像素。

In the old days, such as the original Mac, 72 pixels were distributed across one inch of actual screen space.在过去,例如最初的 Mac,72 个像素分布在一英寸的实际屏幕空间中。 This number of 72 PPI was chosen because it nearly aligns with the typographical unit of a point , with approximately 72 points to the inch.选择 72 PPI 这个数字是因为它几乎与的印刷单位对齐,大约 72 点等于英寸。 (Actually 1 point is equal to 0.013836 inch, so 72 points are 0.996264 inch.) (实际上 1 磅等于 0.013836 英寸,所以 72 磅等于 0.996264 英寸。)

Over the decades, screens grew larger, and pixel density increased with more and more smaller pixels crammed together.几十年来,屏幕变得越来越大,像素密度随着越来越多的小像素挤在一起而增加。 Eventually we had an embarrassment of riches , enough pixels that we could “waste” them on finer detailing, filling in the jaggies for smoother fonts and lines.最终我们遇到了丰富的尴尬,足够的像素我们可以将它们“浪费”在更精细的细节上,填充锯齿以获得更平滑的 fonts 和线条。 Apple refers to their implementation of this as Retina screens; Apple 将其实现称为Retina屏幕; other OSes have similar schemes (of debatable quality).其他操作系统也有类似的方案(质量值得商榷)。 Nowadays, displays have from over 200 to almost 500 pixels per inch.如今,显示器每英寸有超过 200 到近 500 个像素。

To set aside the extra physical pixels for more smoothing, we need logical pixels, imaginary pixels, that the apps think they are painting.为了更平滑地留出额外的物理像素,我们需要应用程序认为它们正在绘制的逻辑像素、虚构像素。 Apple used to use 72 pixels per inch (PPI) for this, for compatibility with older software unaware of the extra smoothing issues. Apple 曾经为此使用每英寸 72 像素 (PPI),以便与未意识到额外平滑问题的旧软件兼容。 That may still be the case, or perhaps nowadays the PPI is variable (I don't know).情况可能仍然如此,或者现在 PPI 可能是可变的(我不知道)。 But the exact number is beside the point.但确切的数字无关紧要。 The point is the logical pixels-per-inch is much less than the physical.关键是逻辑每英寸像素比物理像素少得多。

➥ And germane to your Question, modern Java Swing graphics technology respects those logical pixels while allowing for extra smoothing by the extra physical pixels. ➥ 与您的问题密切相关,现代 Java Swing 图形技术尊重这些逻辑像素,同时允许通过额外的物理像素进行额外的平滑处理。

As I vaguely recall, this may not have been the case in the early transition period, where the extra pixels were wasted, not used for smoothing/detailing.我依稀记得,在早期过渡时期可能不是这种情况,多余的像素被浪费了,没有用于平滑/细节处理。 So, for a while, back then, a Swing app would have appeared "chunky"/"jaggy" while on-screen next to other apps that were Retina-savvy.因此,有一段时间,Swing 应用程序在屏幕上与其他支持 Retina 的应用程序相邻时会显得“矮胖”/“锯齿状”。 Eventually Java 2D & Java Swing were enhanced to be Retina-savvy.最终 Java 2D 和 Java Swing 被增强为 Retina-savvy。 And, voilà , modern Swing apps look great on high-res screens.而且,瞧,现代Swing应用程序在高分辨率屏幕上看起来很棒。

(By the way, in Java 17 the Java graphics technology is being reworked to integrate with Apple's Metal framework rather than OpenGL , for faster and richer graphics.) (顺便说一下,在Java 17 中,Java 图形技术正在重新设计以与 Apple 的Metal框架而不是OpenGL 集成,以获得更快和更丰富的图形。)

The ratio of how many extra physical pixels are reserved for extra smoothing is controlled by the user.为额外平滑保留多少额外物理像素的比例由用户控制。 On macOS you control a setting in System Preferences > Display > Resolution .在 macOS 上,您可以在System Preferences > Display > Resolution中控制设置。 There you determine the logical pixel count.在那里您可以确定逻辑像素数。

Here is a screenshot of my own system, a MacBook Pro (13-inch, M1, 2020) with an external BenQ 4K monitor attached (which I highly recommend by the way, certified as truly flicker-free).这是我自己系统的屏幕截图,一台 MacBook Pro(13 英寸,M1,2020),外接 BenQ 4K 显示器(我强烈推荐,经认证为真正无闪烁)。

Notice how the monitor is physically built with 3,840 pixels across horizontally and 2,160 pixels high vertically.请注意显示器的物理构造,水平方向为 3,840 像素,垂直方向为 2,160 像素。 This 3840 × 2160 is commonly known as 4K display .这种 3840×2160 就是俗称的4K 显示器

But I have Retina scaling engaged.但我有Retina缩放功能。 So the OS and apps act as if I had only 3,008 by 1,692 pixels, the logical pixel count.因此,操作系统和应用程序就像我只有 3,008 x 1,692 像素(逻辑像素数)一样。 I engage this smoothing so that (a) content appears larger, and more importantly (b) content appears smoother with greater detail filled-in.我进行了这种平滑处理,以便 (a) 内容看起来更大,更重要的是 (b) 内容看起来更平滑,并填充了更多细节。

报告逻辑屏幕分辨率的自定义 Java Swing 应用程序屏幕截图、确认逻辑屏幕分辨率的系统报告和显示实际物理像素数的系统信息应用程序。

In the upper-left corner is a white app window from a custom Java program I wrote.左上角是一个白色应用程序 window,来自我编写的自定义 Java 程序。 This app reports the screens as seen by Java Swing. The green call-out lines are for my internal monitor, while the orange lines are for my external 4K monitor discussed above.此应用程序报告 Java Swing 看到的屏幕。绿色标注线用于我的内部显示器,而橙色线用于我上面讨论的外部 4K 显示器。

➥ Notice how Java Swing reports the same logical pixel resolution as we set in scaling. ➥ 注意 Java Swing 如何报告与我们在缩放中设置的相同的逻辑像素分辨率。 So if you size your Java Swing JFrame window to be half the width of the screen, you would in this case be sizing to half of 3008 rather than half of 3840.因此,如果您将 Java Swing JFrame window 调整为屏幕宽度的一半,那么在这种情况下,您将调整为 3008 的一半而不是 3840 的一半。

You can experiment with this app.您可以试用此应用程序。 Change the scaling factor of your Mac, then click the Update screen info button to see fresh numbers.更改 Mac 的比例因子,然后点按“更新屏幕信息”按钮以查看新数字。

➥ Given that you seem to be surprised by this behavior, I suspect you had disengaged the Retina scaling on your previous Mac. ➥ 鉴于您似乎对这种行为感到惊讶,我怀疑您在以前的 Mac 上取消了 Retina 缩放。 Without scaling engaged, your software was using “native” physical pixels rather than logical pixels.如果不进行缩放,您的软件将使用“本机”物理像素而不是逻辑像素。 You could say that as the physical pixels equalled the virtual pixels, mapped one-to-one.您可以这样说,因为物理像素等于虚拟像素,一对一映射。

Here is the source-code for that app.这是该应用程序的源代码。

package work.basil.screen;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

// Example app to show current logical screen resolutions.
// By Basil Bourque. http://www.Basil.work/
public class Screener extends JFrame
{
    public static void main ( String[] args )
    {
        Screener frame = new Screener();
        frame.setVisible( true );
    }

    // Constructor
    public Screener ()
    {
        // Layout
        this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
        this.setPreferredSize( new Dimension( 600 , 200 ) );
        this.setLayout( new BorderLayout() );

        // Widgets
        JTextArea report = new JTextArea( "report goes here" );
        report.setLineWrap( true );
        report.setWrapStyleWord( true );

        JButton update = new JButton( "Update screen info" );
        update.addActionListener( ( ActionEvent e ) -> report.setText( reportScreenInfo() ) );

        // Arrange
        this.add( report , BorderLayout.CENTER );
        this.add( update , BorderLayout.PAGE_END );
        this.pack();
    }

    private String reportScreenInfo ()
    {
        List < String > reportItems = new ArrayList <>();

        GraphicsDevice[] deviceList = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
        for ( GraphicsDevice graphicsDevice : deviceList )
        {
            reportItems.add( "graphicsDevice ID: " + graphicsDevice.getIDstring() );
            GraphicsConfiguration[] graphicsConfigurations = graphicsDevice.getConfigurations();
            for ( GraphicsConfiguration gc : graphicsConfigurations )
            {
                reportItems.add( "bounds: " + gc.getBounds() );
            }
        }

        String result = String.join( System.lineSeparator() , reportItems );
        return result;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM