Java 对模型使用JTextField(在focusLost上)并对模型数据运行操作

Java 对模型使用JTextField(在focusLost上)并对模型数据运行操作,java,swing,jtextfield,Java,Swing,Jtextfield,我有一个JavaSwing应用程序,它有许多JTextFields和一个datamodel 离开文本字段(焦点丢失)时,文本将写入模型。到目前为止,一切顺利 有一些JMenu操作从模型中读取数据并将其发送到服务器 问题在于,通过加速器运行菜单操作时,“焦点丢失”不会触发。因此,操作从数据模型读取并传输旧值 有很多方法可以解决这个问题。。。?您是否有建议如何解决此问题 什么对我不起作用: 每次按键时写入模型(通过文档侦听器):不可用,应仅在离开文本字段时写入(焦点丢失)。文本在写入模型后进行(昂

我有一个JavaSwing应用程序,它有许多JTextFields和一个datamodel

离开文本字段(焦点丢失)时,文本将写入模型。到目前为止,一切顺利

有一些JMenu操作从模型中读取数据并将其发送到服务器

问题在于,通过加速器运行菜单操作时,“焦点丢失”不会触发。因此,操作从数据模型读取并传输旧值

有很多方法可以解决这个问题。。。?您是否有建议如何解决此问题

什么对我不起作用:

  • 每次按键时写入模型(通过文档侦听器):不可用,应仅在离开文本字段时写入(焦点丢失)。文本在写入模型后进行(昂贵的)评估-不能在每次按键后运行
  • 在每个动作中处理对模型的写入。大约有500个文本字段和100个操作。很难匹配而不忘记任何东西

可运行的演示代码:

package swingmodel;

import java.awt.FlowLayout;
import java.awt.event.*;

import javax.swing.*;

/**
 * Simple Demo Problem. Enter a Text in the first Textfield and press ALT-T. The
 * focus listener did no run, therefore the old value from model is displayed.
 */
public class TextDemoOnMenu extends JPanel {
  private Model model;

  public TextDemoOnMenu() {
    super(new FlowLayout());

    model = new Model();
    MyTextField textField = new MyTextField(20, model);
    add(textField);
    add(new JTextField(5));

  }

  class MyTextField extends JTextField {

    private Model model;

    public MyTextField(int arg, Model model) {
      super(arg);
      this.model = model;
      addFocusListener(new FocusAdapter() {
        @Override
        public void focusLost(FocusEvent e) {
          System.out.println("focus lost");
          writeToModel();
        }
      });
    }

    public void writeToModel() {
      this.model.setText(getText());
    }
  }

  class ShowModelTextAction extends AbstractAction {

    public ShowModelTextAction(String string) {
      super(string);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
      String message = "text is: " + model.getText();
      JOptionPane.showMessageDialog(TextDemoOnMenu.this, message);
    }
  }

  class Model {
    private String text;

    void setText(String t) {
      text = t;
    }

    public String getText() {
      return text;
    }
  }

  private void createAndShowGUI() {
    // Create and set up the window.
    JFrame frame = new JFrame("TextDemo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    // Add contents to the window.
    frame.add(this);

    Action action = new ShowModelTextAction("show text");
    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("My Menu");
    menuBar.add(menu);
    JMenuItem menuItem = new JMenuItem("show text");
    menuItem.setAction(action);
    menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.ALT_MASK));
    menu.add(menuItem);
    frame.setJMenuBar(menuBar);

    // Display the window.
    frame.setSize(400, 200);
    frame.setVisible(true);
  }


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

}

为每个文本字段创建一个脏标志。如果发生保存事件,您可以使用任何脏文本字段更新模型

如果您担心您会“忘记”为特定的文本字段执行此操作,那么问题在于您对文本字段的管理。您应该为它们提供一个工厂方法,该方法可以正确设置它们并为它们创建脏标志


我的另一个建议是,当保存操作发生时,您向隐藏组件请求焦点,以触发textField上的focusLost。保存完成后,您会将焦点返回给以前的所有者

为每个文本字段创建一个脏标志。如果发生保存事件,您可以使用任何脏文本字段更新模型

如果您担心您会“忘记”为特定的文本字段执行此操作,那么问题在于您对文本字段的管理。您应该为它们提供一个工厂方法,该方法可以正确设置它们并为它们创建脏标志


我的另一个建议是,当保存操作发生时,您向隐藏组件请求焦点,以触发textField上的focusLost。保存完成后,您会将焦点返回给以前的所有者

您可以修改所有操作以使用KeyboardFocusManager。您将获得具有焦点的当前组件。如果它是自定义文本字段之一,则可以在处理操作之前强制更新模型

将文本写入模型后,对其进行(昂贵的)评估


而且,听起来你也应该处理焦点问题。然后可以保存原始文本,并在自动更新模型之前对焦点丢失的文本进行比较。(即,如果有人只是在所有文本字段中进行制表符操作会怎么样?)

您可以修改所有操作以使用KeyboardFocusManager。您将获得具有焦点的当前组件。如果它是自定义文本字段之一,则可以在处理操作之前强制更新模型

将文本写入模型后,对其进行(昂贵的)评估

而且,听起来你也应该处理焦点问题。然后可以保存原始文本,并在自动更新模型之前对焦点丢失的文本进行比较。(即,如果有人只是在所有文本字段中进行了制表符操作怎么办?)