2

Please see the SSCCE below:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;


@SuppressWarnings("serial")
public class GlueTest extends JComponent {

    private JFrame frame;
    private JToolBar toolbar;
    private JLabel label_1;
    private JTextField textField_1;
    private JLabel label_2;
    private JTextField textField_2;

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Throwable e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    GlueTest window = new GlueTest();
                    window.frame.setVisible(true);
                    window.frame.requestFocusInWindow();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public GlueTest() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame("Test");
        frame.setBounds(0,0,800,600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        toolbar = new JToolBar();
        toolbar.setFloatable(false);
        toolbar.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        toolbar.setMaximumSize(new Dimension(frame.getWidth(), frame.getHeight()));
        frame.getContentPane().add(toolbar, BorderLayout.NORTH);

        Component horizontalGlue = Box.createHorizontalGlue();
        toolbar.add(horizontalGlue);

        label_1 = new JLabel(" 1 ");
        toolbar.add(label_1);

        textField_1 = new JTextField();
        textField_1.setColumns(9);
        textField_1.setMaximumSize(textField_1.getPreferredSize());
        toolbar.add(textField_1);

        label_2 = new JLabel(" 2 ");
        toolbar.add(label_2);

        textField_2 = new JTextField();
        textField_2.setColumns(9);
        textField_2.setMaximumSize(textField_2.getPreferredSize());
        toolbar.add(textField_2);
    }
}

Notice I am using "system" look and feel. In Windows 7, it displays perfectly. The textfields size automatically to their maximum size, and the horizontal glue to their left grows as much as it can, forcing them to be right aligned.

enter image description here

However, in Linux (Ubuntu 12.04 if it matters), it ends up way different. The textfields scroll right off the frame! The horizontal glue sizes itself too large.

enter image description here

I've tried several other different ways to get it to display properly in both, with no luck. In fact, the only way I can get it to display properly in Linux is to remove all the stylings of the textfield (max width, columns, etc), and then it succeeds in not scrolling off the frame, but it is useless since it has only a few pixels of width.

As a sidenote, I haven't even got a chance to try on a Mac OS, but I'd be curious how that turns out.

The111
  • 5,757
  • 4
  • 39
  • 55
  • What happens if you do not use the `system` look and feel? – Jean Hominal Mar 18 '13 at 08:18
  • @JeanHominal Good question. Just tried it out with `Metal` look and feel, and it works fine on Linux. – The111 Mar 18 '13 at 08:21
  • Instead of `frame.setBounds(0,0,800,600);` call `frame.pack()` at the end of adding components. Also remove `toolbar.setMaximumSize(new Dimension(frame.getWidth(), frame.getHeight()));`. Does the GUI appear as you expect on *nix? – Andrew Thompson Mar 18 '13 at 08:38
  • @AndrewThompson Thanks for the suggestion. Unfortunately the problem still persists with your changes, as long as I use `system` look and feel. – The111 Mar 18 '13 at 08:43
  • 1
    `Strange to find such a bad bug in Java box layout.` Maybe the Linux system LAF doesn't use a BoxLayout. Try setting the layout manually to a BoxLayout. Or try the same layout out on a regular panel added to the frame. – camickr Mar 18 '13 at 15:38
  • @camickr I think you have solved it! Default toolbar layout on windows is `javax.swing.JToolBar$DefaultToolBarLayout`... but on Linux it is `javax.swing.plaf.synth.SynthToolBarUI$SynthToolBarLayoutManager`. Forcing it to explicit `BoxLayout` causes it to work in both OS's. Post answer and I will accept. :-) – The111 Mar 18 '13 at 17:29
  • 1
    @camickr is right; I see a custom layout in OpenJDK. For reference, your original `GlueTest ` looks fine on Mac OS X, Java 6, which defaults to `BoxLayout`. – trashgod Mar 18 '13 at 18:19

2 Answers2

3

As an alternative, consider changing the JToolBar layout to FlowLayout.RIGHT.

Ubuntu screenshot

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.border.EtchedBorder;

public class Test extends JComponent {

