2008-11-04 18 views
2

我有一個對話框,其中JTree中的每個條目在不同的面板中都有相應的選項,當選擇更改時會更新它。如果其中一個條目的選項設置爲無效狀態,則當用戶嘗試更改樹中的其他條目時,我希望出現錯誤對話框並且選擇不會更改。阻止JTree選擇發生變化的最佳方法是什麼?

我試着用JTree上的valueChangeListener做這件事,但是如果出現錯誤,當前必須讓valueChanged方法調用「setSelectionRow」到舊選擇。所以,我沒有得到一個StackOverflow,我這樣做之前設置布爾「isError」爲true,以便我可以忽略新的valueChanged事件。不知何故,我有直覺,這不是最好的解決方案。 ;-)

我該怎麼辦呢?這樣的情況有沒有好的設計模式?

回答

3

不確定這是最佳實踐,但也許您可以將FocusListener放置在要驗證的組件上(如果不想要),請在調用事件時調用驗證,然後使用事件由於驗證失敗,焦點將被移動?

後來編輯:

至少與Java 8(我沒有檢查更早版本)這種解決方案將無法工作,因爲FocusEvent不似乎是一個低級別事件。因此它不能被消耗。參見Method AWTEvent.consume()

+0

這是理想的方法,IMO – 2008-11-04 11:14:54

+0

也許是做那麼最好的方式。 – cagcowboy 2008-11-04 11:19:48

0

設置一個實現適當語義的TreeSelectionModel。

6

我沒有找到更好的方法,但這種方法對我來說工作得很好。 我知道在德爾福這是一個非常方便的事件:「改變選擇之前」,你可以很容易地停止改變選擇。

這裏是我的預防無限遞歸問題

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

永遠記住刪除您添加的所有聽衆,以防止內存泄漏的Java代碼。

這裏是另一種方法:

private class VetoableTreeSelectionModel extends DefaultTreeSelectionModel { 
    public void setSelectionPath(TreePath path){ 
     if (allow selection change?) { 
      super.setSelectionPath(path); 
     } 
    } 
} 
{ 
    navTree.setSelectionModel(new VetoableTreeSelectionModel()); 
} 
0

這是實現該包裝另一個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實現,但你明白了...

3

這是我的解決方案。

在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,否則,鼠標事件處理將照常進行並進行選擇。 總之,這使得鉛選擇屬性成爲約束屬性。

-1

在調查同一問題的解決方案時遇到了此線程。首先,讓我告訴你一些沒有用的東西。我試圖用樹來註冊MouseListeners和所有這些。問題在於TreeUI的鼠標監聽器在我的JTree之前正在處理該事件,這意味着設置一個標誌或類似的標誌爲時已晚。此外,這個解決方案產生了一些醜陋的代碼,我通常會避免它。

所以,現在的實際解決方案!
使用一些Thread.dumpStack()調用來獲取堆棧轉儲後,我發現我正在尋找重寫的方法。我擴展了BasicTreeUI並覆蓋了「protected void selectPathForEvent(TreePath path,MouseEvent event)」。

這會讓您在選擇實際發生之前訪問導致選擇的鼠標事件。然後,您可以使用任何需要的邏輯來調用event.consume(),如果要停止選擇,則可以使用返回值,通過調用super.selectPathForEvent(path,event)進行所需的選擇或將其傳遞給默認處理。

只記得設置你在JTree中創建的UI。這個錯誤浪費了我生命中的幾個小生命;-)

0

爲了防止選擇我只是子類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); 
} 

}

相關問題