Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
stanio opened this issue Oct 4, 2020 · 5 comments
Labels
multi-screen Related to using multiple screens
Milestone

Comments

@stanio
Copy link

stanio commented Oct 4, 2020

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 (Win+Shift+Left/Right-Arrow), 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.

@DevCharly
Copy link
Collaborator

Ups, never tried that wide popups 😄

Limiting the maximum width of the popup to the screen width is a good idea 👍

Regarding the second issue: are you sure that you used FlatLaf 0.42?
That issue should be fixed in 0.42 with commit ef4c467 (issue #166).
I can reproduce it with 0.41, but not with 0.42...

@stanio
Copy link
Author

stanio commented Oct 4, 2020

Regarding the second issue: are you sure that you used FlatLaf 0.42?
That issue should be fixed in 0.42 with commit ef4c467 (issue #166).
I can reproduce it with 0.41, but not with 0.42...

Ah, right – I was trying with 0.41 in that setup. Using 0.42 it appears just fine.

@DevCharly
Copy link
Collaborator

fixed in master branch

@DevCharly DevCharly added this to the 0.43 milestone Oct 4, 2020
@DevCharly DevCharly added the multi-screen Related to using multiple screens label Oct 5, 2020
@stanio
Copy link
Author

stanio commented 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.

@DevCharly
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
multi-screen Related to using multiple screens
Projects
None yet
Development

No branches or pull requests

2 participants