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

时间:2015-12-08 06:32:07

标签: java swing intellij-idea hdpi

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

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

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

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

2 个答案:

答案 0 :(得分:7)

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

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

基本上,它扫描UIManager s 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);
        }
    }

}

Font Scaling

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

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

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

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

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

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

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<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。在答案中链接了一个额外的库,您需要将其用于此工作

答案 1 :(得分:0)

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

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

在JFrame中覆盖绘制方法,并使用getGraphics()进行一些逻辑(需要调查),确保在绘制代码之前在图形上调用setScale(2,2)方法,它将使所有内容成为可能画出四倍大。

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

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