bkoodaa
bkoodaa

Reputation: 5322

Java Swing how to fix JLabel size

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("");
    }
}
}

Upvotes: 0

Views: 2329

Answers (3)

Andrew Thompson
Andrew Thompson

Reputation: 168815

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);

Upvotes: 4

aterai
aterai

Reputation: 9808

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);
    });
  }
}

Upvotes: 1

AxelH
AxelH

Reputation: 14572

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.

Upvotes: 1

Related Questions