【问题标题】:Java swing application too small in ~HiDpi~ computersJava swing 应用程序在 ~HiDpi~ 计算机中太小
【发布时间】:2016-03-12 23:50:18
【问题描述】:

我有一个使用 java swing 的 java 桌面应用程序,它在普通显示器上运行良好。

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

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

我见过像 IntelliJ idea 和 eclipse 这样的应用程序在这种显示器上运行良好,没有问题。感谢任何帮助。

【问题讨论】:

  • 我不确定这是否是一个可行的解决方案,但您可以尝试使用JLayer/JXLayer 之类的东西,用于exampleexample

标签: java swing intellij-idea hdpi


【解决方案1】:

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

以下是我提出的想法的示例。它允许您修改UIManagers“字体”属性,对字体大小应用比例。

基本上,它会扫描UIManagers UIDefaults,挑选出所有基于“字体”的属性并将它们存储为“基础”。完成后,它会使用这些值,根据比例和原始大小计算字体大小,并更新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<String, Font> 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<String, Font> 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。

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<JComponent> 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<RenderingHints.Key, Object> 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);


        }

    }

}

这是基于here 提出的想法。答案中链接了一个附加库,您需要使用它来完成这项工作

【讨论】:

【解决方案2】:

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

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

覆盖 JFrame 中的绘画方法,以及一些使用 getGraphics() 的逻辑(您需要对此进行调查),确保在将其提供给绘图代码之前在图形上调用该方法 setScale(2,2),它将使一切画出四倍大。

使用java.awt.EventQueue,编写自己的EventQueue来代理所有鼠标事件,并将它们转换为window(x/2, y/2)中原始位置的1/4,然后放手,他们应该在适当的元素上触发事件。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-30
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多