为单击的按钮添加动作侦听器到JDialog

9

我有一个主应用程序,其中有一个带值的表格。然后,我点击“添加”按钮,弹出一个新的自定义(我自己制作的)JDialog类型的弹出窗口。在那里,我可以输入值,做一些勾选,然后点击“确认”。因此,我需要从对话框中读取该输入,以便将此值添加到主应用程序中的表格中。 如何在“确认”按钮被按下时监听,以便我可以在此之后读取该值?

addISDialog = new AddISDialog();
addISDialog.setVisible(true);
addISDialog.setLocationRelativeTo(null);
//somekind of listener...
//after "Confirm" button in dialog was pressed, get value
value = addISDialog.ISName;

我在JDialog中实现了监听器,可以监听该对话框内的按钮,但我需要在调用该对话框的主应用程序外部监听该按钮。 - Paulius Vindzigelskis
1
你能编辑JDialog类吗?如果可以的话,你可以将ActionEvent转发到另一个实现了ActionListener接口的类中,那个类可以执行你想要的操作。 - mre
我自己制作了AddISDialog(public class AddISDialog extends JDialog implements ActionListener),所以我可以编辑它。你说的将ActionEvent转发到另一个类是什么意思?我该怎么做呢? - Paulius Vindzigelskis
2
一种方法是向JDialog实例注册一个PropertyChangeListener,并让JDialog实例使用一个PropertyChangeSupport实例来触发属性更改事件,指示确认按钮已被按下。 - mre
将此值添加到表中。您可以在构造函数中将表模型传递给对话框(或在自定义对话框中实现setModel()方法)。顺便说一句,为了更快地获得更好的帮助,请发布一个SSCCE - Andrew Thompson
1
addISDialog.setLocationRelativeTo(null); 应该 可能 改为 addISDialog.setLocationRelativeTo(mainApplication); - Andrew Thompson
3个回答

15

如果用户按下确认后对话框将消失:

  • 如果您希望对话框表现为模态 JDialog,则很容易,因为一旦用户完成处理对话框,您就知道程序在代码中的位置——它将恰好位于您在对话框上调用 setVisible(true) 后的代码行之后。因此,在您在对话框上调用 setVisible(true) 后的代码行中,您只需查询对话框对象的状态即可。
  • 如果您需要处理非模态对话框,则需要向对话框添加 WindowListener,以在对话框窗口变为不可见时收到通知。

如果用户按下确认后对话框将保持打开状态:

  • 那么您应该使用一个 PropertyChangeListener,如上所建议。或者将对话框对象提供一个公共方法,允许外部类能够将 ActionListener 添加到确认按钮上。

欲了解更多详情,请向我们展示相关代码片段,或者更好的是,一个SSCCE

例如,要使 JDialog 类接受外部监听器,您可以给它一个 JTextField 和一个 JButton:

