Java Swing удалить последнюю добавленную панель

Я добавляю панели в кадр нажатием кнопки, каждая панель идет под последней добавленной панелью, я достигаю этого с помощью setBounds, каждый раз увеличивая позицию y. Есть вторая кнопка, которая должна удалить последнюю панель, которую я добавил. Он должен удалять панели после каждого клика. Я пробовал несколько решений, но все они потерпели неудачу.

Мой код:

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

Храните List товаров в виде очереди FIFO. Используйте JList и сделайте жизнь всех проще

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

Ответы 1

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

Насколько я понимаю, вы просите код для ActionListener для removeThread ( JButton).

results на самом деле является последним JPanel, который вы добавили, так что это JPanel, который вам нужно удалить. Однако, как только вы удалите его, вам нужно назначить его новому, последнему JPanel, то есть предпоследнему JPanel, который был добавлен.

Метод getComponents возвращает все добавленные компоненты в том порядке, в котором они были добавлены. Когда вы удаляете компонент из Container и впоследствии вызываете метод getComponents, возвращаемый массив не будет содержать компонент, который вы только что удалили. Следовательно, новый, последний JPanel — это последний элемент в массиве, возвращаемом методом getComponents.

Остается только обрабатывать «пограничные» случаи.

Вот код метода actionPerformed:

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;
        }
    }
});
  • Если пользователь нажмет removeThread перед нажатием addThread, то results будет нулевым.
  • Если есть только один добавленный JPanel и мы его удаляем, то нам нужно установить results в ноль.

Для полноты, вот вся программа, включая вышеуказанные изменения.

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

Однако я бы написал вашу программу по-другому, чтобы она использовала менеджеры компоновки Swing . Рассмотрим следующее:

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());
    }
}
  • Все компоненты, добавленные в JFrame , на самом деле добавляются в его панель содержимого, которая по умолчанию является JPanel, чьим менеджером компоновки [по умолчанию] является BorderLayout.
  • Обычно вы должны вызывать метод setVisible (класса JFrame) только после того, как вы добавили все компоненты.
  • После отображения графического интерфейса и добавления или удаления компонентов из контейнера (например, JPanel) необходимо вызвать метод revalidate. Иногда вам также нужно вызвать метод repaint после того, как вы вызвали метод revalidate.
  • Если вы нажмете addThreadButton много раз, не все добавленные JPanel будут видны, поэтому я использую JScrollPane.
  • Текст для addThreadButton — это жирный символ Unicode плюс , а текст для removeThreadButton — это жирный минус.
  • ActionListener реализуются с помощью ссылок на методы.
  • Хотя это и не требуется, рекомендуется явно запустить поток отправки событий (EDT), который выполняется в методе main в приведенном выше коде.

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