1

I am trying to create a small swing application using Zulu JDK 11. In the bottom right part of it I am having an image (logo). My problem is that the logo is displayed poorly when the user changes the scaling to a value greater than 100% (125%, 150%, 175% etc.)

Here is my source code.

Main class:

public class Main {

public static void main(String[] args) {
    FrameServer frameServer = new FrameServer();
    frameServer.setVisible(true);
}}

FrameServer class:

public class FrameServer extends JFrame {

private JPanel contentPane;
private JPanel centerPane = new JPanel();
private JPanel southPane = new JPanel();
private JPanel rightPane = new JPanel();
private JButton btnOK = new JButton("OK");
private JTabbedPane jTabbedPane1 = new JTabbedPane();
private Tab1 tab1Page = new Tab1();
private Tab2 tab2Page = new Tab2();

public FrameServer() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    jbInit();
    pack();
    centerFrame();
    this.repaint();
}

private void jbInit() {
    setTitle("Test Scaling App");
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(new BorderLayout());
    centerPane.setLayout(new BorderLayout());
    centerPane.add(jTabbedPane1, BorderLayout.CENTER);
    southPane.setLayout(new BorderLayout());
    rightPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 5, 5));
    rightPane.add(btnOK);

    CustomStatusBar statusBar = new CustomStatusBar();
    southPane.add(statusBar, BorderLayout.CENTER);
    southPane.add(rightPane, BorderLayout.EAST);
    jTabbedPane1.addTab("Tab 1", tab1Page);
    jTabbedPane1.addTab("Tab 2", tab2Page);

    contentPane.add(centerPane, BorderLayout.CENTER);
    contentPane.add(southPane, BorderLayout.SOUTH);
}

private void centerFrame() {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = this.getSize();
    if (frameSize.height > screenSize.height) {
        frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
        frameSize.width = screenSize.width;
    }
    this.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
}

class Tab2 extends JScrollPane {
    public Tab2() {
        super(new JTextArea(10, 60));
        super.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        super.getViewport().setPreferredSize(new Dimension(500, 300));
    }

}

class Tab1 extends JPanel {
    public Tab1() {
        contentPane = this;
        JScrollPane centerScrollPane = new JScrollPane(new JTable());
        centerScrollPane.getViewport().setBackground(Color.white);
        JPanel eastPane = new JPanel();
        eastPane.setLayout(new FlowLayout());
        JPanel topPane = new JPanel();
        topPane.setLayout(new BoxLayout(topPane, BoxLayout.Y_AXIS));
        eastPane.add(topPane, FlowLayout.LEFT);
        contentPane.setLayout(new BorderLayout());
        contentPane.add(centerScrollPane, BorderLayout.CENTER);
        contentPane.add(eastPane, BorderLayout.EAST);
    }
}

class CustomStatusBar extends JPanel {
    JLabel label0 = new JLabel("", SwingConstants.CENTER);
    JLabel label1 = new JLabel();
    JLabel label2 = new JLabel();
    JLabel label3 = new JLabel("", SwingConstants.CENTER);
    JLabel labelLogo = new JLabel();
    private static final int HEIGHT = 21;

    public CustomStatusBar() {
        setCommonFeatures(label0, 40, "Stuff 0");
        setCommonFeatures(label1, 120, "Stuff 1");
        setCommonFeatures(label2, 120, "Stuff 2");
        setCommonFeatures(label3, 90, "Stuff 3");

        labelLogo.setFont(new java.awt.Font("Dialog", 3, 12));
        labelLogo.setForeground(Color.black);
        labelLogo.setBorder(BorderFactory.createLoweredBevelBorder());
        ImageIcon image = new ImageIcon("small.png");
        labelLogo.setIcon(image);

        labelLogo.setPreferredSize(new Dimension(40, HEIGHT));
        labelLogo.setHorizontalAlignment(SwingConstants.CENTER);

        setLayout(new GridBagLayout());
        setMaximumSize(new Dimension(800, 40));
        add(label0, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label1, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label2, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(label3, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));
        add(labelLogo, new GridBagConstraints(4, 0, GridBagConstraints.REMAINDER, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 50, 0));

    }

    private void setCommonFeatures(JLabel label, int width, String msg) {
        label.setBackground(UIManager.getColor("ScrollBar.track"));
        label.setForeground(Color.black);
        label.setBorder(BorderFactory.createLoweredBevelBorder());
        label.setPreferredSize(new Dimension(width, HEIGHT));
        label.setText(" " + msg);
    }
}}

Small.png image file: Description

When opened at scaling 100%, it looks good: enter image description here

But when changing the scaling to 175%: enter image description here the pixels start to show up (open link to the picture to see better)

Now, what I have done is to replace the logo with one with a higher resolution: enter image description here Now, I am struck as I do not know how to make it fit in the space available for it and display properly when scaled. If i redimension the image from the java code as seen here, it will display properly for 100%, but for 175% scaling the pixels become visible again, like using the small.png file.

Which is the correct way of solving this? Thank you.

actunderdc
  • 1,448
  • 2
  • 11
  • 20
  • See: https://stackoverflow.com/a/46992806/131872. Check out the `StretchIcon` which will dynamically scale based on the space available to the lablel. – camickr Mar 18 '20 at 13:51
  • Tried that, unfortunately it gets rendered blurry even on 100% scaling setting :( – actunderdc Mar 18 '20 at 14:06
  • Maybe try: 1) making the image smaller. That is it should only be 2 times the regular size since scaling will only be up to 175%. 2) maybe make the background transparent instead of white. 3) use anti aliasing when creating the image. – camickr Mar 18 '20 at 14:20
  • Unfortunately, that did not work either... – actunderdc Mar 19 '20 at 09:37
  • 1
    The builtin downscaling algorithm isn't very good, especially for content like your logo. We use something like https://github.com/martinheidegger/java-image-scaling/blob/master/src/main/java/com/mortennobel/imagescaling/ResampleOp.java instead. But it's still preferable to use an Icon implementation supporting multiple images and selecting the closest. You can get the scaling factors via casting the `Graphics` to `Graphics2D` and `AffineTransform currTrans = g2d.getTransform(); double scaleX = currTrans.getScaleX(), scaleY = currTrans.getScaleY();` – Holger Mar 20 '20 at 10:54

1 Answers1

0

The workaround is the following (only tested on Windows 10):

  1. Locate the javaw.exe that the application is using (it very important to apply the following to javaw.exe, not java.exe)
  2. Right click -> Properties -> Compatibility tab
  3. Click button Change high DPI settings
  4. Check Override high DPI scaling behavior. Scaling performed by: Select System in the combobox.
  5. Press OK twice and restart the application
actunderdc
  • 1,448
  • 2
  • 11
  • 20