class MyDialog extends JDialog {
   private JTextField textfield = new JTextField(10);
   private JButton confirmBtn = new JButton("Confirm");

并提供一种方法,允许外部类将ActionListener添加到按钮:

public void addConfirmListener(ActionListener listener) {
  confirmBtn.addActionListener(listener);
}

此时,外部类只需要调用 `addConfirmListener(...)` 方法将其 ActionListener 添加到 confirmBtn 上。

例如:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class OutsideListener extends JFrame {
   private JTextField textField = new JTextField(10);
   private JButton showDialogBtn = new JButton("Show Dialog");
   private MyDialog myDialog = new MyDialog(this, "My Dialog");

   public OutsideListener(String title) {
      super(title);
      textField.setEditable(false);

      showDialogBtn.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent arg0) {
            if (!myDialog.isVisible()) {
               myDialog.setVisible(true);
            }
         }
      });

      // !! add a listener to the dialog's button
      myDialog.addConfirmListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            String text = myDialog.getTextFieldText();
            textField.setText(text);
         }
      });

      JPanel panel = new JPanel();
      panel.add(textField);
      panel.add(showDialogBtn);

      add(panel);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(400, 300);
   }

   private static void createAndShowGui() {
      JFrame frame = new OutsideListener("OutsideListener");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class MyDialog extends JDialog {
   private JTextField textfield = new JTextField(10);
   private JButton confirmBtn = new JButton("Confirm");

   public MyDialog(JFrame frame, String title) {
      super(frame, title, false);
      JPanel panel = new JPanel();
      panel.add(textfield);
      panel.add(confirmBtn);

      add(panel);
      pack();
      setLocationRelativeTo(frame);
   }

   public String getTextFieldText() {
      return textfield.getText();
   }

   public void addConfirmListener(ActionListener listener) {
      confirmBtn.addActionListener(listener);
   }
}

注意:我不建议除非绝对必要否则不要子类化JFrame或JDialog。这里为简洁起见而这样做。我个人更喜欢使用模态对话框来解决这个问题,并在需要时重新打开对话框。

编辑2
一个使用模态对话框的示例:

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class OutsideListener2 extends JFrame {
   private JTextField textField = new JTextField(10);
   private JButton showDialogBtn = new JButton("Show Dialog");
   private MyDialog2 myDialog = new MyDialog2(this, "My Dialog");

   public OutsideListener2(String title) {
      super(title);
      textField.setEditable(false);

      showDialogBtn.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent arg0) {
            if (!myDialog.isVisible()) {
               myDialog.setVisible(true);

               textField.setText(myDialog.getTextFieldText());
            }
         }
      });

      JPanel panel = new JPanel();
      panel.add(textField);
      panel.add(showDialogBtn);

      add(panel);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(400, 300);
   }

   private static void createAndShowGui() {
      JFrame frame = new OutsideListener2("OutsideListener");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class MyDialog2 extends JDialog {
   private JTextField textfield = new JTextField(10);
   private JButton confirmBtn = new JButton("Confirm");

   public MyDialog2(JFrame frame, String title) {
      super(frame, title, true); // !!!!! made into a modal dialog
      JPanel panel = new JPanel();
      panel.add(new JLabel("Please enter a number between 1 and 100:"));
      panel.add(textfield);
      panel.add(confirmBtn);

      add(panel);
      pack();
      setLocationRelativeTo(frame);

      ActionListener confirmListener = new ConfirmListener();
      confirmBtn.addActionListener(confirmListener); // add listener
      textfield.addActionListener(confirmListener );
   }

   public String getTextFieldText() {
      return textfield.getText();
   }

   private class ConfirmListener implements ActionListener {
      public void actionPerformed(ActionEvent e) {
         String text = textfield.getText();
         if (isTextValid(text)) {
            MyDialog2.this.setVisible(false);
         } else {
            // show warning
            String warning = "Data entered, \"" + text + 
               "\", is invalid. Please enter a number between 1 and 100";
            JOptionPane.showMessageDialog(confirmBtn,
                  warning,
                  "Invalid Input", JOptionPane.ERROR_MESSAGE);
            textfield.setText("");
            textfield.requestFocusInWindow();
         }
      }
   }

   // true if data is a number between 1 and 100
   public boolean isTextValid(String text) {
      try {
         int number = Integer.parseInt(text);
         if (number > 0 && number <= 100) {
            return true;
         }
      } catch (NumberFormatException e) {
         // one of the few times it's OK to ignore an exception
      }
      return false;
   }

}

我想我明白你的意思,但现在又出现了另一个相关的问题:在将操作发送给监听器之前,我需要在按下“确认”按钮时确认对话框中的数据。只有当数据有效(当有效时-对话框关闭,否则-不关闭),才能读取该值以进行进一步的操作。我可以从对话框类中触发某种类型的通知到监听器,但我不知道如何实现。 - Paulius Vindzigelskis
那么不要按照上面的代码。你需要做的是将对话框设为模态,并使其确认按钮的操作验证数据,仅在数据正确时关闭对话框。然后,在调用对话框上的 setVisible(true) 后,让主程序立即查询对话框类中的数据。 - Hovercraft Full Of Eels
@PooLaS:请参考上面的模态对话框解决方案示例。 - Hovercraft Full Of Eels
1
我在对话框类中创建了几个公共方法,因此我需要两次验证数据 - 在对话框中用于关闭和在主程序中用于输入新数据。谢谢大家。 - Paulius Vindzigelskis
这个不起作用,因为如果我按窗口的“x”按钮,它会像“确认”按钮一样工作,这不是预期的行为。 - Lucas

0

为什么不检查您的jDialog是否可见?

yourJD.setVisible(true);
while(yourJD.isVisible())try{Thread.sleep(50);}catch(InterruptedException e){}

这个也可以工作。


2
您的代码格式出现了问题。请参考Markdown帮助-代码和预格式化文本,并进行[编辑]。 - Bhargav Rao

-2
import javax.swing.JOptionPane;

或者如果你已经开始了

import javax.swing.*;

我们会为您提供保障。

在条件触发JOptionPane发送警告或任何模态消息后:

    JOptionPane.showMessageDialog(
            null,
            "Your warning String: I can't do that John",
            "Window Title",
            JOptionPane.ERROR_MESSAGE);

检查JOptionPane.*选项以确定消息类型。


这个答案并没有解决原帖作者想要解决的问题。 - Alexey Ivanov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接