Java摆动应用程序在~HiDpi~计算机中太小了

我有一个使用java swing的java桌面应用程序,它可以正常显示。

但是当来到~hiDpi~显示器(3200 * 1800)时整个应用程序太小了。

由于应用程序代码非常庞大且复杂,因此很难重新排列代码以与hi dpi匹配。 这个问题有解决方案吗?

我已经看到像IntelliJ这样的应用程序, eclipse可以很好地处理这种显示而没有问题。 感谢任何帮助。

前段时间,我的任务是开发一个允许用户动态增加或减少应用程序字体大小的解决方案。 毋庸置疑,我花了很多时间撕掉我的头发(主要是因为我的前任立即使用setPreferredSize和其他愚蠢的想法,这使得任何解决方案都难以实现)

以下是我提出的想法的一个例子。 它允许您修改UIManager的“字体”属性,将缩放应用于字体大小。

基本上,它扫描UIManagerUIDefaults ,挑选出所有基于“字体”的属性并将它们存储为“基础”。 完成后,它会使用这些值,根据比例和原始大小计算字体大小,并更新UIManager的值

 import java.awt.Font; import java.util.HashMap; import java.util.Map; import javax.swing.UIManager; import sun.swing.SwingLazyValue; public class FontUtilities { private static Map originals; public static void setFontScale(float scale) { if (originals == null) { originals = new HashMap<>(25); for (Map.Entry entry : UIManager.getDefaults().entrySet()) { Object key = entry.getKey(); if (key.toString().toLowerCase().contains(".font")) { Object value = entry.getValue(); Font font = null; if (value instanceof SwingLazyValue) { SwingLazyValue lazy = (SwingLazyValue) entry.getValue(); value = lazy.createValue(UIManager.getDefaults()); } if (value instanceof Font) { font = (Font) value; originals.put(key.toString(), font); } } } } for (Map.Entry entry : originals.entrySet()) { String key = entry.getKey(); Font font = entry.getValue(); float size = font.getSize(); size *= scale; font = font.deriveFont(Font.PLAIN, size); UIManager.put(key, font); } } } 

字体缩放

这个例子来自Swing教程,增加了字体缩放

基本上,当点击+按钮时,它正在运行此代码……

 scale += 1f; FontUtilities.setFontScale(scale); SwingUtilities.updateComponentTreeUI(TextSamplerDemo.this); updateUI(); revalidate(); repaint(); 

基本思想是定义缩放算法,基于“默认”屏幕分辨率为1 ,随着屏幕分辨率/ DPI的增加,您可以增加字体缩放以遵循。

这有问题。 它可能不适用于外观(看着你的灵气),如果你定义自己的字体,它们将不会被更新。 这也是一个很好的方式,看你何时用api完成了愚蠢的事情,因为它会对你的布局造成严重破坏

另一种解决方案是使用JXLayer / JLayer来动态扩展UI。

JLayer Zooming

 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.RenderingHints; import java.util.HashMap; import java.util.Map; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.jdesktop.jxlayer.JXLayer; import org.pbjar.jxlayer.demo.TransformUtils; import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel; public class TestJLayerZoom { public static void main(String[] args) { new TestJLayerZoom(); } public TestJLayerZoom() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private JXLayer layer; private DefaultTransformModel transformModel; private JPanel content; public TestPane() { content = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridy = 0; JLabel label = new JLabel("Hello"); JTextField field = new JTextField("World", 20); content.add(label, gbc); content.add(field, gbc); gbc.gridy++; gbc.gridwidth = GridBagConstraints.REMAINDER; final JSlider slider = new JSlider(50, 200); slider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { int value = slider.getValue(); double scale = value / 100d; transformModel.setScale(scale); } }); content.add(slider, gbc); transformModel = new DefaultTransformModel(); transformModel.setScaleToPreferredSize(true); Map hints = new HashMap<>(); //hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); //hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); //hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); layer = TransformUtils.createTransformJXLayer(content, transformModel, hints); setLayout(new BorderLayout()); add(layer); } } } 

这是基于这里提出的想法。 在答案中链接了一个额外的库,您需要将其用于此工作

我没有现成的解决方案,但是:

如果您的元素是JFrame中的JPanel(标准方式),请编写自己的布局管理器,将此根Jpanel缩放到JFrame大小的1/4,并使JFrame的大小增加四倍(宽度x 2,长度x 2)。

覆盖JFrame中的绘制方法,以及getGraphics()的一些逻辑(你需要研究一下),确保在给图形代码之前在图形上调用setScale(2,2)方法,它会使所有东西都绘制四次大。

使用java.awt.EventQueue,编写自己的EventQueue,它将代理所有鼠标事件,并将它们转换为窗口中原始位置的1/4(x / 2,y / 2),然后让它们去,它们应该触发关于适当元素的事件。

整个想法是让组件保持其原始大小(虚拟),但缩放绘图代码和鼠标事件,因此它应该看起来和工作方式与低分辨率显示器相同。

    Interesting Posts