Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > Поиск по элементам дерева


Автор: cube 5.6.2008, 10:38
Я реализовал свое дерево расширив JTree, в него добавил поиск по элементам дерева. При нажатии на клавишу показываю попап в котором текстовое поле, при вводе значений в который, проверяю есть ли в названии узлов(нод) слово начинающееся также, если есть устанавливаю выделение на этот узел(ноду).

 Это все работает, вот только вопрос как при больших деревьях, прокручивать еще содержимое дерева, чтобы выделенный узел (нода) всегда была в поле видимости пользователя?

дерево реализовал вот так:
Код

public class Tree extends JTree {
  
  private JPopupMenu searchPopup = new JPopupMenu();       // всплывающее меню 
  private JTextField searchText = new JTextField();                   // поле в который пользователь вводит текст для поиска
  private ArrayList<Node> matches = new ArrayList<Node>(); // список в котором я храню все узлы которые соответствуют поиску
  
  public Tree() 
 {
    searchPopup.setLayout(new BorderLayout());
    searchText.setColumns(5);
    searchPopup.add(new JLabel(" найти "), BorderLayout.WEST);
    searchPopup.add(searchText, BorderLayout.EAST);
    setComponentPopupMenu(searchPopup);
    initEvents();                                                                         //инициализация событий
  }

  private void initEvents()
  {
    final JTree my = this;
    searchText.getDocument().addDocumentListener(new DocumentListener() {
      public void insertUpdate(DocumentEvent e){search(e);}
      public void removeUpdate(DocumentEvent e){search(e);}
      public void changedUpdate(DocumentEvent e){search(e);}
    });
    searchText.addKeyListener(new KeyAdapter() {
      @Override
      public void keyPressed(KeyEvent e)
      {
// выделяю узлы соответсвующие поиску при нажатии на клавыши вниз или вверх из текстового поля
        if (getSelectedNodes().length>0 && (KeyEvent.VK_DOWN == e.getKeyCode() || KeyEvent.VK_UP == e.getKeyCode()))
        {
           int i = matches.indexOf(getSelectedNodes()[0]);
           if(KeyEvent.VK_DOWN == e.getKeyCode())selectMatch(++i); // выделение следуещего
           else selectMatch(--i); // выделение предыдущего
        }
      }
    });
    
    this.addKeyListener(new KeyAdapter() {
      @Override
      public void keyPressed(KeyEvent e)
      {
// если нажата клавиша символа на дереве показываю форму поиска
        if (Character.isLetter(e.getKeyChar()))
        {
          searchPopup.show(my, 90, 0);
          searchText.grabFocus();
        }
      }
    });
  }
  
  private void search(DocumentEvent e)
  {
    matches.clear(); // очищаю ранее найденные результаты
    search((Node)getModel().getRoot()); // начинаю поиск
    selectMatch(0); // выделяю первый найденный результат
  }
  
  private void search(Node parent)
  {
    for (int i=0; i<getModel().getChildCount(parent);i++)
    {
      Node child = (Node)getModel().getChild(parent, i);
      if (child.getLabel().getText().toLowerCase().startsWith(searchText.getText().toLowerCase())) // добавляю узел в список соответствующих поиску
        matches.add(child);
      if (child.getChildCount()>0) search(child); // рекурсия
    }
  }
  
  private void selectMatch(int index) 
  {
// если список найденных узлов не пуст и идекс соответствует размерности списка выделяю путь к этому узлу
    if (!matches.isEmpty() && index<matches.size() && index>=0)
        setSelectionPath(new TreePath(matches.get(index).getPath()));
  }

.... другие методы....
}


Автор: dorogoyIV 5.6.2008, 12:04
Код

  TreePath path = tree.getSelectionPath();
  Rectangle rect = tree.getPathBounds(path);
  ((JViewport)tree.getParent()).setViewPosition(new Point(rect.x, rect.y));//это если дерево лежит на JScrollPane

Автор: cube 5.6.2008, 13:43
Цитата(dorogoyIV @ 5.6.2008,  12:04)
Код

  TreePath path = tree.getSelectionPath();
  Rectangle rect = tree.getPathBounds(path);
  ((JViewport)tree.getParent()).setViewPosition(new Point(rect.x, rect.y));//это если дерево лежит на JScrollPane

Спасибо большое! Работает, но вот только этот вьюпорт устанавливает на столько жестко, что курсор (при выделении) остается на одном месте, как бы дерево перемещаеться вокруг выделенного элемента... 

есть уже готовое решение как сделать это явление нормальным?

Автор: dorogoyIV 5.6.2008, 13:57
ну попробуй еще jViewport.scrollRectToVisible(java.awt.Rectangle contentRect)

если не получится код покажи

Автор: cube 5.6.2008, 14:27
Цитата(dorogoyIV @ 5.6.2008,  13:57)
ну попробуй еще jViewport.scrollRectToVisible(java.awt.Rectangle contentRect)

если не получится код покажи

(((( неработает
 
вот метод selectMatch() в котором я выделяю узел соответствующий поиску

Код

  private void selectMatch(int index)
  {
    if (!matches.isEmpty() && index<matches.size() && index>=0)
    {
      TreePath path = new TreePath(matches.get(index).getPath()); // получаю путь к узлу
      setSelectionPath(path); // выделяю его
      Rectangle rect = getPathBounds(path); 
      JViewport viewport = (JViewport)getParent();
      viewport.scrollRectToVisible(rect);
    }
  }


спасибо!

на рисунке показано мое дерево в режиме поиска

Автор: cube 5.6.2008, 14:37
Еще срабатывает вот так:

Автор: dorogoyIV 5.6.2008, 14:46
Цитата(cube @  5.6.2008,  13:43 Найти цитируемый пост)
 Работает, но вот только этот вьюпорт устанавливает на столько жестко, что курсор (при выделении) остается на одном месте, как бы дерево перемещаеться вокруг выделенного элемента... 

не понятно, у меня нормально скроллится
показал бы весь GUI

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)