    public Test() {
        JToolBar toolbar = new JToolBar();
        toolbar.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        toolbar.setLayout(new FlowLayout(FlowLayout.RIGHT));
        toolbar.add(new JLabel("1"));
        toolbar.add(new JTextField(9));
        toolbar.add(new JLabel("2"));
        toolbar.add(new JTextField(9));

        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(toolbar, BorderLayout.NORTH);
        frame.add(new JTextArea(10, 40));
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                Test window = new Test();
            }
        });
    }
}
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • simplest as is possible, please did OPs code caused the same issue on your enviroment too – mKorbel Mar 18 '13 at 17:21
  • Thanks Trash, that is a nice idea, unfortunately my SSCCE is a bit _too_ simple as it obscures the fact that my real app has left-aligned buttons also, hence the horizontal glue. @camickr just found the real issue I think, in the comments under the OP above. – The111 Mar 18 '13 at 17:30
  • Yes, but I (carelessly) assumed a default `BoxLayout`. – trashgod Mar 18 '13 at 17:31
  • Yeah, I think the real lesson for me here is never assume a layout manager for a component... always set it yourself. Setting my toolbar to the layout I wanted (rather than just being happy that on Windows it seemed to have it already) would have saved me a lot of headache. – The111 Mar 18 '13 at 17:57
2

question (not ***nix user), do you have the same issue with this code

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.border.EtchedBorder;

@SuppressWarnings("serial")
public class GlueTest extends JComponent {

    private JFrame frame;
    private JToolBar toolbar;
    private JLabel label_1;
    private JTextField textField_1;
    private JLabel label_2;
    private JTextField textField_2;

    public GlueTest() {
        toolbar = new JToolBar();
        toolbar.setFloatable(false);
        toolbar.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        toolbar.setAlignmentY(TOP_ALIGNMENT);
        toolbar.add(Box.createHorizontalGlue());

        label_1 = new JLabel(" 1 ");        
        toolbar.add(label_1);
        toolbar.add(Box.createRigidArea(new Dimension(10,1)));

        textField_1 = new JTextField();
        textField_1.setColumns(9);
        textField_1.setMaximumSize(textField_1.getPreferredSize());
        toolbar.add(textField_1);
        toolbar.add(Box.createHorizontalStrut(10));

        label_2 = new JLabel(" 2 ");
        toolbar.add(label_2);
        toolbar.add(Box.createRigidArea(new Dimension(10,1)));

        textField_2 = new JTextField();
        textField_2.setColumns(9);
        textField_2.setMaximumSize(textField_2.getPreferredSize());
        toolbar.add(textField_2);
        toolbar.add(Box.createHorizontalStrut(10));

        frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(toolbar, BorderLayout.NORTH);
        frame.add(new JTextArea(10, 40));
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GlueTest window = new GlueTest();
            }
        });
    }
}

switch the built_in BoxLayout to BorderLayout

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.border.EtchedBorder;

@SuppressWarnings("serial")
public class GlueTest extends JComponent {

    private JFrame frame;
    private JToolBar toolbar;
    private JLabel label_1;
    private JTextField textField_1;
    private JLabel label_2;
    private JTextField textField_2;

    public GlueTest() {
        toolbar = new JToolBar();
        toolbar.setFloatable(false);
        toolbar.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        toolbar.setLayout(new BorderLayout(10, 10)); 
        JPanel panel = new JPanel();
        panel.setOpaque(false);
        label_1 = new JLabel("1");        
        panel.add(label_1);
        textField_1 = new JTextField();
        textField_1.setColumns(9);
        panel.add(textField_1);
        label_2 = new JLabel("2");
        panel.add(label_2);
        textField_2 = new JTextField();
        textField_2.setColumns(9);
        panel.add(textField_2);
        toolbar.add(panel, BorderLayout.EAST);
        frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(toolbar, BorderLayout.NORTH);
        frame.add(new JTextArea(10, 40));
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                GlueTest window = new GlueTest();
            }
        });
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Yup, same issue. And as with my version, it only exists when using `system` look and feel. – The111 Mar 18 '13 at 09:31
  • then there must be some issue with built_in BoxLayout, change this Layout to BorderLayout, will edit this post – mKorbel Mar 18 '13 at 09:35
  • Thanks. I'm headed to bed but a quick test run of your code seems like it does the trick. Upvote for now, will play around more extensively tomorrow and accept the answer if I find no more issues with it. :-) Strange to find such a bad bug in Java box layout. – The111 Mar 18 '13 at 09:47
  • @The11: Also consider changing the layout of the `JToolBar` itself, as shown [here](http://stackoverflow.com/a/15482680/230513). – trashgod Mar 18 '13 at 17:12
  • @mKorbel Check comments under OP, the problem was related indeed to toolbar layout as you discovered, but I don't think going so far as border layout is required. Explicitly setting BoxLayout apparently does the trick, and is closer to my original intent. – The111 Mar 18 '13 at 17:33
  • @The111 can or couldn't be, because otherwise you aren't able to place another JComponent to the left side too, depends of your requirements, I nice to see real issue commented by (@camickr) – mKorbel Mar 18 '13 at 17:37