Best way to stop a JTree selection change from hap

2019-02-15 19:09发布

I have a dialog where each entry in a JTree has its corresponding options in a different panel, which is updated when the selection changes. If options for one of the entries is set to an invalid state, when the user attempts to change to a different entry in the tree, I want there to be an error dialog and have the selection not change.

I tried doing this with a valueChangeListener on the JTree, but currently then have to have the valueChanged method call "setSelectionRow" to the old selection if there is an error. So that I don't get a StackOverflow, I set a boolean "isError" to true before I do this so that I can ignore the new valueChanged event. Somehow I have the gut feeling this is not the best solution. ;-)

How would I go about it instead? Is there a good design pattern for situations like this?

7条回答
家丑人穷心不美
2楼-- · 2019-02-15 19:53

Here is an example of implementing a TreeSelectionModel that wraps another TreeSelectionModel but allows selection to be vetoed:

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();
   }

}

And here is the listener to go with it:

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;
}

You can use your own implementation of ListenerList, but you get the idea...

查看更多
登录 后发表回答