【问题标题】:Pattern for swing information exchange between two JFrames两个 JFrame 之间交换信息的模式
【发布时间】:2024-01-12 06:26:01
【问题描述】:

他们是如何设计的,即 JFileChooser?

JFileChooser chooser = new JFileChooser();
int returnVal = chooser.showOpenDialog(this);
if(returnVal == JFileChooser.APPROVE_OPTION) {
  System.out.println("You chose to open this file: " +
                chooser.getSelectedFile().getName());

我该如何设计这样一个具有信息交换功能的框架。例如,我有 Frame1 和 Frame2。 Frame1 打开 Frame2。 Frame2 有一个 JTextArea,我将在其中设置一些文本并对其进行编辑。在 frame2 中按下 ok 按钮后,它被关闭,我想要 Frame1 中的变量中的文本。

或者说我是否要制作一个字体选择器对话框。

JOptionPane 不适合我。在 frame2 中,我将有一个 HTML 编辑器。在 frame1 我有 JTable。单击表格上的一行将打开带有 HTML 编辑器的 frame2。我为此使用SHEF。当我按 OK/Save 按钮关闭 frame2 时,我想要 frame1 中的 html 文本 String。并相应地设置行内容。但是 frame2 可以是一个模态对话框。

【问题讨论】:

    标签: java swing design-patterns jframe


    【解决方案1】:

    看看"Event Driven Programming":不是组件之间的紧密耦合(每个组件都必须知道每个其他组件),您可以发送事件并且组件可以响应它们。

    【讨论】:

      【解决方案2】:

      首先阅读The Use of Multiple JFrames: Good or Bad Practice?

      然后阅读How to make dialogs

      JFileChooser 是一个组件,它有一个显示对话框的方法。您的需求可能不同,但这不是一个糟糕的模式,因为它不会让您的组件开始需要始终显示在对话框中

      更新

      您可以使用JOptionPane

      import java.awt.EventQueue;
      import javax.swing.JOptionPane;
      import javax.swing.JTextField;
      import javax.swing.UIManager;
      import javax.swing.UnsupportedLookAndFeelException;
      
      public class TestOptionPane12 {
      
          public static void main(String[] args) {
              new TestOptionPane12();
          }
      
          public TestOptionPane12() {
              EventQueue.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                      }
      
                      JTextField field = new JTextField();
                      int option = JOptionPane.showConfirmDialog(null, field, "Fill it out", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
                      switch (option) {
                          case JOptionPane.OK_OPTION:
                              System.out.println("You entered " + field.getText());
                              break;
                      }
      
                  }
      
              });
          }
      
      }
      

      或者您可以创建更自定义的解决方案...

      import java.awt.BorderLayout;
      import java.awt.Component;
      import java.awt.EventQueue;
      import java.awt.GridBagLayout;
      import java.awt.Window;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import javax.swing.JButton;
      import javax.swing.JDialog;
      import javax.swing.JOptionPane;
      import javax.swing.JPanel;
      import javax.swing.JTextField;
      import javax.swing.SwingUtilities;
      import javax.swing.UIManager;
      import javax.swing.UnsupportedLookAndFeelException;
      
      public class TestOptionPane12 {
      
          public static void main(String[] args) {
              new TestOptionPane12();
          }
      
          public TestOptionPane12() {
              EventQueue.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                      } catch (ClassNotFoundException ex) {
                      } catch (InstantiationException ex) {
                      } catch (IllegalAccessException ex) {
                      } catch (UnsupportedLookAndFeelException ex) {
                      }
      
                      FieldsPane pane = new FieldsPane();
                      switch (pane.showDialog(null)) {
                          case JOptionPane.OK_OPTION:
                              String text = pane.getText();
                              System.out.println("You entered: " + text);
                              break;
                      }                
                  }
              });    
          }
      
          protected class FieldsPane extends JPanel {
      
              private JTextField field;
              private int state = JOptionPane.CANCEL_OPTION;
      
              public FieldsPane() {
                  setLayout(new GridBagLayout());
                  field = new JTextField(10);
                  add(field);
              }
      
              public String getText() {
                  return field.getText();
              }
      
              public int showDialog(Component parent) {
      
                  JButton btnOkay = new JButton("Ok");
                  JButton btnCancel = new JButton("Cancel");
                  JPanel buttons = new JPanel();
                  buttons.add(btnOkay);
                  buttons.add(btnCancel);
      
                  btnOkay.addActionListener(new ActionListener() {
                      @Override
                      public void actionPerformed(ActionEvent e) {
                          state = JOptionPane.OK_OPTION;
                          Window win = SwingUtilities.getWindowAncestor((Component)e.getSource());
                          win.dispose();
                      }
                  });
                  btnCancel.addActionListener(new ActionListener() {
                      @Override
                      public void actionPerformed(ActionEvent e) {
                          state = JOptionPane.CANCEL_OPTION;
                          Window win = SwingUtilities.getWindowAncestor((Component)e.getSource());
                          win.dispose();
                      }
                  });
      
                  JDialog dialog = new JDialog(parent == null ? (Window)null : SwingUtilities.getWindowAncestor(parent), "Fill it out");
                  dialog.setModal(true);
                  dialog.add(this);
                  dialog.add(buttons, BorderLayout.SOUTH);
                  dialog.pack();
                  dialog.setLocationRelativeTo(null);
                  dialog.setVisible(true);
      
                  return state;            
              }        
          }    
      }
      

      更新了 JOptionPane 和 JEditorPane 示例

      import java.awt.BorderLayout;
      import java.awt.Component;
      import java.awt.Dimension;
      import java.awt.EventQueue;
      import java.awt.GridBagLayout;
      import java.awt.Window;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import javax.swing.JButton;
      import javax.swing.JDialog;
      import javax.swing.JEditorPane;
      import javax.swing.JOptionPane;
      import javax.swing.JPanel;
      import javax.swing.JScrollPane;
      import javax.swing.JTextField;
      import javax.swing.SwingUtilities;
      import javax.swing.UIManager;
      import javax.swing.UnsupportedLookAndFeelException;
      
      public class TestOptionPane12 {
      
          public static void main(String[] args) {
              new TestOptionPane12();
          }
      
          public TestOptionPane12() {
              EventQueue.invokeLater(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                      } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                      }
      
                      JEditorPane editorPane = new JEditorPane("text/html", null);
                      JScrollPane scrollPane = new JScrollPane(editorPane);
                      scrollPane.setPreferredSize(new Dimension(200, 200));
                      int option = JOptionPane.showConfirmDialog(null, scrollPane, "Fill it out", JOptionPane.OK_CANCEL_OPTION, -1);
                      switch (option) {
                          case JOptionPane.OK_OPTION:
                              System.out.println("You entered " + editorPane.getText());
                              break;
                      }
      
                  }
      
              });
          }
      }
      

      【讨论】:

      • 还要考虑无模式对话框中的观察者模式,参见here
      • 我想要 JDialog。但我仍然需要一个模式来处理 OK、Cancel 或其他事件,并在我的 Frame1 类中获取文本或其他更多对象。
      • 从创建组件开始,可能使用JPanel,将你的文本字段添加到它。提供获取文本的 getter 方法。创建一个方法来创建一个对话框
      • 在没有 cmets 的情况下,一定会喜欢否决票。帮助我们,发表评论,以便我们讨论解决问题的方法
      • JOptionPane 不适合我。我在我的问题中添加了对该问题的更多描述。
      【解决方案3】:

      使其成为多个对话框而不是框架,然后阅读中介模式:

      http://blue-walrus.com/2013/06/mediator-pattern-in-swing/

      您的基本问题是您有一个组件层次结构,并且一个分支上的组件希望与另一个遥远分支上的组件通信。您需要某种中介对象来在这些遥远的分支之间进行通信。

      【讨论】:

        【解决方案4】:

        您可以创建特殊的类来保存结果。比如:

        public class Result {
            private String result;
        
            public void setResult(String result) { ... }
        
            public String getResult() { ... }
        }
        

        在第一帧创建此类的实例并将其传递给第二帧。在关闭第二帧时设置结果,然后第一帧可以得到它。

        【讨论】:

        • 我明白了。但是 JFileChooser 方法对我来说似乎更干净、更容易。