Обработка длительных задач EDT (например, поиск по TreeModel)
Триггер - это недавно обнаруженная проблема SwingX: поддержка глубокая - то есть под свернутыми узлами, а не только для видимых узлов, что является текущим поведением - поиск узлов.
"Nichts leichter als das" со всем моим текущим знакомством с SwingWorker: прогуляйтесь по TreeModel в фоновом потоке и обновите пользовательский интерфейс в процессе, как показано в сыром фрагменте ниже. Средство проверки EDT в Fest достаточно счастливое, но затем проверяет только перерисовку (что хорошо происходит на EDT здесь)
Только... строго говоря, этот фоновый поток должен быть EDT, поскольку он обращается (к чтению) к модели. Итак, вопросы:
- как реализовать поиск по теме - правильно?
- или мы можем жить с этим риском (конечно, с большим количеством документов)
Одна возможность для решения в особом случае будет иметь вторую (клонированную или иначе "сделанную") модель для поиска, а затем найти соответствующие совпадения в "реальной" модели. Это не слишком хорошо работает с общей поддержкой поиска, так как она не может ничего знать о какой-либо конкретной модели, то есть не может создать клона, даже если она этого хочет. Плюс к этому придется применить все виды сортировки / фильтрации (в будущем) ...
// 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, это, скорее всего, возможно только для самых простых.
Некоторые мысли, которые возникли в дискуссиях здесь и на других форумах. В конкретном контексте, прежде всего, измерьте, если обход идет медленно: большинство моделей в памяти молниеносно просматривают, ничего не нужно делать, кроме как с использованием базовой поддержки.
Только если обход является узким местом (как, например, в реализациях FileSystemModel SwingX), необходима дополнительная работа:
- в действительно неизменяемом и неизменяемом TreeModel мы могли бы получить доступ только для чтения в фоновом потоке SwingWorker
- неизменяемое предусловие нарушается в сценариях отложенной загрузки / удаления
- может существовать естественная пользовательская структура данных, которая поддерживает модель, которая фактически отчасти "отделена" от фактической модели, которая позволяет синхронизироваться с этой моделью поддержки (как в модели обхода, так и в модели представления)
- передать фактический поиск обратно в базу данных
- использовать обертку поверх заданной TreeModel, которая гарантирует доступ к базовой модели в EDT
- "поддельный" фоновый поиск: на самом деле делайте это в достаточно маленьких блоках на EDT (например, в таймере), чтобы пользователь не заметил никакой задержки
Какой бы ни была техническая опция для медленного поиска, нужно решить одну и ту же проблему: как представить задержку конечному пользователю? И это совсем другая история, возможно, даже в большей степени зависящая от контекста / требований:-)
1 ответ
И то и другое SwingWorker
а также TreeModel
следует синхронизировать доступ к общему, основному DataModel
, Создание общих квантов данных (эффективно) неизменяемыми может минимизировать накладные расходы. Поскольку это сильно зависит от приложения, я не уверен, какую поддержку может предложить представление для поиска невидимых узлов.