.add() в java AWT не работает после выполнения действия

#java #button #awt

Вопрос:

Я довольно новичок в кодировании и столкнулся с этой проблемой в своем коде. Я создаю кнопку с помощью импорта Java AWT. Затем я проверяю ответ с помощью цикла while и хочу создать другую кнопку после, однако .add (), похоже, больше не работает.

 import java.awt.*;
import java.awt.event.*;

public class Main1
{
    public static void main(String[] args)
    {
       Frame f = new Frame();
       f.setSize(500, 500);
       f.setVisible(true);
       ButtonPanel bp = new ButtonPanel(f);
       
       bp.x = null;
       while (bp.x == null)
       {
       }
       System.out.println(bp.x);
       
       //THE ISSUE- THIS WILL NOT APPEAR AFTER BUTTON PRESS
       f.add("South", new Button("REEE"));
    }
}
 
 class ButtonPanel extends Panel implements ActionListener
{
    volatile String x;
    public ButtonPanel(Frame f)
    {
        Button b = new Button("Hi");
        b.addActionListener(this);
        f.add("North", b);
    }
    
    
    public void actionPerformed(ActionEvent e)
    {
        x = e.getActionCommand();
    }
}
 

Я пробовал решения для этого в течение последнего дня или около того, и, похоже, ничего не работает. Я видел в других сообщениях, что люди говорили использовать Wait/Notify, однако я не слишком уверен, как это работает, и я хотел бы четко знать, что происходит не так в моей программе (хотя я все еще открыт для использования Wait/Notify в своем решении).

Любая помощь будет признательна, большое вам спасибо

Комментарии:

1. О да, извините, я кое-что проверял, хотел удалить это для этого вот

2. Не используйте while цикл для «остановки» выполнения кода подобным образом. Вместо этого используйте обратный вызов (наблюдатель)

3. Убедительное предложение: не используйте AWT. После AWT существует два поколения графических фреймворков: Swing и JavaFX. Если вы хотите узнать что-то новое, попробуйте javafx.

Ответ №1:

Итак, здесь речь идет о ряде проблем.

Во — первых, это тот факт, что менеджеры по верстке, как правило, ленивы. Это означает, что вы можете быстро добавить и/или удалить несколько компонентов, а затем выполнить один макет и покраску.

Для этого вам нужно revalidate Container , чтобы приложение было обновлено.

Далее, AWT (и расширение Swing) основаны на концепции «Модель-представление-контроллер», одним из аспектов которой является «шаблон наблюдателя». Это в основном концепция обратного вызова, которая позволяет вам получать уведомления, когда происходит что-то интересное.

Button использует an ActionListener для генерации событий, когда кнопка «активирована». Это и есть «модель наблюдателя» в действии.

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

Например, действительно ButtonPanel ли это ответственность за обновление кадра? Действительно ли предоставление ButtonPanel неограниченного контроля над кадром-хорошая идея?

Вместо ButtonPanel этого «должно» предоставлять какое-то уведомление, когда произошло какое-то действие, и тогда любые заинтересованные стороны должны иметь возможность делать все, что им нужно.

В качестве «базового» примера…

 import java.awt.Button;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import javax.swing.event.EventListenerList;

public class Test {

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

    public Test() {
        Frame f = new Frame();
        f.setPreferredSize(new Dimension(500, 500));
        f.pack();

        ButtonPanel bp = new ButtonPanel(f);
        bp.addObsever(new Observer() {
            @Override
            public void hiWasPerformed() {
                f.add("South", new Button("REEE"));
                f.revalidate();
            }
        });

        f.setVisible(true);
    }

    public interface Observer extends EventListener {
        public void hiWasPerformed();
    }


    class ButtonPanel extends Panel  {

        private EventListenerList eventListener = new EventListenerList();

        public ButtonPanel(Frame f) {
            Button b = new Button("Hi");
            b.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Observer[] listeners = eventListener.getListeners(Observer.class);
                    for (Observer observer : listeners) {
                        observer.hiWasPerformed();
                    }
                }
            });
            f.add("North", b);
        }

        public void addObsever(Observer observer) {
            eventListener.add(Observer.class, observer);
        }

        public void removeObsever(Observer observer) {
            eventListener.remove(Observer.class, observer);
        }
    }
}
 

Ответ №2:

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

Однако в то же время простое решение состоит в том, чтобы переместить эту строку f.add("South", new Button("REEE")); внутри события действия и использовать Frame.pack(); :

 public class Main1
{
    public static void main(String[] args)
    {
       Frame f = new Frame();
       //set minimums rather than a fixed size
       f.setMinimumSize(new Dimension(500, 500));
       f.setVisible(true);
       CustomButton b = new CustomButton(f);

       //Add this line to update/size/show the UI
       f.pack();
       
       //Don't place any more code inside the main method. Future events should be triggered by interacting with the UI/buttons
    }
}
 

Тогда для кнопки нам не нужно расширять панель, мы можем сделать что-то вроде этого:

 class CustomButton implements ActionListener
{
    Frame parentFrame;
    public CustomButton(Frame f)
    {
        parentFrame = f;
        Button b = new Button("Hi");
        b.addActionListener(this);
        f.add("North", b);
    }
    
    public void actionPerformed(ActionEvent e)
    {
        //Add button here instead of the main class
        parentFrame.add("South", new Button("REEE"));
        //The buttons are being added below the bottom of your window, this will force them to be shown.
        //Using a layout manager will solve this ploblem and you will not need to do this:
        parentFrame.pack();
    }
}
 

Примечание: при многократном нажатии на кнопку «Привет» появятся интересные результаты, если кнопки «REEE» будут перекрываться или делать странные вещи, если вы измените размер окна.

Комментарии:

1. ОООО, иногда я такая идиотка, я понятия не имела, что это будет создано вне рамок, спасибо

2. Вместо того , чтобы использовать pack , что может повлиять на размер окна, если пользователь изменит его, лучше повторно проверить контейнер, содержащий кнопки