0

I have 2 buttons, one named btnShort and one named btnLong. I'd like them to be of the same width, so what would be the best option?

enter image description here

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class TestCode2 {

public static void main(String[] args) {

    JFrame window = new JFrame("Test2");
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.setSize(400, 200);

    // ---------------------------------------------------------------------

    GridBagLayout layout = new GridBagLayout();
    GridBagConstraints constraints = new GridBagConstraints();

    JPanel container = new JPanel(layout);
    window.add(container);

    constraints.gridy = 0;

    JButton btnShort = new JButton("Short");
    layout.setConstraints(btnShort, constraints);
    container.add(btnShort);

    constraints.gridy = 1;

    JButton btnLong = new JButton("That's a long button");
    layout.setConstraints(btnLong, constraints);
    container.add(btnLong);

    //This one won't work because button dimension is not known yet...
    //btnShort.setPreferredSize(new Dimension(btnLong.getWidth(), btnLong.getHeight()));

    // ---------------------------------------------------------------------

    window.setVisible(true);
}

}

2 Answers2

3

Set the GridBagConstraints fill property to GridBagConstraints.HORIZONTAL so that both JButton components occupy equal width in the container

constraints.fill = GridBagConstraints.HORIZONTAL;
Reimeus
  • 158,255
  • 15
  • 216
  • 276
  • Thank you for this answer, but it's not very satisfying as the longest button will have it's size changed too - my goal was only to change the width of the short one. – Matei Focseneanu Jul 05 '13 at 10:09
  • In that case you will have to additionally override getPreferredSize for the long button to get the size you want. See update – Reimeus Jul 05 '13 at 10:45
  • @MateiFocseneanu Using GridBagConstarints.HORIZONTAL won't change the size of the largest component in that column, but will cause all components to fill the column – MadProgrammer Jul 05 '13 at 11:14
  • @MadProgrammer You must be kidding: it **will change its size**, not only, but the size will change! Anyway it's not the expected behaviour! – Matei Focseneanu Jul 08 '13 at 07:14
  • @Rimeus I don't see any code that allows me to set the width of the **short button**, not the long one! – Matei Focseneanu Jul 08 '13 at 07:17
  • @MateiFocseneanu Yes, fill HORIZONTAL will change the size of all the components in the specified column to meet the width of the column (which will be the widest component in that column), which is, from what I understand, is what you want – MadProgrammer Jul 08 '13 at 07:17
  • @MateiFocseneanu As an example of what I'm talking about, see the example I provided easier. The size of the widest component hasn't changed, but the shorter one has changed to match its width – MadProgrammer Jul 08 '13 at 07:28
  • @MadProgrammer Yes, sorry! I realized the widthest button will give the size of the rest. But I still find this a bit lame. Need to check the rest... – Matei Focseneanu Jul 08 '13 at 10:17
1

Make use of an appropriate layout manager, like GridBagLayout and it's constraints...

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Buttons {

    public static void main(String[] args) {
        new Buttons();
    }

    public Buttons() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                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 {

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            add(new JButton("I'm a very long button"), gbc);
            add(new JButton("I'm not"), gbc);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }
    }    
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Well, that's complicated. I Don't see the reason of invoking the new ´Run()´ method - it works without, but I don't get why the buttons look different in that case!!! – Matei Focseneanu Jul 08 '13 at 10:23
  • The reason for the invokeLater is explained in [Inital Threads](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html). If you supply a weightX constraint, this will change the size of all the components for the column to occupy the amount of space specified. This example just uses the fill HORIZONTAL constraint to request that all the components within the column fill the column – MadProgrammer Jul 08 '13 at 20:39
  • Sorry but I still don't get **why** you used `invokeLater()`? As I told, everything works fine without, but has different aspect (another thing that I don't understand) – Matei Focseneanu Jul 09 '13 at 08:22
  • Assuming you read the linked article, all interactions with Swing MUST be done from with in the context on the EDT, when your application starts, it's not running in side the EDT, this ensures that the UI is initialized within the correct thread context – MadProgrammer Jul 09 '13 at 09:06
  • Hi thank you for your explanation, but honestly I don't get exactly what you're saying (and yes, I read the linked article, although I don't see what you mean by EDT)... I mean, I don't see any concrete reason why I can't do without, as I said sooner: it actually **works**, even if fonts and sizes are slightly different, which I still don't understand why!!! – Matei Focseneanu Jul 09 '13 at 10:06
  • Swing is a single threaded framework, see [this](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) & [this](https://weblogs.java.net/blog/cayhorstmann/archive/2007/06/the_single_thre.html) & [this](http://bitguru.wordpress.com/2007/03/21/will-the-real-swing-single-threading-rule-please-stand-up/). Will it make a differnece to your code (as it is), there's a possibility, but when it does, you will spend so long looking for it, it will drive you crazy – MadProgrammer Jul 09 '13 at 11:13
  • Well all this looks very interesting, I've read all the stuff you provided, **but**, could you please answer, if you can/want to these basic questions: **1.** Why fonts/sizes are not the same between the two methods? **2.** How can I find a simple way of testing that shows using standard way is actually wrong? I mean it is said to be wrong, but it's hard to understand how/why without a concrete example. – Matei Focseneanu Jul 10 '13 at 09:04
  • And I really think all this is **totally crazy**, I mean having to deal with multithreading issues as I'm just trying to write super simple code is really surprising. And the worst is that is all this infomation is hidden, I mean so many example exists and no tracks of this issue, and questions still exist, for example [here](https://weblogs.java.net/blog/cayhorstmann/archive/2007/06/the_single_thre.html) – Matei Focseneanu Jul 10 '13 at 09:08
  • Any UI toolkit will have similar restrictions, Java juts doesn't make any assumptions about how you might start your application. I think the proposed application framework might have had a method an entry point that was thread safe, but since our applications start with main, we have to deal with it ourselves. As to the fonts, I'm not sure what you mean. The difference between my example and yours is I'm using the System look and feel, your using the default, these have different fonts, this is why you should avid using setPreferredSize ;) – MadProgrammer Jul 10 '13 at 11:09
  • Hi and thanx for explaining **1.**, I'm sorry because it's in fact pretty obvious now, I should have understood before. Now, looks like **2.** is much more difficult to do, I still didn't find any way of showing what difference it is between the 2 approaches... – Matei Focseneanu Jul 11 '13 at 08:09
  • The problem, generally, is it will always be difficult if you are not trying to use multiple threads to simultaneously update the UI. When moving from Java 6 to 7 the application I'm working stopped because the previously developer didn't understand this basic rule and we hit a dead lock with the EDT. Swing components are not thread safe, they are not designed to be updated by multiple threads. You can check this by calling `EventQueue.isDispatchingThread`, which will return false if you do so from `main` directly. – MadProgrammer Jul 11 '13 at 08:18
  • The problem tends to be suitable, deadlocks here and there, unexplained paint artifacts, race conditions (the UI not begin updated with the value your expected), that sort of thing. Proofing it one way or another wouldn't be easy. This basic conscientious is that all interactions with the UI should be done from within the EDT. This is especially important when dealing with cross platform applications, as the implementation of the EDT (at a native level) will vary. – MadProgrammer Jul 11 '13 at 08:21
  • Well OK, thank you for your explanations, this seems pretty important to know and should be used from the very start, in order to avoid way bigger problems afterwards. But hey, that's a really important thing and I still can't unserstand why the hell this is not very well documented, and seems to be marginal stuff - but it's not! (probably the problems you had with your previous developper has something to do with the lack of documentation about that sensitive subject) – Matei Focseneanu Jul 11 '13 at 09:51