Reordering labels

Viewed 48

I'm creating labels dynamically from an array in a FlowLayout JPanel, storing them in a JLabel array for future reference. They are displayed from left to right as intended.
I want to move one of the labels to the beginning (leftmost) of the panel.

I don't mind if the whole array shifts or just two labels swap places:

apple orange pear cherry melon
              |
cherry apple orange pear melon
              or
cherry orange pear apple melon

I've swapped array entries, then revalidate() and repaint(), but nothing happens.
Is there an easy way to move swing components around without removing all and then re-adding them to the panel or copying all the properties from one label to the other (I have others defined, not just the text)?

Here is a stripped down version of my code:

import javax.swing.*;

public class Test extends JPanel {
    public Test () {
        String entries[] = { "apple", "orange", "pear", "cherry", "melon" };
        JLabel[] lbls = new JLabel[entries.length];

        for (int i = 0; i < entries.length; ++i) {
            lbls[i] = new JLabel();
            lbls[i].setText(entries[i]);
            add(lbls[i]);
        }

        // swap array entries
        JLabel tmplbl = new JLabel();
        tmplbl = lbls[3];
        lbls[3] = lbls[0];
        lbls[0] = tmplbl;
        revalidate();
        repaint();

    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Test");
                frame.setContentPane(new Test());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
                frame.pack();
            }
        });
    }
}
2 Answers

I've swapped array entries

Swapping entries in an array does nothing. The Array has nothing to do with the panel.

So you need to adjust the components on the panel.

I want to move one of the labels to the beginning (leftmost) of the panel.

Well that is a different requirement than "swapping". It is also easier.

You can add a component to a panel and specify its position in the panel, so adding a component to the beginning is easy because its position will always be zero.

So to move the 3rd component to the beginning the code would be something like:

Component component = panel.getComponent(2);
panel.add(component, 0);
panel.revalidate();
panel.repaint();

If you really want a swap, then the code would be similar. You would get the component at both locations and then add the one component back to the lower location first and the add the other component back to the higher location.

There are a couple of things to fix before fixing your error:

  1. Here are 2 errors in this line: public class Test extends JPanel {

    • Class name, do you know how many people call their classes Test? A LOT! Make it more descriptive, like SwapLabelsTest.
    • extends JPanel, you're not changing the behavior of the JPanel so there's no need to extend it in this case, just create a new instance of JPanel.
  2. Don't put everything in the constructor, it's better to have an initialize() method or something like that (createAndShowGUI() in the code below) to handle GUI construction. It may seem like the easiest way, but separating that part will come handy later on when the project becomes bigger.

  3. Move your variables to a bigger scope, for easier handling, unless those variables are local to the method, this will improve performance and readability.

  4. Include a component that detects events, such as a JButton so that your swapping execution will happen when that event is triggered (a button click).

  5. Your swapping logic seems a little bit odd, you have created new JLabels there and are trying to swap them, but it's better to have a MVC kind of pattern here, so that you swap the values in the array and then just update the UI after with those changes.

    You may be asking, but how do I do that? Well like this:

    String tmpString = entries[3];
    entries[3] = entries[1];
    entries[1] = tmpString;
    

    The above code swaps the values in the entries array, all we have to do now is update each label with lbl[i].setText(entries[i]) inside of a for-loop.

So, you end up with something like this in the end:

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class Test {
    private JFrame frame;
    private JPanel panel;
    private String entries[] = { "apple", "orange", "pear", "cherry", "melon" };
    private JLabel[] lbls = new JLabel[entries.length];
    JButton button;

    private void createAndShowGUI() {
        panel = new JPanel();

        for (int i = 0; i < entries.length; ++i) {
            lbls[i] = new JLabel();
            lbls[i].setText(entries[i]);
            panel.add(lbls[i]);
        }

        button = new JButton("Swap 1 and 3");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String tmpString = entries[3];
                entries[3] = entries[1];
                entries[1] = tmpString;
                reloadLabels();
            }
        });

        frame = new JFrame("Test");
        frame.add(panel);
        frame.add(button, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.pack();
    }

    private void reloadLabels() {
        for (int i = 0; i < entries.length; ++i) {
            lbls[i].setText(entries[i]);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Test().createAndShowGUI();
            }
        });
    }
}

Everytime you click the button, the items 1 & 3 (indexes) will be swapped and the UI will be updated (as .setText triggers an UI update).

enter image description here enter image description here

Related