0

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

离开文本字段(失去焦点)时,文本将写入模型。到现在为止还挺好。

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

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

可能有很多方法可以解决这个问题......?你有建议如何解决这个问题吗?

什么对我不起作用:

  • 在每次按键时写入模型(通过文档侦听器):不可用,只能在离开文本字段时写入(焦点丢失)。在将文本写入模型后(昂贵地)评估文本 - 每次按键后都无法运行。
  • 处理写作以在每个动作中建模。那里约。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();
      }
    });
  }

}
4

2 回答 2

2

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

在将文本写入模型后(昂贵地)评估文本

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

于 2010-12-03T16:56:17.387 回答
1

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

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

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

于 2010-12-03T13:35:51.177 回答