Удаление текущих элементов управления в Java

Хорошо, давайте попробуем это. Это небольшое Java-приложение для динамического создания JButton. Я пытаюсь найти способ полностью удалить созданные JButtons, чтобы сборщик мусора освободил память, которую они использовали. ЭТО МИНИМАЛЬНЫЙ ВОСПРОИЗВОДИМЫЙ ПРИМЕР, иллюстрирующий то, чего я пытаюсь достичь.

Таким образом, пользователь может установить положение элемента управления по x и y и нажать кнопку «Создать», и JButton станет называться myButton. Теперь мне бы хотелось, чтобы кнопка «Удалить» удаляла, делала нулевыми все созданные кнопки. Я знаю, что могу сделать его невидимым, удалить из контейнера и т. д., но я хочу его уничтожить.

Вопрос 1: Насколько я понимаю, если я установлю объект = null, он позволит собрать мусор и удалить его из памяти? Итак, если я сделаю myButton=null, можно ли будет удалить этот объект из памяти?

Вопрос 2: Если вопрос 1 верен, я знаю, что при создании все кнопки нового объекта будут иметь одно и то же имя. Итак, как мне динамически создавать их экземпляры, сохраняя при этом возможность уничтожить их позже? Я пробовал использовать ListArray, и хотя у меня есть к ним доступ, я не могу обнулить их.

Вопрос 3. Когда в контейнер добавляется еще одна кнопка, этот объект по-прежнему работает правильно, даже если я создаю еще одну кнопку J, которая заменяет содержимое исходной кнопки myButton. Наверное, меня смущает процесс, который происходит между созданием экземпляра и добавлением его в контейнер.

То, что я пытаюсь сделать, просто невозможно, это грубая концептуальная ошибка с моей стороны, или есть способ сделать это?

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

}

Как обычно, заранее благодарю.

Писать c = null; — нонсенс. c — это локальная переменная, которая выходит за пределы области видимости после завершения цикла (при повторении цикла она будет ссылаться на другой объект). Окружать это утверждение блоком try/catch также бессмысленно: c = null; не может генерировать исключение.

Thomas Kläger 16.06.2024 21:12

Этот блок кода не создает и не предотвращает утечку памяти. Если у вас есть утечка памяти, возьмите дамп кучи и проанализируйте его с помощью Eclipse MAT — это даст вам лучшие подсказки о том, где происходит утечка памяти, чем публикация некоторых фрагментов кода в stackoverflow.

Thomas Kläger 16.06.2024 21:15

Почему ты поставил c = null; в блок try?

Jim Garrison 17.06.2024 02:16

Сообщение заменено на MRE. Это помогло мне продумать эту проблему, пока я ее писал, но до сих пор не могу найти способ выполнить свою задачу, если это возможно. Пожалуйста, смотрите пост.

MartinH 17.06.2024 06:55
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
90
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Введение

Я изменил ваш код, чтобы создать следующий графический интерфейс.

Я разделил JFrame на два JPanels. JPanel слева — это место, где появятся элементы управления, созданные пользователем. JPanel справа содержит элементы управления графическим интерфейсом.

Причина, по которой я это сделал, заключалась в том, чтобы не дать пользователю накладывать элементы управления графического интерфейса и отделить элементы управления графического интерфейса от элементов управления, созданных пользователем. Это станет важным, когда мы удалим созданные пользователем элементы управления.

Вот графический интерфейс с созданным пользователем JButton. Я поместил текст на JButtons, чтобы можно было отличить их друг от друга.

Объяснение

У Oracle есть полезное руководство Создание графического интерфейса с помощью Swing. Пропустите раздел «Обучение с использованием среды IDE NetBeans». Добавьте в закладки и изучите оставшуюся часть урока.

Я использовал JFrame по умолчанию BorderLayout. Я создал элементы управления графического интерфейса JPanel, используя GridLayout внутри FlowLayout. GridLayout делает четыре компонента Swing равными по размеру и размещает их в два ряда по два столбца. FlowLayout делает GridLayoutJPanel минимальным размером.

Созданные пользователем элементы управления JPanel имеют макет null и начальный размер. Вы можете сделать JPanel больше или меньше, изменив размер JFrame. Один из способов — максимизировать JFrame.

Чтобы удалить все созданные пользователем элементы управления, я удаляю компоненты Swing из созданных пользователем элементов управления JPanel. Мне не нужно беспокоиться об удалении компонентов Swing с графическим интерфейсом.

Код

Вот полный работоспособный код.

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

}

Отредактировано, добавлено 1

Я не ответил на вопросы.

Вопрос 1: Насколько я понимаю, если я установлю объект = null, он позволит собрать мусор и удалить его из памяти? Итак, если я сделаю myButton=null, можно ли будет удалить этот объект из памяти?

Да, но вам не обязательно этого делать. Когда вы удаляете компонент Swing из JPanel, процесс удаления позволит выполнить сборку мусора для компонента Swing.

Вопрос 2: Если вопрос 1 верен, я знаю, что при создании все кнопки нового объекта будут иметь одно и то же имя. Итак, как мне динамически создавать их экземпляры, сохраняя при этом возможность уничтожить их позже? Я пробовал использовать ListArray, и хотя у меня есть к ним доступ, я не могу обнулить их.

Вы удаляете компоненты Swing, получая компоненты из JPanel и удаляя их.

Вопрос 3. Когда в контейнер добавляется еще одна кнопка, этот объект по-прежнему работает правильно, даже если я создаю еще одну кнопку J, которая заменяет содержимое исходной кнопки myButton. Наверное, меня смущает процесс, который происходит между созданием экземпляра и добавлением его в контейнер.

JPanel сохраняет ссылки на созданные пользователем JButtons. Код вашего приложения не обязательно должен хранить ссылки.

Вы противоречите сами себе. В конце вы правильно говорите: «JPanel поддерживает ссылки на созданные пользователем JButtons», поэтому не следует отвечать «да» на вопрос 1, так как установка переменной в ноль не позволит выполнить сборку мусора кнопок.

Holger 17.06.2024 14:05

@Holger: Объект myButton, на который ссылается OP, выйдет за пределы области действия в конце метода btCreateButtonactionPerformed. Ничего не изменится, если он добавит myButton=null; в конец метода. Эта строка необязательна, но она не является недействительной.

Gilbert Le Blanc 17.06.2024 14:55

Вопрос был не в том, действительна или недействительна строка, а в том, сделает ли она кнопку сборщиком мусора. И ответ — нет, поскольку, как вы правильно сказали в вопросе 3, панель по-прежнему содержит ссылки на кнопку (кнопки), присвоение переменной значения null не делает кнопку (кнопки) пригодными для сбора мусора. Кроме того, переменная myButton не выходит за пределы области видимости в конце метода, поскольку это не локальная переменная, а поле экземпляра внешнего объекта.

Holger 17.06.2024 15:22

Другие вопросы по теме