Java摆动应用程序在~HiDpi~计算机中太小了 [英] Java swing application too small in ~HiDpi~ computers

查看:111
本文介绍了Java摆动应用程序在~HiDpi~计算机中太小了的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a java desktop application which uses java swing and it works fine with normal displays.

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

But when come to ~hiDpi~ displays( 3200*1800) whole application is too small.

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

As application code is very large and complex, it is difficult to rearrange code to match with hi dpi. Is there a solution to this problem?

我见过像 IntelliJ 这样的应用程序, eclipse 可以正常使用这种显示而没有问题。感谢任何帮助。

I have seen application like IntelliJ idea and eclipse works fine with this kind of displays without a problem. Appreciate any help.

推荐答案

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

Some time ago, I was tasked with developing a solution which would allow a user to increase or decrease the font size of the application dynamically. Needless to say, I spent a lot of time tearing my hair out (mostly because my predecessor was instant on using setPreferredSize and other stupid ideas which made any solution a pain to implement)

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

The following is an example of the idea I came up with. It allows you to modify the UIManagers "font" properties, applying a scale to the font size.

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

Basically, it scans the UIManagers UIDefaults, picking out all the "font" based attributes and stores these as a "base". Once it's done that, it uses these values, calculates the font size, based on the scale and the original size, and updates the values in the 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教程,增加了字体缩放

The example is taking from the Swing tutorials, with the addition of the font scaling

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

Basically, when ever the + button is clicked, it's running this code...

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

基本思路是根据默认屏幕分辨率定义缩放算法 1 并且随着屏幕分辨率/ DPI的增加,您可以增加字体缩放比例。

The basic idea would be to define a scaling algorithm, based on the "default" screen resolution been 1 and as the screen resolution/DPI increases, you can increase the font scaling to follow.

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

There are problems with this. It might not work on look and feels (looking at you nimbus) and if you define your own fonts they won't be updated. It's also a really great way to see when you've done stupid things with the api, as it will play havoc with your layouts

另一种解决方案是使用 JXLayer / JLayer 以动态扩展用户界面。

The other solution would be to use JXLayer/JLayer to dynamically scale the UI as a whole.

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


        }

    }

}

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

This is based on the idea presented here. There is an additional library linked in the answer which you will need to make this work

这篇关于Java摆动应用程序在~HiDpi~计算机中太小了的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