将JTextField与Model(在focusLost上)一起使用,并使用模型数据运行Actions

时间:2010-12-03 10:57:12

标签: java swing jtextfield

我有一个Java Swing应用程序,它有许多JTextField和一个数据模型。

当离开文本字段(焦点丢失)时,文本将写入模型。到目前为止,非常好。

有JMenu-Actions从模型中读取数据并将其发送到服务器。

问题是,当它的加速器运行菜单操作时,不会触发“焦点丢失”。因此,Actions从数据模型中读取并传输旧值。

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

什么对我不起作用:

  • 在每次按键时写入模型(通过文档侦听器):不可用,只应在离开文本字段时写入(焦点丢失)。在将文本写入模型后(昂贵地)评估文本 - 在每次按键后都无法运行。
  • 在每个动作中处理对模型的写入。有大约500 Textfields和ca. 100个动作。在不忘记任何事情的情况下进行匹配。

Runnable演示代码:

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();
      }
    });
  }

}

2 个答案:

答案 0 :(得分:2)

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

  

在将文本写入模型

之后(昂贵地)评估该文本

此外,听起来你也应该处理focusGained。然后可以保存原始文本并在自动更新模型之前对焦点丢失的文本进行比较。 (即如果有人只是浏览所有文本字段会怎么样?)。

答案 1 :(得分:1)

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

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

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