トリガーは最近再検出されたSwingXの問題です:サポートディープ-現在の動作である表示ノードのみではなく、折りたたまれたノードの下にあります-ノード検索。
「Nichtsleichteralsdas」と、SwingWorkerへの現在のすべての露出:以下の大まかなスニペットに示すように、バックグラウンドスレッドでTreeModelをウォークし、処理中のUIを更新します。FestのEDTチェッカーは十分に満足していますが、再描画のみをチェックします(これは、ここのEDTでうまく行われています)。
厳密に言えば、そのバックグラウンドスレッドは、モデルにアクセスしている(読み取ることによって)ため、EDTである必要があります。したがって、質問は次のとおりです。
- 検索スレッドを正しく実装する方法は?
- または、そのリスクを抱えて生きることができますか(もちろん、詳細に文書化されています)
特殊なケースのソリューションの1つの可能性は、検索用の2番目の(クローンまたは「同じ」作成の)モデルを用意し、「実際の」モデルで対応する一致を見つけることです。これは、特定のモデルについて何も知ることができないため、一般的な検索サポートではうまく機能しません。つまり、必要な場合でもクローンを作成することはできません。さらに、すべてのビューの並べ替え/フィルタリングを適用する必要があります(将来)...
// a crude worker (match hard-coded and directly coupled to the ui)
public static class SearchWorker extends SwingWorker<Void, File> {
private Enumeration enumer;
private JXList list;
private JXTree tree;
public SearchWorker(Enumeration enumer, JXList list, JXTree tree) {
this.enumer = enumer;
this.list = list;
this.tree = tree;
}
@Override
protected Void doInBackground() throws Exception {
int count = 0;
while (enumer.hasMoreElements()) {
count++;
File file = (File) enumer.nextElement();
if (match(file)) {
publish(file);
}
if (count > 100){
count = 0;
Thread.sleep(50);
}
}
return null;
}
@Override
protected void process(List<File> chunks) {
for (File file : chunks) {
((DefaultListModel) list.getModel()).addElement(file);
TreePath path = createPathToRoot(file);
tree.addSelectionPath(path);
tree.scrollPathToVisible(path);
}
}
private TreePath createPathToRoot(File file) {
boolean result = false;
List<File> path = new LinkedList<File>();
while(!result && file != null) {
result = file.equals(tree.getModel().getRoot());
path.add(0, file);
file = file.getParentFile();
}
return new TreePath(path.toArray());
}
private boolean match(File file) {
return file.getName().startsWith("c");
}
}
// its usage in terms of SwingX test support
public void interactiveDeepSearch() {
final FileSystemModel files = new FileSystemModel(new File("."));
final JXTree tree = new JXTree(files);
tree.setCellRenderer(new DefaultTreeRenderer(IconValues.FILE_ICON, StringValues.FILE_NAME));
final JXList list = new JXList(new DefaultListModel());
list.setCellRenderer(new DefaultListRenderer(StringValues.FILE_NAME));
list.setVisibleRowCount(20);
JXFrame frame = wrapWithScrollingInFrame(tree, "search files");
frame.add(new JScrollPane(list), BorderLayout.SOUTH);
Action traverse = new AbstractAction("worker") {
@Override
public void actionPerformed(ActionEvent e) {
setEnabled(false);
Enumeration fileEnum = new PreorderModelEnumeration(files);
SwingWorker worker = new SearchWorker(fileEnum, list, tree);
PropertyChangeListener l = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
//T.imeOut("search end ");
setEnabled(true);
((SwingWorker) evt.getSource()).removePropertyChangeListener(this);
}
}
};
worker.addPropertyChangeListener(l);
// T.imeOn("starting search ... ");
worker.execute();
}
};
addAction(frame, traverse);
show(frame)
}
参考: OTNのSwingフォーラムとSwingLabsフォーラムへのクロスポスト-最後にすべての入力の要約を投稿しようとします(ある場合:-)
補遺
結局のところ、私は間違った質問(または間違ったコンテキストでの正しい質問;-)をしたことが判明しました:「問題」は想定された解決策によって発生しました。解決すべき実際のタスクは階層検索アルゴリズムをサポートすることです(現在、AbstractSearchableは線形検索で大きく歪んでいます)。
それが解決したら、次の質問は、具体的な階層型検索可能ファイルをサポートするためにフレームワークがどれだけできるかということかもしれません。TreeModelsのさまざまなカスタム実装を考えると、それはおそらく最も単純な場合にのみ可能です。
ここや他のフォーラムでの議論で浮かび上がったいくつかの考え。具体的なコンテキストでは、最初にトラバーサルが遅いかどうかを測定します。ほとんどのメモリ内モデルはトラバースが非常に高速であり、基本的なサポートを使用する以外に何もする必要はありません。
トラバーサルがボトルネックである場合(SwingXのFileSystemModel実装のfiのように)のみ、追加の作業が必要です。
- 真に不変で変更不可能なTreeModelでは、SwingWorkerのバックグラウンドスレッドでの読み取り専用アクセスを回避できる可能性があります
- 遅延読み込み/削除シナリオでは、変更できない前提条件に違反しています
- モデルを裏付ける自然なカスタムデータ構造が存在する可能性があります。これは、実際のモデルから事実上「切り離された」ものであり、その裏付けモデル(トラバーサルモデルとビューモデルの両方)への同期を可能にします。
- 実際の検索をデータベースに戻します
- 特定のTreeModelの上にラッパーを使用して、EDTの基になるモデルへのアクセスを保証します
- 「偽の」バックグラウンド検索:実際には、EDT(タイマーのfi)の十分に小さいブロックで実行して、ユーザーが遅延に気付かないようにします。
低速検索の技術的なオプションが何であれ、解決すべき同じユーザビリティの問題があります。エンドユーザーに遅延を提示する方法は?そして、それはまったく別の話であり、おそらくさらにコンテキスト/要件に依存します:-)