Aplicación Java swing demasiado pequeña en ~ HiDpi ~ computadoras

Tengo una aplicación de escritorio java que usa java swing y funciona bien con pantallas normales.

Pero cuando se trata de ~ hiDpi ~ displays (3200 * 1800) toda la aplicación es demasiado pequeña.

Como el código de la aplicación es muy grande y complejo, es difícil reorganizar el código para que coincida con los ppp de alta resolución. ¿Hay una solución a este problema?

He visto aplicaciones como IntelliJ idea y eclipse que funcionan bien con este tipo de pantallas sin ningún problema. Aprecia cualquier ayuda.

Hace algún tiempo, tuve la tarea de desarrollar una solución que permitiera a un usuario boost o disminuir el tamaño de la fuente de la aplicación de forma dinámica. Huelga decir que pasé mucho tiempo arrancándome el pelo (sobre todo porque mi predecesor setPreferredSize instantáneamente setPreferredSize y otras ideas estúpidas que dificultaban cualquier solución)

El siguiente es un ejemplo de la idea que se me ocurrió. Le permite modificar las UIManager “fuente” del UIManager , aplicando una escala al tamaño de fuente.

Básicamente, escanea los UIManager UIDefaults , seleccionando todos los atributos basados ​​en “fonts” y los almacena como una “base”. Una vez hecho esto, utiliza estos valores, calcula el tamaño de fuente, según la escala y el tamaño original, y actualiza los valores en el 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); } } } 

Escala de fuente

El ejemplo está tomando de los tutoriales Swing, con la adición de la escala de la fuente

Básicamente, cuando se hace clic en el botón + , se está ejecutando este código …

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

La idea básica sería definir un algoritmo de escalado, basado en la resolución de pantalla “predeterminada” 1 y, a medida que aumenta la resolución / DPI de la pantalla, puede boost la escala de la fuente para seguir.

Hay problemas con esto Puede que no funcione con la apariencia (mirando su nimbo) y si define sus propias fonts no se actualizarán. También es una gran forma de ver cuándo has hecho cosas estúpidas con la API, ya que hará esgulps en tus diseños.

La otra solución sería usar JXLayer / JLayer para escalar dinámicamente la UI como un todo.

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

Esto se basa en la idea presentada aquí . Hay una biblioteca adicional vinculada en la respuesta que necesitará para que esto funcione

No tengo una solución lista, pero:

Si sus elementos están en un JPanel en JFrame (forma estándar), escriba su propio Administrador de diseño, que escala este Jpanel raíz a 1/4 del tamaño de JFrame y haga que el JFrame sea más grande cuatro veces (ancho x 2, longitud x 2).

Anule los métodos de pintura en JFrame, y cierta lógica con getGraphics () (necesita investigar eso), asegúrese de que el método setScale (2,2) se invoque en los gráficos antes de que se le dé al código de dibujo, hará que todo dibuje cuatro veces más grande.

Usa java.awt.EventQueue, escribe tu propia EventQueue que verificará todos los eventos del mouse, y los traduce para que sean 1/4 de la posición original en la ventana (x / 2, y / 2), luego déjalos ir, deben disparar eventos en elementos apropiados.

La idea es dejar que los componentes permanezcan en su tamaño original (virtualmente), pero escalar el código de dibujo y los eventos del mouse, por lo que debe verse y funcionar de la misma manera que en pantallas de menor resolución.