2009-09-23 86 views
1

這是情況,我有一個帶有選項卡窗格的jFrame,並且在選項卡內有一對jTable和一個jTree。我希望能夠根據用戶是否使用ctrl/shift + click與常規點擊來鏈接表和樹之間的選擇。 (如果按住ctrl並單擊第一個表格/樹,則會添加到整體選區,如果您使用常規單擊,則會清除其他表格/樹中的選區)。目前我遇到了Java的jTree組件問題。我添加了一個TreeSelectionListener和一個MouseListener,它實現了兩個接口,稱之爲MyBigListener; 即MouseEvent之前的Java JTree valueChanged事件

MyBigListener listener = new MyBigListener(); 
jTree1.addMouseListener(listener); 
jTree1.addTreeSelectionListener(listener); 

MyBigListener implements TreeSelectionListener, MouseListener { 
    private boolean chained = false; 
    public synchronized setChained(boolean ch){ 
    chained = ch; 
    } 
    public synchronized boolean isChained(){ 
    return chained 
    } 
    public void valueChanged(TreeSelectionEvent e){ 
    if(isChained()){ blah... } 
    } 

    public void mousePressed(MouseEvent e){ 
    setChained(e.isControlDown() || e.isShiftDown()); 
    } 
} 

我的計劃是,如果用戶使用CTRL /轉向設置一個布爾標誌+單擊我可以在的valueChanged(TreeSelectionEvent E)期間檢查由樹選擇監聽器來實現。 我想能夠在valueChanged TreeSelectionEvents之前處理鼠標事件,但問題是我在valueChanged treeSelection事件後收到鼠標事件。這對我來說似乎很奇怪,我在鼠標按下事件觸發前收到選擇更改,當選擇更改實際上是通過按下鼠標啓動的。 (我已經同步了布爾標誌設置,這很諷刺地幫助突出了事件的錯誤順序)。

我已經嘗試過添加keyListener之類的替代方法,但是當焦點位於一個單獨的框架,當用戶按住CTRL鍵時,我會點擊它,然後點擊進入jTree,從而使它接收焦點並觸發任何valueChanged選擇事件。

任何幫助將不勝感激,謝謝!

- 編輯 - @akf 我有一個標籤面板充當用於在結節 - 圖數據的摘要/控制面板獨立JTable中和jTrees。我在標籤式窗格中使用這些組件來協調選擇顯示在單獨的jFrame中的圖形。單獨使用jTree,每張桌子的工作情況都很好。它是棘手的窗格之間的協調。這到目前爲止工作正常與jTable組件,因爲我作爲一個MouseEvent的結果觸發新的選擇,我可以判斷shift/ctrl按鈕是否關閉,制定我的新選擇,並將它傳遞給父框架,協調所有窗格並將最終選擇發送到圖形。然而,父母需要知道它是否需要在窗格之間鏈接選擇,或擠壓其他窗格。隨着jTables的再次罰款,因爲我觸發選擇的變化,作爲一個鼠標點擊的結果。 jTree更是一個問題,因爲我正在做一些強制選擇。如果你點擊一個分支,它會強制所有葉子進入選擇。我需要實現一個TreeSelectionListener來做到這一點,但只得到一個valueChanged(TreeSelectionEvent)來實現變化。我添加了一個mouseListener來監聽ctrl + clicks和shift + clicks,但顯然這些事件並不總是以相同的順序發生..至少目前爲止我在mousePressed事件之前收到了valueChanged事件,因此檢查是否一個ctrl +在選擇已被修改後,點擊發生的帖子。

現在,我發佈一個未決的選擇更改,然後讓MouseListener抓住它並將它發送到鏈上,但是如果這些事件不能保證以相同的順序發生,在某些時候它會發生失敗。實現延時器也會讓我誤以爲是。

感謝您的幫助。

--EDIT2-- @ykaganovich

我想重寫fireValueChanged方法更接近於正確的方式去了解的東西。根據我對什麼操作應該導致對其他組件進行「鏈接」選擇的定義,我需要收集一些關於在valuateChanged方法觸發前發生的情況的上下文。這基本上意味着在所有情況下我都可以自己調用它來定義觸發它的人是什麼意思。即如果一個鼠標事件導致它,並按下Ctrl然後設置我需要設置(解釋),然後激發。如果由於鍵盤事件而發生更改,請再次設置我需要設置的內容,然後啓動。我不認爲TreeSelectionModel是要走的路,因爲我仍然不知道事件發生時的情況。我認爲這意味着我需要重寫jTree的部分來做到這一點,但我想我會看看它是怎麼回事。謝謝。

+0

