Home > Blockchain >  java swing remove latest added panel
java swing remove latest added panel

Time:10-18

I am adding panels to a frame with a button click, each panel goes under the last added panel, I achieve that with setBounds, each time incrementing y position. There is a second button, that is supposed to remove the latest panel that I added. It should keep removing panels after every click. I have tried a few solutions but they all failed.

My code:

public class lab3 {
static int y = 50;
static JButton addThread;
static JPanel results;
public static void main(String[] args) {
    JFrame jFrame = new JFrame();
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jFrame.setSize(550, 650);
    jFrame.setTitle("Lab3");
    jFrame.setVisible(true);
    JPanel panelAddThread = new JPanel();
    panelAddThread.setLayout(null);
    panelAddThread.setBounds(0, 0, 550, 50);
    panelAddThread.setBackground(Color.red);
    JLabel threadLabel = new JLabel();
    threadLabel.setText("Thread count: ");
    addThread = new JButton();
    addThread.setBounds(300, 0, 25, 25);
    addThread.setText(" ");
    addThread.setBorder(null);
    addThread.addActionListener(e -> {
        results = new JPanel();
        results.setBounds(0, y, 550, 150);
        results.setBackground(Color.blue);
        results.setLayout(null);
        jFrame.add(results);
        jFrame.repaint();
        y = y  150;
    });
    // Remove
    JButton removeThread = new JButton();
    removeThread.setBorder(null);
    removeThread.setBounds(340, 0, 25, 25);
    removeThread.setText("-");
    removeThread.addActionListener(e -> {         
    });
    panelAddThread.add(threadLabel);
    panelAddThread.add(removeThread);
    panelAddThread.add(addThread);
    jFrame.add(panelAddThread);    }
    
    }

CodePudding user response:

I understand that you are asking for the code for the ActionListener for removeThread (JButton).

results is actually the last JPanel that you added, so that is the JPanel that you need to remove. However, once you remove it, you need to assign it to the new, last JPanel, i.e. the second last JPanel that was added.

Method getComponents returns all the components that were added, in the order that they were added. When you remove a component from a Container and subsequently call method getComponents, the array returned will not contain the component that you just removed. Hence the new, last JPanel is the last element in the array returned by method getComponents.

All that remains is to handle the "edge" cases.

Here is the code for the actionPerformed method:

removeThread.addActionListener(e -> {
    if (results != null) {
        jFrame.remove(results);
        jFrame.repaint();
        y -= 150;
        Container contentPane = jFrame.getContentPane();
        Component[] cmpts = contentPane.getComponents();
        int count = cmpts.length;
        if (count > 1) {
            results = (JPanel) cmpts[count - 1];
        }
        else {
            results = null;
        }
    }
});
  • If the user clicks removeThread before clicking addThread then results will be null.
  • If there is only one, added JPanel and we remove it, then we need to set results to null.

For completeness, here is the entire program, including the above changes.

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;

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

public class lab3 {
    static int y = 50;
    static JButton addThread;
    static JPanel results;

    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(550, 650);
        jFrame.setTitle("Lab3");
        jFrame.setVisible(true);
        JPanel panelAddThread = new JPanel();
        panelAddThread.setLayout(null);
        panelAddThread.setBounds(0, 0, 550, 50);
        panelAddThread.setBackground(Color.red);
        JLabel threadLabel = new JLabel();
        threadLabel.setText("Thread count: ");
        addThread = new JButton();
        addThread.setBounds(300, 0, 25, 25);
        addThread.setText(" ");
        addThread.setBorder(null);
        addThread.addActionListener(e -> {
            results = new JPanel();
            results.setBounds(0, y, 550, 150);
            results.setBackground(Color.blue);
            results.setLayout(null);
            jFrame.add(results);
            jFrame.repaint();
            y = y   150;
        });
        // Remove
        JButton removeThread = new JButton();
        removeThread.setBorder(null);
        removeThread.setBounds(340, 0, 25, 25);
        removeThread.setText("-");
        removeThread.addActionListener(e -> {
            if (results != null) {
                jFrame.remove(results);
                jFrame.repaint();
                y -= 150;
                Container contentPane = jFrame.getContentPane();
                Component[] cmpts = contentPane.getComponents();
                int count = cmpts.length;
                if (count > 1) {
                    results = (JPanel) cmpts[count - 1];
                }
                else {
                    results = null;
                }
            }
        });
        panelAddThread.add(threadLabel);
        panelAddThread.add(removeThread);
        panelAddThread.add(addThread);
        jFrame.add(panelAddThread);
    }
}

However, I would write your program differently such that it uses Swing's layout managers. Consider the following:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;

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

public class LabThree implements Runnable {
    private JFrame frame;
    private JPanel container;
    private JPanel results;

    public void run() {
        buildAndDisplayGui();
    }

    private void buildAndDisplayGui() {
        frame = new JFrame("Lab 3");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createButtonsPanel(), BorderLayout.PAGE_START);
        frame.add(createMainPanel(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JPanel createButtonsPanel() {
        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
        buttonsPanel.setBackground(Color.red);
        JButton addThreadButton = new JButton("\u2795");
        addThreadButton.addActionListener(this::addThread);
        buttonsPanel.add(addThreadButton);
        JButton removeThreadButton = new JButton("\u2796");
        removeThreadButton.addActionListener(this::removeThread);
        buttonsPanel.add(removeThreadButton);
        return buttonsPanel;
    }

    private JScrollPane createMainPanel() {
        container = new JPanel();
        container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
        JScrollPane scrollPane = new JScrollPane(container);
        scrollPane.setPreferredSize(new Dimension(570, 620));
        return scrollPane;
    }

    private void addThread(ActionEvent event) {
        results = new JPanel();
        results.setBackground(Color.blue);
        Dimension dim = new Dimension(550, 150);
        results.setMaximumSize(dim);
        results.setMinimumSize(dim);
        results.setPreferredSize(dim);
        container.add(results);
        container.revalidate();
    }

    private void removeThread(ActionEvent event) {
        if (results != null) {
            container.remove(results);
            Component[] cmpts = container.getComponents();
            int count = cmpts.length;
            if (count > 0) {
                results = (JPanel) cmpts[count - 1];
            }
            else {
                results = null;
            }
            container.revalidate();
            container.repaint();
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new LabThree());
    }
}
  • All components added to a JFrame are actually added to its content pane which, by default, is a JPanel whose [default] layout manager is BorderLayout.
  • Usually you should call method setVisible (of class JFrame) only after you have added all the components.
  • After the GUI is displayed and you add or remove components from a container (such as JPanel), you need to call method revalidate. Sometimes you also need to call method repaint after you have called method revalidate.
  • If you click addThreadButton many times, not all the added JPanels will be visible, hence I use JScrollPane.
  • The text for addThreadButton is the Unicode heavy plus symbol and the text for removeThreadButton is the heavy minus symbol.
  • The ActionListeners are implemented using method references.
  • Although not required, it is recommended to explicitly launch the event dispatch thread (EDT), which is done in method main in the above code.
  • Related