0

多くの JTextField とデータモデルを持つ Java Swing アプリケーションがあります。

テキストフィールドを離れる (フォーカスが失われる) と、テキストがモデルに書き込まれます。ここまでは順調ですね。

モデルからデータを読み取り、それをサーバーに送信する 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();
      }
    });
  }

}
4

2 に答える 2

2

すべてのアクションを変更して、KeyboardFocusManager を使用することができます。フォーカスのある現在のコンポーネントを取得します。カスタム テキスト フィールドの 1 つである場合は、アクションを処理する前にモデルを強制的に更新できます。

テキストは、モデルに書き込んだ後に (高価に) 評価されます。

また、focusGained も処理する必要があるようです。次に、元のテキストを保存し、モデルを自動的に更新する前に、フォーカスが失われたテキストを比較できます。(つまり、誰かがすべてのテキスト フィールドをタブで移動したらどうなるでしょうか?)。

于 2010-12-03T16:56:17.387 に答える
1

textField ごとにダーティ フラグを作成します。保存イベントが発生した場合、ダーティな textField でモデルを更新できます。

特定のテキストフィールドに対してこれを行うのを「忘れる」のではないかと心配している場合、問題はテキストフィールドの管理です。それらを正しく設定し、それらのダーティフラグを作成するファクトリメソッドが必要です。

私の他の提案は、その保存アクションが発生したときに、非表示のコンポーネントにフォーカスをリクエストして、textField で focusLost をトリガーすることです。保存が完了したら、フォーカスを前の所有者に戻します。

于 2010-12-03T13:35:51.177 に答える