Лучший способ остановить изменение выбора JTree? - PullRequest
2 голосов
/ 04 ноября 2008

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

Я попытался сделать это с помощью valueChangeListener на JTree, но в настоящее время необходимо иметь вызов метода valueChanged "setSelectionRow" для старого выбора в случае ошибки. Чтобы я не получил StackOverflow, перед тем, как сделать это, я установил для логического значения «isError» значение true, чтобы можно было игнорировать новое событие valueChanged. Почему-то у меня такое чувство, что это не лучшее решение. ; -)

Как бы я поступил вместо этого? Есть ли хороший шаблон дизайна для подобных ситуаций?

Ответы [ 7 ]

6 голосов
/ 22 февраля 2009

Я не нашел лучшего способа, но этот подход прекрасно работает для меня. Я знаю, что в Delphi это было очень удобное событие: «до изменения выбора», где вы могли очень легко прекратить изменять выбор.

вот мой код Java с предотвращением бесконечной проблемы рекурсии

    navTree.addTreeSelectionListener(new TreeSelectionListener() {

        boolean treeSelectionListenerEnabled = true;

        public void valueChanged(TreeSelectionEvent e) {
            if (treeSelectionListenerEnabled) {
                if (ok to change selection...) {
                    ...
                } else {
                    TreePath treePath = e.getOldLeadSelectionPath();
                    treeSelectionListenerEnabled = false;
                    try {
                        // prevent from leaving the last visited node
                        navTree.setSelectionPath(treePath);
                    } finally {
                        treeSelectionListenerEnabled = true;
                    }
                }
            }
        }
    });

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

вот другой подход:

private class VetoableTreeSelectionModel extends DefaultTreeSelectionModel {
    public void setSelectionPath(TreePath path){
        if (allow selection change?) {
            super.setSelectionPath(path);
        }
    }
}
{
    navTree.setSelectionModel(new VetoableTreeSelectionModel());
}
3 голосов
/ 01 июля 2010

Вот мое решение.

В подклассе JTree:

protected void processMouseEvent(MouseEvent e) {
        TreePath selPath = getPathForLocation(e.getX(), e.getY());
        try {
            fireVetoableChange(LEAD_SELECTION_PATH_PROPERTY, getLeadSelectionPath(), selPath);
        }
        catch (PropertyVetoException ex) {
            // OK, we do not want change to happen
            return;
        }

        super.processMouseEvent(e);
}

Затем в дереве используется класс:

VetoableChangeListener vcl = new VetoableChangeListener() {

        public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
            if ( evt.getPropertyName().equals(JTree.LEAD_SELECTION_PATH_PROPERTY) ) {
                try {
                    <some code logic that has to be satisfied>
                } catch (InvalidInputException e) {
                    throw new PropertyVetoException("", evt);
                }

            }
        }
    };
    tree.addVetoableChangeListener(vcl);

Механизм запускается как можно раньше. Действие мыши перехвачено, путь, который будет выбран, объявляется VetoableChangeListeners. В конкретном VCL проверяется изменяющееся свойство, и если это выбор отведений, проверяется вето логика. Если требуется вето, VCL создает исключение PropertyVetoException, в противном случае обработка события мыши происходит как обычно, и происходит выбор. Короче говоря, это делает свойство выбора отведений ограниченным свойством.

3 голосов
/ 04 ноября 2008

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

Позже Редактировать:

По крайней мере с java 8 (я не проверял более ранние версии) это решение не будет работать, потому что FocusEvent, по-видимому, не является событием низкого уровня. Следовательно это не может быть потреблено. См. Метод AWTEvent.consume ()

0 голосов
/ 07 января 2012

Чтобы предотвратить выбор, я просто создал подкласс DefaultTreeSelectionModel и переопределил все методы, чтобы проверить объекты, которые я не хотел выбирать (примеры «DisplayRepoOwner» в моем примере ниже). Если объект был в порядке, я выбрал супер метод; в противном случае я не сделал. Я установил модель выбора моего JTree на экземпляр этого подкласса.

public class MainTreeSelectionModel extends DefaultTreeSelectionModel {
public void addSelectionPath(TreePath path) {
    if (path.getLastPathComponent() instanceof DisplayRepoOwner) {
        return;
    }
    super.addSelectionPath(path);
}
public void addSelectionPaths(TreePath[] paths) {
    for (TreePath tp : paths) {
        if (tp.getLastPathComponent() instanceof DisplayRepoOwner) {
            return;
        }
    }
    super.addSelectionPaths(paths);
}
public void setSelectionPath(TreePath path) {
    if (path.getLastPathComponent() instanceof DisplayRepoOwner) {
        return;
    }
    super.setSelectionPath(path);
}
public void setSelectionPaths(TreePath[] paths) {
    for (TreePath tp : paths) {
        if (tp.getLastPathComponent() instanceof DisplayRepoOwner) {
            return;
        }
    }
    super.setSelectionPaths(paths);
}

}

