【问题标题】:Communication between JOptionPane buttons and a custom panelJOptionPane 按钮和自定义面板之间的通信
【发布时间】:2012-01-06 17:37:56
【问题描述】:

我通过构建一个包含所需字段的 JPanel 并将其添加到 JOption 窗格中来创建一个多输入对话框

JMainPanel mainPanel = new JMainPanel(mensaje, parametros, mgr);

int i = JOptionPane.showOptionDialog(null, mainPanel, "Sirena",
        JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
        new String[] {"Aceptar", "Cancelar"}, "Aceptar");

但是我在使用按钮时遇到了问题,因为有些字段是必需的。如何在每个必填字段都打开后启用“确定”按钮,或者单击按钮进行验证并且在填写每个必填字段之前不要关闭窗格?

从 Java API 中,我发现了这个:

options - 表示用户可能选择的对象数组 可以使;如果对象是组件,则它们被正确渲染; 非字符串对象使用其 toString 方法呈现;如果这 参数为null,选项由外观决定

那么,我不能将自定义按钮作为参数传递吗?

看起来我将不得不制作自己的 JDialog?对于这种情况,我不知道如何让它像 JOptionPane 一样返回 int,有什么推荐的教程吗?

在示例中,options{"Aceptar", "Cancelar"},它们是显示的按钮,

PS。我可以完全控制我添加到 JPanel 的字段。

这是 JOptionPane 的截图:

