Обработка долгосрочных задач EDT (например, поиск по TreeModel) - PullRequest
4 голосов
/ 21 февраля 2012

Trigger - недавно обнаруженная проблема 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)
 } 

К вашему сведению: перекрестная публикация на форуме Swing OTN и форуме SwingLabs - попытается опубликовать сводку всех вводимых данных в конце (если они есть: -)

Приложение

В конце дняОказалось, что я задал неправильный вопрос (или правильный вопрос в неправильном контексте ;-): «проблема» возникла из-за предполагаемого решения, реальная задача, которую нужно решить, - это поддержка алгоритма иерархического поиска (верно).теперь AbstractSearchable сильно искажен при линейном поиске.)

Как только это будет решено, следующий вопрос может заключаться в том, сколько фреймворк может сделать для поддержки конкретных иерархических поисковых запросов.Учитывая разнообразие пользовательских реализаций TreeModels, это, скорее всего, возможно только для самых простых.

Некоторые мысли, которые возникли в дискуссиях здесь и на других форумах.В конкретном контексте, сначала измерьте , если обход идет медленно: большинство моделей в памяти молниеносно перемещаются, ничего не нужно делать, кроме как с использованием базовой поддержки.

Только еслиОбход является узким местом (как, например, в реализациях FileSystemModel SwingX), требуется дополнительная работа:

  • в действительно неизменяемой и неизменяемой модели TreeModel, которой мы могли бы избежать доступа только для чтения в фоновом потоке SwingWorker
  • неизменяемое предварительное условие нарушается в сценариях с отложенной загрузкой / удалением
  • может существовать естественная структура пользовательских данных, которая поддерживает модель, которая фактически отчасти "отделена" от фактической модели, что позволяетсинхронизация с этой моделью поддержки (как в модели обхода, так и в модели представления)
  • передает фактический поиск обратно в базу данных
  • использует оболочку поверх заданной модели TreeModel, которая гарантирует доступ к базовой модели приEDT
  • «поддельный» фоновый поиск: actделайте это в достаточно маленьких блоках на EDT (например, в таймере), чтобы пользователь не заметил никакой задержки

Независимо от технической опции медленного поиска, есть та же проблема юзабилитирешить: как представить задержку конечному пользователю?И это совсем другая история, возможно, даже в большей степени зависящая от контекста / требований: -)

1 Ответ

3 голосов
/ 21 февраля 2012

И SwingWorker, и TreeModel должны синхронизировать доступ к общему базовому DataModel. Создание общих квантов данных (эффективно) неизменяемыми может минимизировать накладные расходы. Поскольку это сильно зависит от приложения, я не уверен, какую поддержку может предложить представление для поиска невидимых узлов.

...