pbi*_*rre 3 java swing retina-display java-16 macos-big-sur
我们的交互式数学应用程序是使用 Swing JFrames 设计的,并针对 2560p (Mac) 和 1920p (Win) 显示器开发,即使用本机像素坐标进行图形输出和鼠标输入处理。
iMac Retina 5K 测试——大惊喜!应用程序窗口的正常宽度是屏幕宽度的 1/2。我完全预料到在高分辨率 (5120p) iMac(1/4 屏幕宽度)上运行时会出现问题。但不,它呈现 1/2 屏幕宽。
查看程序在何处轮询系统以获取显示设备边界:
GraphicsDevice[] deviceList = getLocalGraphicsEnvironment.getScreenDevices()
GraphicsConfiguration[] gc = deviceList[0].getConfigurations();
Rectangle deviceBounds = gc[0].getBounds();
Run Code Online (Sandbox Code Playgroud)
我看到它返回为 [ 0, 0, 2560, 1440 ],尽管 MacOS 系统报告显示为 [5120 x 2880 ]。
此外,作为应用程序输入的 MouseEvent 坐标被“减半”,以便与 deviceBounds 一致。
我找不到这些测试结果的任何解释。不用说,我很高兴该应用程序无需修改即可在 5K Retina iMac 上完美运行。
但是,我确实需要了解谁在自动缩小本机图形环境。MacOS 就是这么做的吗?Java16 对 Swing 应用程序做了什么?或者,Java16 MacOS JRE 为 Swing 应用程序做了什么?第四种可能性?
你问:
\n\n\n我真的需要了解谁在自动缩小本机图形环境。
\n
警告:我不是Swing 图形工作原理方面的专家,但我也许可以向您提供有关正在发生的情况的基本图片(双关语!)。
\n为了简化故事,您可以认为存在逻辑像素与物理像素。
\n在过去,例如最初的 Mac,72 个像素分布在一英寸的实际屏幕空间上。选择 72 PPI 这个数字是因为它几乎与点的印刷单位对齐,即每英寸大约有 72 个点。(实际上 1 点等于 0.013836 英寸,因此 72 点等于 0.996264 英寸。)
\n几十年来,屏幕变得越来越大,像素密度也随着越来越多的小像素挤在一起而增加。最终我们遇到了丰富的尴尬,足够的像素,我们可以 \xe2\x80\x9cwaste\xe2\x80\x9d 进行更精细的细节处理,填充锯齿以获得更平滑的字体和线条。Apple 将其实现称为Retina屏幕;其他操作系统也有类似的方案(质量有争议)。如今,显示器每英寸像素数从 200 多个到近 500 个不等。
\n为了留出额外的物理像素以实现更平滑,我们需要应用程序认为它们正在绘制的逻辑像素、虚拟像素。Apple 过去为此使用 72 像素/英寸 (PPI),以便与旧版软件兼容,而没有意识到额外的平滑问题。情况可能仍然如此,或者也许现在 PPI 是可变的(我不知道)。但具体数字不是重点。关键是逻辑每英寸像素远低于物理像素。
\n\xe2\x9e\xa5 与你的问题密切相关,现代 Java Swing 图形技术尊重那些逻辑像素,同时允许通过额外的物理像素进行额外的平滑。
\n我依稀记得,早期过渡时期的情况可能并非如此,额外的像素被浪费了,没有用于平滑/细节处理。因此,当时有一段时间,Swing 应用程序在屏幕上与其他支持 Retina 的应用程序旁边时会显得“厚重”/“锯齿”。最终,Java 2D 和 Java Swing 得到增强,支持 Retina。并且,瞧\xc3\xa0,现代 Swing 应用程序在高分辨率屏幕上看起来很棒。
\n(顺便说一句,在Java 17 中,Java 图形技术正在重新设计,以与 Apple\xe2\x80\x99s Metal框架集成,而不是与OpenGL 集成集成,以获得更快、更丰富的图形。)
\n保留多少额外物理像素用于额外平滑的比例由用户控制。在 macOS 上,您可以在“系统偏好设置” > “显示” > “分辨率”中控制设置。您可以在此处确定逻辑像素数。
\n这是我自己的系统的屏幕截图,一台 MacBook Pro(13 英寸,M1,2020),连接了外部 BenQ 4K 显示器(顺便说一句,我强烈推荐,经过认证)无闪烁)。
\n请注意显示器的物理构造,水平方向为 3,840 像素,垂直方向为 2,160 像素。这个3840\xe2\x80\x89\xc3\x97\xe2\x80\x892160就是俗称的4K显示器。
\n但我有视网膜缩放功能。因此,操作系统和应用程序的表现就好像我只有 3,008 x 1,692 像素(逻辑像素数)。我进行这种平滑处理,以便 (a) 内容显得更大,更重要的是 (b) 内容显得更平滑,填充了更多细节。
\n\n左上角是一个白色的应用程序窗口,来自我编写的自定义 Java 程序。该应用程序报告 Java Swing 所看到的屏幕。绿色标注线用于我的内部显示器,而橙色线用于上面讨论的外部 4K 显示器。
\n\xe2\x9e\xa5 请注意 Java Swing 如何报告与我们在缩放中设置的相同的逻辑像素分辨率。因此,如果将 Java SwingJFrame窗口的大小设置为屏幕宽度的一半,则在这种情况下,您的大小将设置为 3008 的一半,而不是 3840 的一半。
您可以尝试一下这个应用程序。更改 Mac 的缩放系数,然后单击“更新屏幕信息”按钮以查看新的数字。
\n\xe2\x9e\xa5 鉴于您似乎对这种行为感到惊讶,我怀疑您已经在之前的 Mac 上禁用了 Retina 缩放功能。如果不进行缩放,您的软件将使用 \xe2\x80\x9cnative\xe2\x80\x9d 物理像素而不是逻辑像素。您可以说,物理像素等于虚拟像素,一对一映射。
\n这是该应用程序的源代码。
\npackage work.basil.screen;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.ActionEvent;\nimport java.util.ArrayList;\nimport java.util.List;\n\n// Example app to show current logical screen resolutions.\n// By Basil Bourque. http://www.Basil.work/\npublic class Screener extends JFrame\n{\n public static void main ( String[] args )\n {\n Screener frame = new Screener();\n frame.setVisible( true );\n }\n\n // Constructor\n public Screener ()\n {\n // Layout\n this.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );\n this.setPreferredSize( new Dimension( 600 , 200 ) );\n this.setLayout( new BorderLayout() );\n\n // Widgets\n JTextArea report = new JTextArea( "report goes here" );\n report.setLineWrap( true );\n report.setWrapStyleWord( true );\n\n JButton update = new JButton( "Update screen info" );\n update.addActionListener( ( ActionEvent e ) -> report.setText( reportScreenInfo() ) );\n\n // Arrange\n this.add( report , BorderLayout.CENTER );\n this.add( update , BorderLayout.PAGE_END );\n this.pack();\n }\n\n private String reportScreenInfo ()\n {\n List < String > reportItems = new ArrayList <>();\n\n GraphicsDevice[] deviceList = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();\n for ( GraphicsDevice graphicsDevice : deviceList )\n {\n reportItems.add( "graphicsDevice ID: " + graphicsDevice.getIDstring() );\n GraphicsConfiguration[] graphicsConfigurations = graphicsDevice.getConfigurations();\n for ( GraphicsConfiguration gc : graphicsConfigurations )\n {\n reportItems.add( "bounds: " + gc.getBounds() );\n }\n }\n\n String result = String.join( System.lineSeparator() , reportItems );\n return result;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
571 次 |
| 最近记录: |