Java/Swing では、合法的に「通知内で変更を試みる」方法はありますか?
-
02-10-2019 - |
質問
IllegalStateException を回避し、JTextField が「通知内で変更を試みる」こと、つまりリスナーがトリガーされた場合に独自のテキストを設定できるようにするために使用できる何らかの魔法があるかどうか疑問に思っていました。
参考までに、JTextField でのユーザーの入力に応じて、12 の列挙型の範囲で最も一致する可能性の高いものを返すオートコンプリート関数をプログラムしようとしています。
コードサンプルは次のとおりです。列挙型の結果が不器用なアルゴリズムであることはご容赦ください。例外を生成するコードをコメントで強調表示しました。
jtfElement1.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
String s = jtfElement1.getText();
int[] attributes = new int[13];
// iterate through each enum
for (BaseEnumAttributes b: BaseEnumAttributes.values()) {
// iterate through the length of the current text in jtfElement1
for (int i = 0; i < s.length(); i++) {
if (s.length() <= b.toString().length()) {
if (b.toString().charAt(i) == s.charAt(i)) {
// increase the number of "hits" noted for that enum
attributes[b.ordinal()] = attributes[b.ordinal()] + 1;
}
}
}
}
int priorC = 0;
int rightC = 0;
// iterate through the "array" of enums to find the highest score
for (int j = 0; j < attributes.length; j++) {
if (attributes[j] > priorC) {
priorC = attributes[j];
rightC = j;
}
}
if (!s.equals("")) {
// assign to b the Enum corresponding to the "array" with highest score
BaseEnumAttributes b = BaseEnumAttributes.values()[rightC];
iController.updateInputElement1String(b.toString());
// THIS TRIGGERS EXCEPTION
jtfElement1.setText(b.toString());
}
}
});
解決
おそらく、ドキュメント フィルターまたはカスタム ドキュメントを使用する方がよいでしょう。
イベントのディスパッチ中にドキュメントが同じままでない場合、他のリスナーは何を確認することが期待されますか?
他のヒント
SwingUtilities.invokeLater() を使用して、すべての変更をそこに配置します
たぶん、caretUpdate() が終了した後に実行するスレッドを使用して setText() を遅らせることができます。
私も同じ問題を抱えていますが、簡単な解決策を見つけました。
テキストを jTextField に設定している間は、後にロックを解除するよりも、ブール値の if(false) によって CaretUpdate() をロックします。。このようなもの:
ブール値キャレット = true;
private void listValueChanged(javax.swing.event.listselectionevent evt){caret = false;name.setText((String)list.getSelectedValue());キャレット = true;}
private void nameCaretUpdate(javax.swing.event.CaretEvent evt) {
if(caret){
model = new DefaultListModel();
this.fillList(name.getText());
list.setModel(model);
}
}
カスタム Document を作成し、insertString( ) をオーバーライドします。
filenameText = new JTextField(new FilenameDocument(), "", 0);
...
/**
* document which adds .xml extension if not specified
*
*/
private class FilenameDocument extends PlainDocument {
@Override
public void insertString(int offset, String insertedText, AttributeSet set)
throws BadLocationException {
if (offset == 0) {
insertedText = insertedText.trim( );
}
super.insertString(offset, insertedText, set);
if (filenameText != null) {
final int caretPos = filenameText.getCaretPosition();
String text = filenameText.getText().trim();
if (text.indexOf('.') == -1) {
filenameText.setText(text + ".xml");
filenameText.setCaretPosition(caretPos);
}
}
}
}
setText を呼び出すと、insertString( ) への再帰呼び出しが行われるため、停止条件があることを確認してください。
誰もこれに答えなかったのには驚きましたが、編集可能なものを実装したほうが良かったのではないかと思います。 Jスピナー とともに スピナーリストモデル?