0 голосов
/ 11 сентября 2010

Наткнулся на эту тему, изучая решение той же проблемы. Во-первых, позвольте мне рассказать вам вещи, которые не сработали. Я попытался зарегистрировать MouseListeners и все это в дереве. Проблема заключалась в том, что слушатели мыши TreeUI обрабатывали событие раньше, чем мой JTree, то есть было слишком поздно устанавливать флаг или что-то в этом роде. Кроме того, это решение дало некрасивый код, и я бы его вообще избегал.

Так что теперь для фактического решения!
После нескольких вызовов Thread.dumpStack () для получения дампа стека я нашел метод, который искал для переопределения. Я расширил BasicTreeUI и переопределил «защищенный void selectPathForEvent (путь TreePath, событие MouseEvent)».

Это даст вам доступ к событию мыши, которое вызвало выделение до того, как оно произойдет. Затем вы можете использовать любую логику, в которой вы нуждаетесь, либо event.consume (), и возвращать, если хотите остановить выбор, сделать любой выбор или передать его для обработки по умолчанию, вызвав super.selectPathForEvent (path, event);

Просто не забудьте установить интерфейс, который вы создали в JTree. Эта ошибка потратила впустую несколько минут моей жизни; -)

0 голосов
/ 04 марта 2009

Вот пример реализации TreeSelectionModel, которая оборачивает другую TreeSelectionModel, но допускает вето на выбор:

public class VetoableTreeSelectionModel implements TreeSelectionModel
{
   private final ListenerList<VetoableTreeSelectionListener> m_vetoableTreeSelectionListeners = new ListenerList<VetoableTreeSelectionListener>();

   private final DefaultTreeSelectionModel m_treeSelectionModel = new DefaultTreeSelectionModel();

   /**
    * {@inheritDoc}
    */
   public void addTreeSelectionListener(final TreeSelectionListener listener)
   {
      m_treeSelectionModel.addTreeSelectionListener(listener);
   }

   /**
    * {@inheritDoc}
    */
   public void removeTreeSelectionListener(final TreeSelectionListener listener)
   {
      m_treeSelectionModel.removeTreeSelectionListener(listener);
   }

   /**
    * Add a vetoable tree selection listener
    *
    * @param listener the listener
    */
   public void addVetoableTreeSelectionListener(final VetoableTreeSelectionListener listener)
   {
      m_vetoableTreeSelectionListeners.addListener(listener);
   }

   /**
    * Remove a vetoable tree selection listener
    *
    * @param listener the listener
    */
   public void removeVetoableTreeSelectionListener(final VetoableTreeSelectionListener listener)
   {
      m_vetoableTreeSelectionListeners.removeListener(listener);
   }

   /**
    * {@inheritDoc}
    */
   public void addPropertyChangeListener(final PropertyChangeListener listener)
   {
      m_treeSelectionModel.addPropertyChangeListener(listener);
   }

   /**
    * {@inheritDoc}
    */
   public void removePropertyChangeListener(final PropertyChangeListener listener)
   {
      m_treeSelectionModel.removePropertyChangeListener(listener);
   }