你是否試圖使用樹,就好像它是表中的第一列,並試圖在整個樹和表組件中進行選擇,就像它們是一樣? – akf 2009-09-24 02:21:27

回答

1

落實不這樣做的,覆蓋JTree.fireValueChanged代替。

嘗試這樣的事情(未經測試):

class ChainedSelectionEvent extends TreeSelectionEvent { 
    ChainedSelectionEvent(TreeSelectionEvent e) { 
    super(e.newSource, e.paths, e.areNew, e.oldLeadSelectionPath, e.newLeadSelectionPath); 
    } 
} 

protected void fireValueChanged(TreeSelectionEvent e) { 
    if(chained) { // figure out separately 
     super.fireValueChanged(new ChainedSelectionEvent(e)); 
    } else { 
     super.fireValueChanged(e); 
    } 
} 

然後檢查的instanceof ChainedSelectionEvent在監聽

編輯

其實我覺得這樣做的正確方法是實施你自己的TreeSelectionModel,並重寫那裏的fireValueChanged。假設setSelectionPath(s)方法意味着一個新的選擇,並且add/removeSelectionPath(s)意味着鏈接,您可以乾淨地區分這兩者。我不喜歡直接聽鍵盤或鼠標事件,因爲改變選擇的方法不止一種(例如,如果有人按住SHIFT並按下向下箭頭,則不會獲得鼠標事件)。

+0

我想我仍然會遇到同樣的問題,無法確定選擇是否應該鏈接,因爲事件發生不按順序。誰控制着fireValueChanged的調用?樹本身?如果我不需要,我不想完全重寫jTree,儘管我已經把它添加到了拖放支持中。嗯...我想我可以在我的樹中重載它,在那裏實現一個MouseListener,並且只是作爲鼠標事件的結果調用這個方法,但是然後選擇分支collapse/expand變得更加棘手..我想我討厭jTrees :) – user49913 2009-09-24 15:28:55

+0

我認爲這應該工作。由JTree調用fireValueChanged來響應選擇。我不認爲你應該永遠不得不明確地處理MouseEvents。 – ykaganovich 2009-09-24 18:52:40

+0

我需要處理MouseEvents,因爲這是我知道用戶是否按住shift或ctrl按鈕時添加/刪除某些東西的唯一方法。這是我對什麼時候鏈接的定義。我同意它不乾淨,但我可以讓KeyListener基本上做同樣的事情來捕獲這些事件並做出響應。 對於我何時鏈接或不鏈接的定義,我想我需要捕捉用戶可以修改選擇的所有方式,並在允許選擇更改觸發之前瞭解發生了什麼情況。謝謝您的幫助。 – user49913 2009-09-24 22:07:56

1

您可能會在樹選擇事件之前或之後獲得鼠標事件。最好不要依賴這樣的訂單。原因是樹選擇事件是響應鼠標事件而引起的。那個鼠標事件監聽器是在你的監聽器之前還是之後調用的?可能是。

這種事情是密切參與的PL & F.

0

這裏的關鍵是理解一個JTree與BasicTreeUI.MouseHandler一起交付,請參閱javax.swing.plaf.basic.BasicTreeUI。

要回答中心問題,「什麼引發fireValueChanged」,答案是「這個鼠標處理程序」......當你轉到tree.getMouseListeners()時,它變成唯一的鼠標監聽器。

所以你必須用你自己的版本替換這個默認的鼠標監聽器...這是一個有點棘手。我使用Jython,每個人都需要發現它。此代碼應該不會太困難但是翻譯成Java:

from javax.swing.plaf.basic import BasicTreeUI  
    def makeMouseHandlerClass(): 
    class MouseHandlerClass(BasicTreeUI.MouseHandler): 
     def mousePressed(self, mouseEvent): 
     genLog.info("mouse handler MOUSE PRESSED!") 
     nTFSelf.mousePressedStatus = True 
     BasicTreeUI.MouseHandler.mousePressed(self, mouseEvent) 
     nTFSelf.mousePressedStatus = False 

    return MouseHandlerClass 
    suppliedMouseHandler = nTFSelf.taskTree.mouseListeners[ 0 ] 
    nTFSelf.taskTree.removeMouseListener(suppliedMouseHandler ) 
    nTFSelf.taskTree.addMouseListener(makeMouseHandlerClass()(nTFSelf.taskTree.getUI())) 

...基本上相應的Java這裏將BasicTreeUI.MouseHandler延伸MyMouseHandler,然後在最後一行用新MyMouseHandler替換( tree.getUI())...「nTFSelf」這裏僅僅是代碼的「this」對象的引用,其中所有這些都被寫入...