12

I'm having a problem with this. I have a JPanel and normally I would create a JLabel like this:

JLabel lblNewLabel = new JLabel("New label");
lblNewLabel.setBounds(0, 0, 135, 14);
panel.add(lblNewLabel);

but I want each time I click a button, in that panel to be created a new JLabel with the same size, but with a different height possition. I tried:

panel.add(new JLabel(stringName));

but this way I don't get to set it's bounds. stringName I get from a JTextField.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
martin
  • 1,007
  • 2
  • 16
  • 32
  • 4
    *"normally I would create a JLabel like this: .. `lblNewLabel.setBounds(0, 0, 135, 14);`"* Normally you are doing it wrong. ***Use layouts!*** – Andrew Thompson Dec 25 '12 at 11:17

3 Answers3

14

First off, use a layout. Done correctly the layout will place the components like you want. Secondly, when dynamically adding a component to a layout you need to tell the layout to update. Here is an example, it adds a label each time a button is pressed:

public static void main(String[] args) {

    final JFrame frame = new JFrame("Test");
    frame.setLayout(new GridLayout(0, 1));

    frame.add(new JButton(new AbstractAction("Click to add") {
        @Override
        public void actionPerformed(ActionEvent e) {

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    frame.add(new JLabel("Bla"));
                    frame.validate();
                    frame.repaint();
                }
            });
        }
    }));

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 300);
    SwingUtilities.invokeLater(new Runnable() {
        @Override public void run() {
            frame.setVisible(true);
        }
    });
}
dacwe
  • 43,066
  • 12
  • 116
  • 140
  • 3
    Swing components should also be created on EDT, and `setSize` is a real no no use a correct `LayoutManager` and call `pack()` on `JFrame` before setting it visible – David Kroukamp Dec 25 '12 at 12:56
  • 1
    @DavidKroukamp: No need to do it on the EDT before it is realized (in this case `setVisible(true)`) and about `pack()` this example needed more space to prove the point. – dacwe Dec 25 '12 at 17:15
  • 1
    I dont get what you mean? I see no `invokeLater` block which would cause `JFrame#setVisible(true);` to be run on EDT? As for the space thats where `pack()` would come in handy after adding the component to resize the JFrame, if though `setSize` is a must rather override `getPrefferedSize()` and return appropriate dimensions – David Kroukamp Dec 25 '12 at 17:19
4

As said by @AndrewThompson use a correct LayoutManager, you should not be messing with setBounds etc.

Here is an example I made (Simply adds a JLabel to the JPanel each time the JButton is clicked):

enter image description here

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class Test {

    public Test() {
        createAndShowUI();
    }

    private void createAndShowUI() {
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initComponents(frame);

        frame.setResizable(false);
        frame.pack();
        frame.setVisible(true);
    }

    private void initComponents(final JFrame frame) {

        final JPanel panel = new JPanel();

        JButton button = new JButton("Add label");

        button.addActionListener(new ActionListener() {
            int count = 1;

            @Override
            public void actionPerformed(ActionEvent e) {
                JLabel _lbl = new JLabel("Label " + count);//make label and assign text in 1 line

                panel.add(_lbl);//add label we made

                panel.revalidate();
                panel.repaint();

                frame.pack();//so our frame resizes to compensate for new components

                count++;
            }
        });

        frame.add(panel, BorderLayout.CENTER);
        frame.add(button, BorderLayout.SOUTH);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test();
            }
        });
    }
}
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
0

Try swapping the order of of your commands, add the panel first then set the location.

Sam
  • 86,580
  • 20
  • 181
  • 179
Xiaoerge
  • 101
  • 1
  • 1