Как расширить узлы JTree (заранее), но сделать их невидимыми

Мне кажется, что когда я звоню

JTree.expandPath(путь)

Что по умолчанию все его родители также расширены. Но что я на самом деле хочу сделать, так это заранее настроить конкретных невидимых дочерних элементов. Так что, когда узел расширяется, появляется его полное поддерево.

Я обнаружил, что внутри JTree expandedState.put(path, Boolean.TRUE); записываются расширенные узлы, но я не могу получить к ним доступ. (ps я не хочу использовать отражение :)

Установка прослушивателя для события расширения приведет к запуску большого количества обновлений во время выполнения. Вот почему я предпочитаю, чтобы JTree записывал расширенные состояния.

Надеюсь, что есть и другие способы сделать это.
Любая помощь приветствуется?

Принято решение Listener. Вариант 2

Вариант 1 Переопределение:

Один неприятный drawBack.. это зависит от реализации setExpandedState()

private boolean cIsExpandingHidden = false;
private TreePath cExpandingPath;

public void expandBranchHidden(DefaultMutableTreeNode node) {
  TreeNode[] mPathSections = mNode.getPath();
  TreePath mPath = new TreePath(mPathSections);
  //
  if (!cTree.isVisible(mPath)){
    cIsExpandingHidden = true;
  }
  cExpandingPath = mPath;
  try{
    expandPath(mPath);
  }finally{
    cExpandingPath = null;
    cIsExpandingHidden = false;
  }
}

@Override
public boolean isExpanded(TreePath path) {
  // override the questions whether the node parents of
  //  'the currently expanded node' to return TRUE
  if (cIsExpandingHidden){
    if (path.isDescendant(cExpandingPath)){
      return true; // just claim it doesn't need expanding
    }
  }
  return super.isExpanded(path);
}

@Override
public void fireTreeExpanded(TreePath path) {
  // the treeUI must not to know.. bad luck for any other listeners 
  if (!cIsExpandingHidden){
    super.fireTreeExpanded(path);
  }
}

Вариант 2 Слушатель

/* code where new nodes are received */
{
  // only if direct parent is expanded.. else expansionListener will pick it up
  if (cTree.isExpanded(mCreator.getParentTreeNode())){
    for (TreeNode mNode : mAddNodes) {
      if (mNode.isDefaultExpanded()) {
        cTree.expandBranch(mNode);
        mNode.setDefaultExpanded(false);
      }
    }
  }
}

/*  expansion listener */
{
  if (cRecursiveExpand){
    return;
  }
  // walk through children, expand and clear its preference
  cRecursiveExpand = true;
  IExtendedTreeNode[] mNodes = cTree.getChildrenOfCurrentNode();
  for (IExtendedTreeNode mNode : mNodes) {
    TreeNode mTreeNode = (TreeNode)mNode;
    if (mTreeNode.isDefaultExpanded()){
      cTree.expandBranch(mTreeNode);
      mTreeNode.setDefaultExpanded(false);
    }
  }
  cRecursiveExpand = false;
}

person Houtman    schedule 20.10.2009    source источник


Ответы (2)


Вам будет легче звонить

addTreeExpansionListener(TreeExpansionListener tel)

Когда вызывается метод treeExpanded(TreeExpansionEvent event) в вашем TreeExpansionListener, вы можете проверить, следует ли вам рекурсивно расширять все дочерние элементы для недавно расширенного TreePath.

person Sam Barnum    schedule 20.10.2009
comment
Это правда, но в вопросе конкретно упоминается этот подход и спрашивается, есть ли альтернатива, которая позволила бы дереву записывать состояния, а не запускать множество обновлений, когда что-то расширяется. - person CarlG; 21.10.2009
comment
Тем не менее, это правильный ответ. Может быть, он был на моем пути... Сэм, а ты? - person Houtman; 21.10.2009
comment
Накладные расходы на запуск этих TreeExpansionEvents будут минимальными, и они будут запускаться только при расширении или сворачивании узла. Код, вероятно, также будет более кратким. - person Sam Barnum; 21.10.2009
comment
На самом деле работает довольно хорошо. Я также включил решение Listener в свой вопрос. - person Houtman; 21.10.2009
comment
На самом деле это занимает меньше времени :) Поскольку мне нужно посещать только прямые дочерние элементы недавно расширенного узла, а не ВСЕ входящие/созданные узлы дерева. - person Houtman; 21.10.2009

Один из простых способов сделать это - создать подкласс JTree и переопределить метод

setExpandedState(TreePath path, boolean state)

В этом методе вместо раскрытия всех родителей расширяйте только те подпути, которые вы хотите расширить. Именно поэтому метод защищен :)

person Suraj Chandran    schedule 21.10.2009
comment
Я согласен, что это было бы удобно, так как оно защищено, но. переменная 'expandedState' является частной :( Но... я думаю, что я мог бы избежать рекурсивного расширения вверх, также переопределив 'isExpanded()', так как это используется для создания стека дел :) - person Houtman; 21.10.2009
comment
частный статический класс MyTree extends JTree { int rows[]; общественное MyTree (int rows []) { this.rows = rows; } protected void setExpandedState (путь TreePath, логическое состояние) { TreePath [] paths = new TreePath [rows.length]; for (int i = 0; i ‹ rows.length; i++) { paths[i] = this.getPathForRow(rows[i]); if (paths[i].isDescendant(путь)) { super.setExpandedState(путь, состояние); } else { // ничего не делать } } } } Хорошо... теперь вы должны отдать мне свой голос :) - person Suraj Chandran; 21.10.2009
comment
Хорошо, вот и все :) Хотя ваше решение не совсем то, что мне нужно. - person Houtman; 21.10.2009