question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Extra-length combo-box popup sizing and positioning in multi-screen environment

See original GitHub issue

FlatScreenInfo

Scale factors:  125% / 150%
Java version:   11.0.7

ID:      \Display0 (main)
Size:    1920 x 1080 / 32 Bit / 60 Hz
Bounds:  1536 x 864 / x 0 / y 0   (scale -1.25)
Insets:  left 0 / right 0 / top 0 / bottom 50
Scale:   1.25

ID:      \Display1
Size:    1920 x 1080 / 32 Bit / 60 Hz
Bounds:  1280 x 720 / x -1280 / y -50   (scale -1.5)
Insets:  left 0 / right 0 / top 0 / bottom 0
Scale:   1.5

Using the following sample program:

//package ;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.GraphicsConfiguration;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.MetalTheme;

@SuppressWarnings("serial")
public class ComboBoxTest extends JFrame {

    private Container mainPane;
    private JLabel scaleLabel;

    public ComboBoxTest() {
        super("Combo-box test");
        add(initMainPanel(), BorderLayout.CENTER);
        add(initStatusBar(), BorderLayout.PAGE_END);
    }

    private Container initMainPanel() {
        JComboBox<String> history = new JComboBox<>();
        history.addItem(randomItem(50));
        history.addItem(randomItem(500));
        history.addItem(randomItem(100));

        JComponent main = new JPanel(new BorderLayout());
        main.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        main.add(history, BorderLayout.PAGE_START);
        mainPane = main;
        return main;
    }

    private static String randomItem(int maxLength) {
        StringBuilder buf = new StringBuilder(maxLength + 10);
        buf.append(randomWord());
        while (buf.length() < maxLength) {
            buf.append(' ').append(randomWord());
        }
        return buf.toString();
    }

    private static String randomWord() {
        final int length = (int) (Math.random() * 5 + 5);
        StringBuilder buf = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            buf.append((char) (Math.random() * 26 + 'a'));
        }
        return buf.toString();
    }

    private Component initStatusBar() {
        LookAndFeel lnf = UIManager.getLookAndFeel();
        String lnfLabel = "Look and Feel: " + lnf.getName();
        if (lnf instanceof MetalLookAndFeel) {
            lnfLabel += " / " + MetalLookAndFeel.getCurrentTheme().getName();
        }

        scaleLabel = new JLabel();
        updateScaleLabel();
        addPropertyChangeListener("graphicsConfiguration", evt -> updateScaleLabel());

        JComponent status = Box.createHorizontalBox();
        status.add(new JLabel(lnfLabel));
        status.add(new JLabel(", "));
        status.add(scaleLabel);
        status.add(Box.createHorizontalGlue());
        return status;
    }

    void updateScaleLabel() {
        GraphicsConfiguration gc = getGraphicsConfiguration();
        if (gc == null) {
            scaleLabel.setText("Scale: ?");
        } else {
            AffineTransform defaultTransform = gc.getDefaultTransform();
            Set<Double> factors = new LinkedHashSet<>(1);
            factors.add(defaultTransform.getScaleX());
            factors.add(defaultTransform.getScaleY());
            scaleLabel.setText("Scale: " + factors);
        }
    }

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(() -> {
            setLookAndFeel(args.length > 0 ? args[0] : null);

            ComboBoxTest frame = new ComboBoxTest();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setSize(frame.getFont().getSize() * 50, frame.getHeight());
            frame.setLocation(new Point(0, 0));
            frame.mainPane.requestFocusInWindow();
            frame.setVisible(true);
        });
    }

    static void setLookAndFeel(String param) {
        if (param == null)
            return;

        String lnfClassName, themeClassName;
        switch (param.toLowerCase()) {
        case "ocean":
            lnfClassName = "javax.swing.plaf.metal.MetalLookAndFeel";
            themeClassName = "javax.swing.plaf.metal.OceanTheme";
            break;
        case "steel":
            lnfClassName = "javax.swing.plaf.metal.MetalLookAndFeel";
            themeClassName = "javax.swing.plaf.metal.DefaultMetalTheme";
            break;
        case "nimbus":
            lnfClassName = "javax.swing.plaf.nimbus.NimbusLookAndFeel";
            themeClassName = null;
            break;
        case "flatlaf":
            lnfClassName = "com.formdev.flatlaf.FlatLightLaf";
            themeClassName = null;
            break;
        case "plastic":
            lnfClassName = "com.jgoodies.looks.plastic.Plastic3DLookAndFeel";
            themeClassName = "com.jgoodies.looks.plastic.theme.SkyBluer";
            break;
        case "system":
            lnfClassName = UIManager.getSystemLookAndFeelClassName();
            themeClassName = null;
            break;
        case "default":
            lnfClassName = UIManager.getCrossPlatformLookAndFeelClassName();
            themeClassName = null;
            break;
        default:
            return;
        }

        try {
            if (themeClassName != null) {
                MetalLookAndFeel.setCurrentTheme((MetalTheme) Class
                        .forName(themeClassName).getConstructor().newInstance());
            }
            UIManager.setLookAndFeel(lnfClassName);
        } catch (LinkageError | ReflectiveOperationException | UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
    }

}
java -cp flatlaf-0.42.jar ComboBoxTest.java flatlaf

Moving the application window to the left (secondary) monitor, then opening the combo-box popup – the popup is misaligned, using the resolution/scaling of the right (main) monitor and extends across the right monitor end:

extra-lenght-combo-option

In my opinion, the popup should not extend across monitors.

Not sure if it is related, I’m noticing – without the extra-length item:

        history.addItem(randomItem(50));
        history.addItem(randomItem(75));
        history.addItem(randomItem(100));

when moving the application window between monitors (<kbd>Win+Shift+Left/Right-Arrow</kbd>), the first time the combo popup is opened it is shown at a weird position:

just-moved-to-screen

The second time the popup is opened it is aligned/positioned as expected.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5

github_iconTop GitHub Comments

1reaction
DevCharlycommented, Oct 5, 2020

If the taskbar/dock is at the bottom, Swing changes the location of combobox popup so that the popup never overlaps the taskbar/dock. So I think it should also not overlap the taskbar/dock if it is on the right or left side.

0reactions
staniocommented, Oct 5, 2020

Thank you. I saw the change and wondered if screen insets should be considered (as is currently) for a popup. Maybe it is o.k. as the insets might be occupied by an always-on-top window which might show even on top of the popup.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JavaFX ComboBox: Pop-up is getting shifted when screen is ...
My primary screen is FHD and secondary is 2K. So if I set the 2K monitor as primary the combobox is popping up...
Read more >
Combobox changing size when popup open #4551 - GitHub
Describe the bug Hi, The ComboBox loses value and changes a width when the popup was opened. Please, take a look at the...
Read more >
How to Use the Multi-Display Function on Windows 10 - Eizo
In the “System > Display” menu the screen position, display size (enlargement ratio), display orientation, display method of the multi-display, and main/sub ...
Read more >
Wrong popup position on dual screen in Linux : JBR-3388
Arranging the relative positions of the 2 monitors in settings makes a difference, so I managed to get a decent balance of popup...
Read more >
keeping popups on a single monitor in a dual ... - QuickBooks
Open your QuickBooks Desktop. Once the pop up screen comes up, move & drag it to the main monitor. At the top menu...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found