Связь между кнопками JOptionPane и пользовательской панелью - PullRequest
4 голосов
/ 06 января 2012

Я создал диалоговое окно множественного ввода, построив 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, параметры определяются по типу Look and Feel

Итак, я не могу передать пользовательские кнопки в качестве параметра?

Похоже, мне придется сделать свой собственный JDialog? для какого случая я не знаю, как заставить его вернуть int, как это делает JOptionPane, какой-либо рекомендуемый учебник?

В примере options - это {"Aceptar", "Cancelar"}, которые являются отображаемыми кнопками,

PS. Я полностью контролирую поля, добавленные в JPanel.

Это скриншот панели JOptionPane:

enter image description here

Ответы [ 2 ]

2 голосов
/ 07 января 2012

Я не думаю, что вы можете деактивировать кнопки выбора 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) прослушивание документов текстового поля, если вы хотите знать, есть ли у них данные или нет.Затем код получает JRootPane, который содержит JCheckBox, затем 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 голосов
/ 06 января 2012

Я предлагаю вам определить некоторые свойства в вашем расширенном классе JPanel и использовать PropertyChangeListener для прослушивания произошедших изменений и включения / отключения относительных кнопок.

Вот статья .

Другой проблемой может быть нахождение кнопок ok / cancel в иерархии компонентов, поскольку JDialog создается через JOptionPane, а у вас нет ссылки на кнопки.Вот полезный поток .

. Вы можете добавить свойство в JComponent, используя метод putClientProperty .Когда в данном свойстве происходят изменения, возникает событие PropertyChanged.

Таким образом, в вашем примере вы можете определить логическое свойство, обозначающее обязательные, которые вставляются в JDialog.Затем добавьте PropertyChangeListener, который при получении уведомления включает / отключает кнопку ОК.

...