Выполнение действия при закрытии JFrame

#java #dispose #jframe

#java #утилизировать #jframe

Вопрос:

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

Пример кода, который у меня пока есть: Основной фрейм…

 
public class MainFrame extends JFrame
 {
     public MainFrame()
     {
         super("Main Frame");
         JButton details = new JButton("Add Detail");
         add(details);
         details.addActionListener(new ActionListener(){
             public void actionPerformed(ActionEvent e)
             {
                 new DetailFrame().setVisible(true);
             }
         });
     }
 }
  

Подробный фрейм…

 
 public class DetailFrame extends JFrame
 {
     public DetailFrame()
     {
         super("Detail Frame");
         JButton save = new JButton("Save");
         add(save);
         save.addActionListener(new ActionListener(){
             public void actionPerformed(ActionEvent e)
             {
                 // Save whatever content
                 dispose();
             }
         });
     }
 }
  

Итак, когда я нажимаю кнопку «Сохранить» в детальном фрейме, я хочу что-то сделать в основном фрейме, тогда как при нажатии на «x» в детальном фрейме я ничего не хочу делать..

Надеюсь, кто-нибудь сможет мне помочь, и прошу прощения за мой английский..

Ответ №1:

Вы можете передать дескриптор мэйнфрейма конструктору DetailFrame. Затем, при нажатии кнопки Сохранить, DetailFrame вызовет функцию в MainFrame и передаст ей изменения.

Другой способ — создать public boolean переменную в DetailFrame и установить ее в true значение при нажатии кнопки Сохранить. Таким образом, МэйнФрейм узнает, был ли подробный фрейм закрыт или сохранен.

РЕДАКТИРОВАТЬ: еще несколько идей:

Используйте JDialog вместо JFrame . JDialog.setVisible является модальным, т. Е. блокирует вызывающую функцию до тех пор, пока диалоговое окно не будет закрыто; таким образом, вы можете обрабатывать результаты диалога в том же прослушивателе кнопок «Подробности».

Чтобы получить доступ к диалоговому окну после его вызова, сохраните диалоговое окно в отдельной переменной. Сначала создайте диалоговое окно, затем покажите его, а затем обработайте результат, проанализировав его переменные.

Сохраните результаты редактирования в других общедоступных переменных DetailFrame (или давайте назовем это DetailDialog ). Это должно произойти только при нажатии кнопки «Сохранить». Это может даже позволить обходиться без логической переменной (зависит от типов значений, которые вы редактируете).

 DetailDialog dlg = new DetailDialog();
dlg.setVisible(true);
if(dlg.approvedResult != null) {
    // process the result...
}
  

РЕДАКТИРОВАТЬ: Извините, JDialog по умолчанию не является модальным. Необходимо вызвать специальный super конструктор, чтобы сделать его модальным.

Также здесь вам придется передать ссылку на MainFrame в конструктор dialog, но вы все равно можете объявить ее как простую JFrame и избежать ненужных зависимостей.

Чтобы получить ссылку на вложенный файл MainFrame изнутри анонимного ActionListener, используйте MainFrame.this .

Чтобы иметь возможность изменять текст кнопки после ее создания, вам придется сохранить кнопку в переменной-члене.

Основной фрейм…

 public class MainFrame extends JFrame
{
    private JButton details = new JButton("Add Detail");

    public MainFrame()
    {
        super("Main Frame");
        getContentPane().add(details);
        details.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                DetailDialog dlg = new DetailDialog(MainFrame.this);
                dlg.setVisible(true);
                if(dlg.approved){
                    details.setText("Edit Detail");
                }
            }
        });
    }
}
  

Подробное диалоговое окно… (не фрейм)

 public class DetailDialog extends JDialog
{
    public boolean approved = false;

    public DetailDialog(JFrame parent)
    {
        super(parent,"Detail Dialog",true);        // modal dialog parented to the calling frame
        JButton save = new JButton("Save");
        getContentPane().add(save);
        save.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                // Save whatever content
                approved = true;
                dispose();
            }
        });
    }
}
  

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

1. Я пробовал использовать общедоступное логическое значение, но по какой-то причине я просто не могу получить к нему доступ с мэйнфрейма.. Я не уверен, что вы имеете в виду, передавая дескриптор конструктору DetailFrame?

2. Я отредактировал ответ, пожалуйста, смотрите более подробную информацию выше. На самом деле, передача MainFrame в диалоговое окно — не лучшая идея, потому что это добавляет слишком много зависимостей между классами; метод с общедоступными переменными лучше, потому что он позволит вам использовать одно и то же диалоговое окно в разных местах.

3. Я попробовал вышеописанное сейчас, но все еще не работает.. В моем коде диалоговое окно, похоже, не является модальным — функция, которая открывает диалоговое окно, продолжает выполняться сразу, вместо ожидания закрытия диалогового окна..

4. Наконец-то это заработало, вызвав функцию setModal (true), прежде чем сделать диалоговое окно видимым.

5. @Simon: «Наконец-то это заработало, вызвав setModal(true)» Это можно сделать в конструкторе. Кстати — Модальность диалога была впервые упомянута в моем ответе. Вы это пропустили?

Ответ №2:

Создайте фрейм сведений в основном фрейме и добавьте к нему windowlistener, используя класс windowadapter. Реализуйте событие windowclosing, проверяя наличие изменений, обрабатывайте их, а затем удаляйте фрейм сведений. Все это делается в мэйнфрейме.

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

Возможно, вы захотите реализовать проверку изменений в detailframe как метод, возвращающий класс, содержащий интересующие данные. Таким образом, ваш windowlistener может быть небольшим в нужной степени.

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

1. Я не совсем понимаю .. Точная вещь, которую я хочу сделать, это изменить текст кнопки «Добавить деталь» на «Редактировать деталь», но только при добавлении детали.. Не могли бы вы случайно привести пример кода того, что вы описали выше?

Ответ №3:

Забудьте о 2-м JFrame . вместо этого используйте модальный диалог. Он будет блокировать ввод до тех пор, пока не будет отклонен. После отклонения единственное, что нужно сделать, это решить, обновлять ли исходные данные. JOptionPane имеет некоторую встроенную функциональность, которая упрощает это. Если пользователь нажимает Cancel или esc клавишу, showInputDialog() метод вернет null результат.

 import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

class EditInfo {

    public static void main(String[] args) {

        Runnable r = new Runnable() {
            public void run() {
                final JFrame f = new JFrame("Uneditable");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JPanel p = new JPanel(new BorderLayout(10,10));

                final JTextField tf = new JTextField("Hello World!", 20);
                tf.setEnabled(false);
                p.add(tf, BorderLayout.CENTER);

                JButton edit = new JButton("Edit");
                edit.addActionListener( new ActionListener(){
                    public void actionPerformed(ActionEvent ae) {
                        String result = JOptionPane.showInputDialog(
                            f,
                            "Edit text",
                            tf.getText());
                        if (result!=null) {
                            tf.setText(result);
                        }
                    }
                } );
                p.add(edit, BorderLayout.EAST);

                p.setBorder(new EmptyBorder(10,10,10,10));

                f.setContentPane(p);
                f.pack();
                f.setLocationByPlatform(true);
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
  

Если необходимо отредактировать несколько полей одновременно в JOptionPane , используйте JPanel , чтобы вместить их все, и поместите их в showMessageDialog() вызов. Проверьте результат возврата на основе целых чисел, чтобы определить, одобрил ли пользователь изменения.