Search code examples
javaswinggarbage-collection

Deleting current controls in java


OK, let's try this. This a small Java application to dynamically create JButtons. What I am trying to find a way to do is fully delete created JButtons so the garbage collection will free up the memory they used to use. THIS IS A MINIMAL REPRODUCIBLE EXAMPLE as an example of what I am trying to accomplish.

So, the user can set the x and y position of a control and click the create button and it makes the JButton called myButton. Now what I would like is for the Delete button to delete, make null, all the created buttons. I know I can make it invisible, remove it from the container, etc, but I am looking to destroy it.

Question 1: As I understand it, if I set an object = null it allows it to be garbage collected and removed from memory? So if I do a myButton=null, will that object be able to be removed from memory?

Question 2: If Question 1 is correct, I know when created all the new object buttons will have the same name. So how do I go about dynamically creating an instance them while still being able to destroy them later? I've tried using a ListArray, and while I can access them, I can't null them.

Question 3: When another button is added to a container, that object still operates correctly even though I make another Jbutton that replaces the contents of the original button myButton. I guess I'm confused on the process that occurs between instantiation and adding it to a container.

Is what I'm trying to do just not possible, a gross conceptual error on my part, or is there a means to do it?

package makeControls;

 import java.awt.EventQueue;

 import javax.swing.JFrame;
 import javax.swing.JButton;
 import java.awt.event.ActionListener;
 import java.awt.event.ActionEvent;
 import javax.swing.JTextField;
 import javax.swing.SwingConstants;

public class MakeControls {

private JFrame frame;
private JTextField txtXPosition;
private JTextField txtYPosition;
private JButton btnDelete;
private JButton myButton;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                MakeControls window = new MakeControls();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the application.
 */
public MakeControls() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);
    
    JButton btCreateButton = new JButton("Create Button");
    btCreateButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            myButton  = new JButton();                  // create new button
            int x = Integer.valueOf(txtXPosition.getText());    
            int y = Integer.valueOf(txtYPosition.getText());
            myButton.setBounds( x,y,50,20);                     // set bounds based on entered values
            frame.getContentPane().add(myButton);                   
            myButton.setVisible(true);                      
            frame.repaint();
        }
    });
    btCreateButton.setBounds(222, 11, 146, 23);
    frame.getContentPane().add(btCreateButton);
    
    txtXPosition = new JTextField();
    txtXPosition.setText("X Position");
    txtXPosition.setHorizontalAlignment(SwingConstants.LEFT);
    txtXPosition.setBounds(36, 12, 86, 20);
    frame.getContentPane().add(txtXPosition);
    txtXPosition.setColumns(10);
    
    txtYPosition = new JTextField();
    txtYPosition.setText("Y Position");
    txtYPosition.setBounds(126, 12, 86, 20);
    frame.getContentPane().add(txtYPosition);
    txtYPosition.setColumns(10);
    
    btnDelete = new JButton("Delete All");
    btnDelete.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Deleting");
            myButton = null;
        }
    });
    btnDelete.setBounds(222, 50, 146, 23);
    frame.getContentPane().add(btnDelete);
}

}

As usual, thank in advance.


Solution

  • Introduction

    I rearranged your code to create the following GUI.

    Start

    I divided the JFrame into two JPanels. The JPanel on the left is where your user created controls will appear. The JPanel on the right contains the GUI controls.

    The reason I did this was to keep the user from overlaying the GUI controls and to separate the GUI controls from the user created controls. This will become important when we delete the user created controls.

    Here's the GUI with a user created JButton. I put some text on the JButtons so I could tell them apart.

    Next

    Explanation

    Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Bookmark and study the rest of the tutorial.

    I made use of the JFrame default BorderLayout. I created the GUI controls JPanel using a GridLayout inside of a FlowLayout. The GridLayout makes the four Swing components equal in size and arranges them in two rows of two columns. The FlowLayout makes the GridLayout JPanel a minimal size.

    The user created controls JPanel has a null layout and an initial size. You can make this JPanel larger or smaller by changing the size of the JFrame. One way is to maximize the JFrame.

    To delete all the user created controls, I remove the Swing components from the user created controls JPanel. I don't have to worry about deleting the GUI control Swing components.

    Code

    Here's the complete runnable code.

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.FlowLayout;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    
    public class MakeControls {
    
        private int buttonCounter;
    
        private JFrame frame;
        private JPanel makeControlsPanel;
        private JTextField txtXPosition;
        private JTextField txtYPosition;
    
        /**
         * Launch the application.
         */
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    try {
                        new MakeControls();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        /**
         * Create the application.
         */
        public MakeControls() {
            this.buttonCounter = 1;
            this.makeControlsPanel = createMakeControlsPanel();
            initialize();
        }
    
        /**
         * Initialize the contents of the frame.
         */
        private void initialize() {
            frame = new JFrame("Make Controls");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.add(makeControlsPanel, BorderLayout.CENTER);
            frame.add(createControlPanel(), BorderLayout.EAST);
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private JPanel createMakeControlsPanel() {
            JPanel panel = new JPanel(null);
            panel.setPreferredSize(new Dimension(500, 500));
    
            return panel;
        }
    
        private JPanel createControlPanel() {
            JPanel outerPanel = new JPanel(new FlowLayout());
    
            JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
            panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    
            JButton btCreateButton = new JButton("Create Button");
            btCreateButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent event) {
                    JButton button = new JButton("Button " + buttonCounter++);
                    int x = Integer.valueOf(txtXPosition.getText());
                    int y = Integer.valueOf(txtYPosition.getText());
                    Dimension d = button.getPreferredSize();
                    button.setBounds(x, y, d.width + 10, d.height);
                    makeControlsPanel.add(button);
                    frame.repaint();
                }
            });
            panel.add(btCreateButton);
    
            JButton btnDelete = new JButton("Delete All");
            btnDelete.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent event) {
                    int size = makeControlsPanel.getComponentCount();
                    for (int index = size - 1; index >= 0; index--) {
                        makeControlsPanel.remove(index);
                    }
                    buttonCounter = 1;
                    frame.repaint();
                }
            });
            panel.add(btnDelete);
    
            txtXPosition = new JTextField(10);
            txtXPosition.setText("X Position");
            panel.add(txtXPosition);
    
            txtYPosition = new JTextField(10);
            txtYPosition.setText("Y Position");
            panel.add(txtYPosition);
    
            outerPanel.add(panel);
    
            return outerPanel;
        }
    
    }
    

    Edited to add 1

    I didn't answer the questions.

    Question 1: As I understand it, if I set an object = null it allows it to be garbage collected and removed from memory? So if I do a myButton=null, will that object be able to be removed from memory?

    Yes, but you don't have to do that. When you remove a Swing component from a JPanel, the remove process will allow the Swing component to be garbage collected.

    Question 2: If Question 1 is correct, I know when created all the new object buttons will have the same name. So how do I go about dynamically creating an instance them while still being able to destroy them later? I've tried using a ListArray, and while I can access them, I can't null them.

    You remove the Swing components by getting the components from the JPanel and removing them.

    Question 3: When another button is added to a container, that object still operates correctly even though I make another Jbutton that replaces the contents of the original button myButton. I guess I'm confused on the process that occurs between instantiation and adding it to a container.

    The JPanel maintains the references to the user generated JButtons. Your application code doesn't have to keep the references.