0

I've tried my best to fix a JLabel's size, but it keeps changing and that causes other items in the GUI to move around.

I have specified both the sizing and the spacing of components. According to GridBagLayout's documentation, ipadx and ipady "Specifies the internal padding: how much to add to the size of the component." According to this post, setMinimumSize and setMaximumSize allows you to the set the actual size of the component. Since I have fixed both the size and the spacing, how is it possible that the components keep jumping around whenever text appears in the JLabel?

I was able to solve this in practice by adding a space into the empty text, but this keeps bugging me. What is it that I don't understand about this?

Here is a SSCCE demonstrating the problem. It has elements arranged in a GridBagLayout and changing the contents of one JLabel in one cell causes all items to move.

import javax.swing.*;
import java.awt.*;
import java.io.*;

public class F {
public static void main(String[] args) throws IOException, InterruptedException {
    JFrame frame = new JFrame();

    JPanel mainView = new JPanel();
    mainView.setPreferredSize(new Dimension(300, 300));
    mainView.setLayout(new GridBagLayout());

    JPanel contents = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.insets = new Insets(1,3,3,3);
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.ipady = 2;
    gbc.anchor = GridBagConstraints.EAST;

    JLabel text1 = new JLabel("Some text: ");
    contents.add(text1, gbc);
    gbc.gridy++;
    JLabel text2 = new JLabel("More text: ");
    contents.add(text2, gbc);
    gbc.gridy++;
    JLabel text3 = new JLabel("Third line: ");
    contents.add(text3, gbc);
    gbc.gridx++;
    gbc.gridy = 0;

    JTextField textField1 = new JTextField(10);
    contents.add(textField1, gbc);
    gbc.gridx++;
    gbc.gridy++;
    gbc.gridx--;

    JTextField textField2 = new JTextField(10);
    contents.add(textField2, gbc);
    gbc.gridy++;

    JLabel sitePass = new JLabel("");
    sitePass.setMaximumSize(new Dimension(100, 15));
    sitePass.setMinimumSize(new Dimension(100, 15));
    //sitePass.setPreferredSize(new Dimension(100, 15)); // <-- this line fixes the problem
    contents.add(sitePass, gbc);

    mainView.add(contents);

    frame.add(mainView);
    frame.setSize(400, 400);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    while (true) {
        Thread.sleep(1000);
        sitePass.setText("Pushup time");
        Thread.sleep(1000);
        sitePass.setText("");
    }
}
}
Community
  • 1
  • 1
Atte Juvonen
  • 4,922
  • 7
  • 46
  • 89
  • Where is your [mcve] ? PS : `setPreferedSize(int)` could help (i put the three `prefered, minimal, maximal` to the same value) to fixed a size – AxelH Jan 19 '17 at 10:21
  • Sorry about the example, I accidentally deleted too much when I was trying to create a minimal example. – Atte Juvonen Jan 19 '17 at 10:23
  • You're right, minimumSize and maximumSize was not enough. Adding preferredSize fixed it. – Atte Juvonen Jan 19 '17 at 10:26
  • 2
    [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) – MadProgrammer Jan 19 '17 at 10:30

3 Answers3

4

One way to solve the problem. Change:

    JLabel sitePass = new JLabel("");

To:

    JTextField sitePass = new JTextField("", 12);
    sitePass.setOpaque(false);
    sitePass.setBorder(null);

Explanation: A JTextField has a default size determined by the number of columns, combined with the font and font size. The two statements following ensure it has the look of a JLabel.

An improvement would be to also make the text field act like a label, which might be something along the lines of:

    sitePass.setEditable(false);
    sitePass.setFocusable(false);
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
1

Swing use the preferredSize for some Layout. Setting it will correct your label.

I am used to fixe a JComponent by setting minimum, maximum and preferred size just to be sure ;)

PS : I will try to add more information about how to use it.

AxelH
  • 14,325
  • 2
  • 25
  • 55
  • 4
    [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?](http://stackoverflow.com/questions/7229226/should-i-avoid-the-use-of-setpreferredmaximumminimumsize-methods-in-java-swi) – MadProgrammer Jan 19 '17 at 10:30
  • @MadProgrammer, thanks for that. Well there is pros and cons in that thread. Will take a closer look to each one. But the accepted answer suggest to use external API (JGoodies) to fill the gap in the Layout provided... – AxelH Jan 19 '17 at 10:36
  • @MadProgrammer, here you can see a drastic usage of these properties in a [demo](http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/HtmlDemoProject/src/components/HtmlDemo.java) from Oracle. – AxelH Jan 19 '17 at 11:16
  • The tutorials are full of "good" ideas which are questionable in real life. Run the code on different systems with different resolutions and font settings and see how long it takes for it to fall apart – MadProgrammer Jan 19 '17 at 18:54
  • @mad Thanks for the info. – AxelH Jan 19 '17 at 19:23
1

There is another way to use a dummy whitespace like JComboBox.

//javax.swing.plaf.basic.BasicComboBoxUI#getDefaultSize()
/**
 * Return the default size of an empty display area of the combo box using
 * the current renderer and font.
 *
 * @return the size of an empty display area
 * @see #getDisplaySize
 */
protected Dimension getDefaultSize() {
  // Calculates the height and width using the default text renderer
  Dimension d = getSizeForComponent(getDefaultListCellRenderer()
    .getListCellRendererComponent(listBox, " ", -1, false, false));
  return new Dimension(d.width, d.height);
}
import java.awt.*;
import java.util.Objects;
import javax.swing.*;

public class DummyWhiteSpaceTest {
  public JComponent makeUI(String dummy) {
    JPanel mainView = new JPanel(new GridBagLayout());

    JPanel contents = new JPanel(new GridBagLayout());
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.insets = new Insets(1, 3, 3, 3);
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.ipady = 2;
    gbc.anchor = GridBagConstraints.EAST;

    /* Text labels. */
    JLabel text1 = new JLabel("Some text: ");
    contents.add(text1, gbc);
    gbc.gridy++;
    JLabel text2 = new JLabel("More text: ");
    contents.add(text2, gbc);
    gbc.gridy++;
    JLabel text3 = new JLabel("Third line: ");
    contents.add(text3, gbc);
    gbc.gridx++;
    gbc.gridy = 0;

    JTextField textField1 = new JTextField(10);
    contents.add(textField1, gbc);
    gbc.gridx++;
    gbc.gridy++;
    gbc.gridx--;

    JTextField textField2 = new JTextField(10);
    contents.add(textField2, gbc);
    gbc.gridy++;

    //@see javax.swing.plaf.basic.BasicComboBoxUI#getDefaultSize()
    //JLabel sitePass = new JLabel(" ");
    JLabel sitePass = new JLabel(dummy);
    sitePass.setFont(new Font("Monospaced", Font.PLAIN, 14));
    contents.add(sitePass, gbc);

    mainView.add(contents);

    (new Timer(1000, e -> {
      if (Objects.equals(sitePass.getText(), dummy)) {
        sitePass.setText("Pushup time");
      } else {
        sitePass.setText(dummy);
      }
    })).start();

    return mainView;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      DummyWhiteSpaceTest test = new DummyWhiteSpaceTest();
      JPanel p = new JPanel(new GridLayout(1, 2));
      p.add(test.makeUI(""));
      p.add(test.makeUI(" "));
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(p);
      f.setSize(640, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}
aterai
  • 9,658
  • 4
  • 35
  • 44