   /**
    * {@inheritDoc}
    */
   public void addSelectionPath(final TreePath path)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToAddSelectionPath(path);
            }});

         m_treeSelectionModel.addSelectionPath(path);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void addSelectionPaths(final TreePath[] paths)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToAddSelectionPaths(paths);
            }});

         m_treeSelectionModel.addSelectionPaths(paths);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void clearSelection()
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToClearSelection();
            }});

         m_treeSelectionModel.clearSelection();
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public TreePath getLeadSelectionPath()
   {
      return m_treeSelectionModel.getLeadSelectionPath();
   }

   /**
    * {@inheritDoc}
    */
   public int getLeadSelectionRow()
   {
      return m_treeSelectionModel.getLeadSelectionRow();
   }

   /**
    * {@inheritDoc}
    */
   public int getMaxSelectionRow()
   {
      return m_treeSelectionModel.getMaxSelectionRow();
   }

   /**
    * {@inheritDoc}
    */
   public int getMinSelectionRow()
   {
      return m_treeSelectionModel.getMinSelectionRow();
   }

   /**
    * {@inheritDoc}
    */
   public RowMapper getRowMapper()
   {
      return m_treeSelectionModel.getRowMapper();
   }

   /**
    * {@inheritDoc}
    */
   public int getSelectionCount()
   {
      return m_treeSelectionModel.getSelectionCount();
   }

   public int getSelectionMode()
   {
      return m_treeSelectionModel.getSelectionMode();
   }

   /**
    * {@inheritDoc}
    */
   public TreePath getSelectionPath()
   {
      return m_treeSelectionModel.getSelectionPath();
   }

   /**
    * {@inheritDoc}
    */
   public TreePath[] getSelectionPaths()
   {
      return m_treeSelectionModel.getSelectionPaths();
   }

   /**
    * {@inheritDoc}
    */
   public int[] getSelectionRows()
   {
      return m_treeSelectionModel.getSelectionRows();
   }

   /**
    * {@inheritDoc}
    */
   public boolean isPathSelected(final TreePath path)
   {
      return m_treeSelectionModel.isPathSelected(path);
   }

   /**
    * {@inheritDoc}
    */
   public boolean isRowSelected(final int row)
   {
      return m_treeSelectionModel.isRowSelected(row);
   }

   /**
    * {@inheritDoc}
    */
   public boolean isSelectionEmpty()
   {
      return m_treeSelectionModel.isSelectionEmpty();
   }

   /**
    * {@inheritDoc}
    */
   public void removeSelectionPath(final TreePath path)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutRemoveSelectionPath(path);
            }});

         m_treeSelectionModel.removeSelectionPath(path);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void removeSelectionPaths(final TreePath[] paths)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutRemoveSelectionPaths(paths);
            }});

         m_treeSelectionModel.removeSelectionPaths(paths);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void resetRowSelection()
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToResetRowSelection();
            }});

         m_treeSelectionModel.resetRowSelection();
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void setRowMapper(final RowMapper newMapper)
   {
      m_treeSelectionModel.setRowMapper(newMapper);
   }

   /**
    * {@inheritDoc}
    */
   public void setSelectionMode(final int mode)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToSetSelectionMode(mode);
            }});

         m_treeSelectionModel.setSelectionMode(mode);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void setSelectionPath(final TreePath path)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToSetSelectionPath(path);
            }});

         m_treeSelectionModel.setSelectionPath(path);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   public void setSelectionPaths(final TreePath[] paths)
   {
      try
      {
         m_vetoableTreeSelectionListeners.fireVetoableEvent(new VetoableAction<VetoableTreeSelectionListener>() {
            public void fireEvent(final VetoableTreeSelectionListener listener) throws EventVetoedException
            {
               listener.aboutToSetSelectionPaths(paths);
            }});

         m_treeSelectionModel.setSelectionPaths(paths);
      }
      catch (final EventVetoedException e)
      {
         return;
      }
   }

   /**
    * {@inheritDoc}
    */
   @Override
   public String toString()
   {
      return m_treeSelectionModel.toString();
   }

}

И вот слушатель, чтобы пойти с ним:

public interface VetoableTreeSelectionListener
{
   /**
    * About to add a path to the selection
    *
    * @param path the path to add
    *
    * @throws EventVetoedException
    */
   void aboutToAddSelectionPath(TreePath path) throws EventVetoedException;

   /**
    * About to add paths to the selection
    *
    * @param paths the paths to add
    *
    * @throws EventVetoedException
    */
   void aboutToAddSelectionPaths(TreePath[] paths) throws EventVetoedException;

   /**
    * About to clear selection
    *
    * @throws EventVetoedException
    */
   void aboutToClearSelection() throws EventVetoedException;

   /**
    * About to remove a selection path
    *
    * @param path the path
    *
    * @throws EventVetoedException
    */
   void aboutRemoveSelectionPath(TreePath path) throws EventVetoedException;

   /**
    * About to remove multiple selection paths
    *
    * @param paths the paths
    *
    * @throws EventVetoedException
    */
   void aboutRemoveSelectionPaths(TreePath[] paths) throws EventVetoedException;

   /**
    * About to reset the row selection
    *
    * @throws EventVetoedException
    */
   void aboutToResetRowSelection() throws EventVetoedException;

   /**
    * About to set the selection mode
    *
    * @param mode the selection mode
    *
    * @throws EventVetoedException
    */
   void aboutToSetSelectionMode(int mode) throws EventVetoedException;

   /**
    * About to set the selection path
    *
    * @param path the path
    *
    * @throws EventVetoedException
    */
   void aboutToSetSelectionPath(TreePath path) throws EventVetoedException;

   /**
    * About to set the selection paths
    *
    * @param paths the paths
    *
    * @throws EventVetoedException
    */
   void aboutToSetSelectionPaths(TreePath[] paths) throws EventVetoedException;
}

Вы можете использовать свою собственную реализацию ListenerList, но вы поняли ...

0 голосов
/ 05 ноября 2008

Установите TreeSelectionModel, который реализует соответствующую семантику.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...