【问题讨论】:

    标签: java swing modal-dialog jdialog


    【解决方案1】:

    我认为您不能取消激活 JOptionPane 的选择按钮,但仍然使用 JOptionPane 的一种方法是在未设置必填字段时简单地重新显示它。您可以显示一条错误消息 JOptionPane 首先描述错误,然后显示一个新的 JOptionPane ,它与第二个参数保持相同的 JPanel —— 这样已经输入的数据不会丢失。否则,您可能想要创建自己的 JDialog,顺便说一句,这并不难。

    编辑
    我错了。如果您使用一点递归,您可以启用和禁用对话框按钮。

    例如:

    import java.awt.Component;
    import java.awt.Container;
    import java.awt.event.*;
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.swing.*;
    
    public class Foo extends JPanel {
       private static final String[] DIALOG_BUTTON_TITLES = new String[] { "Aceptar", "Cancelar" };
       private JCheckBox checkBox = new JCheckBox("Buttons Enabled", true);
       private Set<AbstractButton> exemptButtons = new HashSet<AbstractButton>();
    
       public Foo() {
          JButton exemptBtn = new JButton("Exempt Button");
          JButton nonExemptBtn = new JButton("Non-Exempt Button");
    
          add(checkBox);
          add(exemptBtn);
          add(nonExemptBtn);
          exemptButtons.add(checkBox);
          exemptButtons.add(exemptBtn);
    
          checkBox.addActionListener(new ActionListener() {
    
             @Override
             public void actionPerformed(ActionEvent evt) {
                allBtnsSetEnabled(checkBox.isSelected());
             }
          });
    
       }
    
       private void allBtnsSetEnabled(boolean enabled) {
          JRootPane rootPane = SwingUtilities.getRootPane(checkBox);
          if (rootPane != null) {
             Container container = rootPane.getContentPane();
             recursiveBtnEnable(enabled, container);
          }
       }
    
       private void recursiveBtnEnable(boolean enabled, Container container) {
          Component[] components = container.getComponents();
          for (Component component : components) {
             if (component instanceof AbstractButton && !exemptButtons.contains(component)) {
                ((AbstractButton) component).setEnabled(enabled);
             } else if (component instanceof Container) {
                recursiveBtnEnable(enabled, (Container) component);
             }
          }
       }
    
       public int showDialog() {
          return JOptionPane.showOptionDialog(null, this, "Sirena",
                JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
                DIALOG_BUTTON_TITLES, "Aceptar");
       }
    
    
       private static void createAndShowGui() {
          Foo foo = new Foo();
          int result = foo.showDialog();
          System.out.println(DIALOG_BUTTON_TITLES[result]);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    

    此代码使用侦听器来检查 JCheckBox 的状态,但如果您想知道文本字段文档是否有数据,您可以让侦听器 (DocumentListeners) 侦听它们。然后代码获取保存 JCheckBox 的 JRootPane,然后是根窗格的 contentPane,对话框的所有组件都由它保存。然后它遍历对话框持有的所有组件。如果一个组件是一个容器,它会通过该容器递归。如果该组件是一个 AbstractButton(例如任何 JButton 或复选框),它会启用或禁用 -- 例外按钮集中的按钮除外。

    一个更好的文档监听器示例

    import java.awt.*;
    import java.awt.event.*;
    import java.util.HashSet;
    import java.util.Set;
    import javax.swing.*;
    import javax.swing.event.DocumentEvent;
    import javax.swing.event.DocumentListener;
    
    public class Foo2 extends JPanel {
       private static final String[] DIALOG_BUTTON_TITLES = new String[] {
             "Aceptar", "Cancelar" };
       private static final int FIELD_COUNT = 10;
       private Set<AbstractButton> exemptButtons = new HashSet<AbstractButton>();
       private JTextField[] fields = new JTextField[FIELD_COUNT];
    
       public Foo2() {
          setLayout(new GridLayout(0, 5, 5, 5));
          DocumentListener myDocListener = new MyDocumentListener();
          for (int i = 0; i < fields.length; i++) {
             fields[i] = new JTextField(10);
             add(fields[i]);
             fields[i].getDocument().addDocumentListener(myDocListener);
          }
    
          // cheating here
    
          int timerDelay = 200;
          Timer timer = new Timer(timerDelay , new ActionListener() {
    
             @Override
             public void actionPerformed(ActionEvent arg0) {
                checkDocsForText();            
             }
          });
          timer.setRepeats(false);
          timer.setInitialDelay(timerDelay);
          timer.start();
    
       }
    
       private void checkDocsForText() {
          for (JTextField field : fields) {
             if (field.getText().trim().isEmpty()) {
                allBtnsSetEnabled(false);
                return;
             }
          }
          allBtnsSetEnabled(true);
       }
    
       private void allBtnsSetEnabled(boolean enabled) {
          JRootPane rootPane = SwingUtilities.getRootPane(this);
          if (rootPane != null) {
             Container container = rootPane.getContentPane();
             recursiveBtnEnable(enabled, container);
          }
       }
    
       private void recursiveBtnEnable(boolean enabled, Container container) {
          Component[] components = container.getComponents();
          for (Component component : components) {
             if (component instanceof AbstractButton && !exemptButtons.contains(component)) {
                ((AbstractButton) component).setEnabled(enabled);
             } else if (component instanceof Container) {
                recursiveBtnEnable(enabled, (Container) component);
             }
          }
       }
    
       public int showDialog() {
          return JOptionPane.showOptionDialog(null, this, "Sirena",
                JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null,
                DIALOG_BUTTON_TITLES, "Aceptar");
       }
    
       private class MyDocumentListener implements DocumentListener {
    
          public void removeUpdate(DocumentEvent arg0) {
             checkDocsForText();
          }
    
          public void insertUpdate(DocumentEvent arg0) {
             checkDocsForText();
          }
    
          public void changedUpdate(DocumentEvent arg0) {
             checkDocsForText();
          }
       }
    
    
       private static void createAndShowGui() {
          Foo2 foo = new Foo2();
          int result = foo.showDialog();
          if (result >= 0) {
             System.out.println(DIALOG_BUTTON_TITLES[result]);
          }
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    
    }
    

    【讨论】:

      【解决方案2】:

      我建议你在 JPanel 扩展类中定义一些属性,并使用PropertyChangeListener 来监听发生的变化并启用/禁用相关按钮。

      这是article

      另一个问题可能是在组件的层次结构中找到确定/取消按钮,因为 JDialog 是通过 JOptionPane 创建的,并且您没有对按钮的引用。这是一个有用的thread

      您可以使用putClientProperty 方法将属性添加到JComponent。 当给定属性发生更改时,会引发 PropertyChanged 事件。

      因此,在您的示例中,您可以定义一个布尔属性,指示插入到 JDialog 中的必需项。然后添加一个 PropertyChangeListener,当收到通知时启用/禁用 ok 按钮。

      【讨论】:

        猜你喜欢
        • 2013-01-13
        • 2011-05-12
        • 1970-01-01
        • 1970-01-01
        • 2014-05-27
        • 1970-01-01
        • 2016-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多