Swing架構之Renderer(三)

來源:互聯網
上載者:User

http://blog.csdn.net/chosen0ne/archive/2009/08/16/4453510.aspx

前面文章提到過,許多複合資料型組件不僅僅需要展現資料,還需要編輯資料。比如JTable的某些儲存格可能需要編輯,JComboBox除了選擇外還可以直接編輯資料,有些JTree有時也需要直接編輯節點。Swing中解決此類問題的方案叫做所謂的in-place
editor。Swing綜合in-place
editor和Renderer原理賦予了Swing擴充複雜組件功能的能力。注意in-place
editor其實只是普通的Swing組件,並不是新的Swing元素,它們往往結合Renderer完成組件的擴充,所以我把它們和Renderer放在一起講了。

  Swing可以使用In-place editor的兩個前提條件是:

  1. Swing組件需要能脫離容器組件獨立存在;
  2. Swing組件樹能在運行時動態地被修改,包括添加和刪除。
                                                                              

  Swing組件樹就像瀏覽器的HTML
DOM樹一樣,可以通過指令碼語言JavaScript進行動態修改,從而達到瀏覽器頁面的局部更新的功能,Swing通過動態往容器組件中添加或者刪除編輯組件實現複合類型組件的in-place
editor功能。

 
所有Swing組件都是直接或者間接繼承自JComponent,而JComponent是Container類的一個子類,因此所有的Swing組件都
可看作一個容器組件。複合資料型別的組件也是如此,它們內部往往擁有自己的子結構、布局管理器、為實現某種功能而隱藏了的子組件(比如前篇文章中所提到的
CellRendererPane)等。複合資料型別的組件通過動態修改自己內部組件樹結構實現in-place editor。

  In-place
editor的生命週期包括啟用、編輯、停止編輯、取消編輯、刪除編輯器等。下面以JTable為例詳細瞭解In-place
editor的工作過程。

  首先要瞭解JTable的in-place
editor介面TableCellEditor的定義:

public interface TableCellEditor
extends CellEditor {
   
/*該方法返回JTable當前表格的編輯組件,該組件根據提供的參數table、value、isSelected、row、column進行配置。注
意,對該組件的調用有可能會導致停止編輯,丟失尚未編輯完的資料。該組件將作為JTable的子組件添加到組件樹上,之後就可以接受使用者的輸入了。*/
   
Component getTableCellEditorComponent(JTable table,
Object value,
      
boolean
isSelected,
       int
row, int column);
}

public interface CellEditor
{
/*返回編輯器內的值,必須是編輯後有效值,用在JTable中作為擷取編輯結果用*/

   
public Object
getCellEditorValue();
/*讓編輯器判斷anEvent是否能啟用編輯動作,anEvent使用的是JTable組件座標系,這兒編輯器不能假設
getCellEditorComponent返回的組件已經安裝在JTable中。如果當前事件觸發編輯表現方式,則返回true,否則false。*/

   
public boolean isCellEditable(EventObject
anEvent);
/*該方法同前一方法類似,只不過是判斷該事件是否允許選中當前格。大多數情況下,這兒直接返回true,因為一般如果可編輯,就應該允許被選中。然而有
些情況下編輯表現方式發生時,並不想改變表格的選中狀態。比如,使用者可能想改變checkbox編輯器的值,卻並不想因為要點擊checkbox而改變
JTable當前選中的其他行。*/

   
public boolean shouldSelectCell(EventObject
anEvent);
/*停止編輯器的編輯,接受部分編輯的值作為編輯結果值。如果編輯不能停止,則返回false,這對於編輯器檢查正在編輯的值是否有效,是否能接受無效值時很有效。*/

   
public boolean
stopCellEditing();
/*告訴編輯器取消編輯,不要使用任何部分編輯過的值*/

   
public void
cancelCellEditing();
/*添加CellEditorListener,當編輯器停止或者取消編輯表現方式時觸發該處理器*/

   
public void addCellEditorListener(CellEditorListener
l);/*刪除CellEditorListener*/
   
public void removeCellEditorListener(CellEditorListener
l);
}

   再看一下CellEditorListener的定義:

public interface
CellEditorListener extends java.util.EventListener
{
   
/*通知編輯器已經停止編輯,編輯效果生效。*/
    public
void editingStopped(ChangeEvent
e);
   
/*通知編輯器已經取消編輯,編輯效果被取消*/
    public
void editingCanceled(ChangeEvent e);
}

  
當滑鼠雙擊之類引起編輯的事件發生時,JTable的啟用編輯器的過程可用下面的圖來示意:

 
首先檢查當前是否正在編輯。如果正在編輯,則調用TableCellEditor的stopCellEditing來結束編輯。
stopCellEditing如果不能正常結束,則返回false,這時便把焦點重新置放給該編輯器,並結束。如果當前不是正在編輯,或者雖然正在編
輯,但是stopCellEditing正常結束了,則判斷當前的滑鼠事件是否是滑鼠拖動行為。如果是則調用mousePressedDND方法處理。否
則說明該事件有可能引發編輯功能。接著調用TableModel.isCellEditable判斷該目前的儲存格是否允許編輯。如果允許編輯,則獲得當前
儲存格的TableCellEditor,調用其isCellEditable判斷當前滑鼠事件是否意味著啟用編輯(比如規定雙擊意味著啟用編輯、單擊並
不啟用等)。如果是啟用編輯事件,則從TableCellEditor.getTableCellEditorComponent擷取編輯組件,最後將該
組件添加到組件樹上,添加適當的處理器、有效化之後等待使用者輸入。

 
TableCellEditor的stopCellEditing方法通常會刪除當前編輯器。上面過程中,如果JTable正在處於編輯中,滑鼠的點擊則
會導致調用TableCellEditor的stopCellEditing方法刪除編輯器,並開始新的編輯器的安裝過程。
stopCellEditing在這個過程中擷取編輯器的值並把它賦予JTable。其工作過程如下:

 
tableCellEditing的stopCellEditing(左邊)先檢查目前編輯組件的值是否有效(比如輸入的整數是否越界)。如無效則
(有時需要提示使用者)返回false。如果有效則將該值作為editor的最終值儲存起來,以備JTable通過
editor.getCellEditorValue調用。然後觸發編輯停止事件fireEditingStopped。由於JTable在安裝編輯器
時,總把自己註冊為它的CellEditorListener處理器,因此當JTable能接到該通知。之後JTable就在其
editingStopped(右邊)方法中處理該事件。JTable首先使用editor.getCellEditorValue獲得該
editor編輯好的值,並調用setValueAt將該值更新到目前的儲存格,最後調用removeEditor刪除該編輯器。控制返回到
TableCellEditor的stopCellEditing(左邊圖)後,stopCellEditing返回true結束整個過程。

   
TableCellEditor還會發出另一個事件fireEditingCanceled。這經常出現在編輯器本身有所謂取消功能編輯組件上。比如想在
按下ESC鍵時取消當前正在編輯的值,就可以調用TableCellEditor的cancelEditing來取消。cancelEditing的工作
過程比較簡單,往往是直接通過fireEditingCanceled觸發取消動作,偵聽的JTable會在其editingCanceled方法中簡單
將編輯器刪除去,繼續保留以前的值。

 
理解TableCellEditor介面的方法之間的關係對於編寫自己的Editor很重要,它們之間除了上面注釋所描述的含義外,還有一些暗示的關係編寫程式時需要注意:

1.
在自訂編輯器的stopCellEditing中要檢查編輯組件正在編輯資料的有效性。如有效,要通過fireEditingStopped之類方法通
知註冊在此編輯器上的介面。如果沒有觸發,JTable將不能正常工作,編輯的值也會被丟失。最後要返回true作為成功的標識;如果資料沒有效,一般做
法是提示使用者錯誤,使用者確認錯誤提示後要要把焦點重新置放到編輯組件上,並返回false作為失敗的標識。

2.注意在fireEditingStopped調用之前,getCellEditorValue返回的值一定要是當前有效值。因為JTable會緊跟其後,調用該方法將編輯好的值填入表中並刪除當前編輯器。

3.cancelCellEditing一般什麼都不做,簡單的fireEditingCanceled就行了。JTable響應該事件僅僅是簡單的刪除編輯器。

4.
要實現方法addCellEditorListener和removeCellEditorListener,而不能空著它們,並且要定義
fireEditingStopped和fireEditingCanceled兩個方法以便在stopCellEditing和
cancelCellEditing方法中使用它們觸發事件。

5.getTableCellEditorComponent
返回的組件需要添加適當的事件處理器,該處理器在使用者編輯確認時(比如JTextField在敲斷行符號引發ActionPerformed時),應該
stopCellEditing以此來通知這次編輯過程已經完成,需要更新到JTable中。

 
TableCellEditor介面暗含許多內部關係,如果不能正確建立它們之間的關係,實現往往並不能複合你的需求。

    
JTree的TreeCellEditor介面和TableCellEditor除了擷取編輯組件的方法的參數有所不同外,其他完全相同,其工作過程也類似。

  除了JTable和JTree外,JComboBox也有in-place
editor,它的editor介面相對簡單一些:

public
interface ComboBoxEditor {
/*返回編輯的組件*/
public
Component
getEditorComponent();
/*設定要編輯的值,如果需要終止正在編輯的其他值*/
public
void setItem(Object
anObject);
/*返回當前正在編輯的值*/
public Object
getItem();
/*全選*/
public void
selectAll();
/*當編輯的值得到確認時或者發生變化時將會調用註冊上面的ActionListener,改方法添加ActionListener*/
public
void addActionListener(ActionListener
l);
/*刪除ActionListener*/
public void
removeActionListener(ActionListener l);
}

 
由於JComboBox只有一處可以編輯,因此的編輯過程相當簡單。JComboBox將
ComboBoxEditor 提供組件作為編輯器添加到組件樹上,自己註冊為該 ComboBoxEditor
的ActionListener。當編輯組件的值發生變化,或使用者確認編輯結果時,通知JComboBox。JComboBox發出適當的事件通知JComboBox的外來事件偵聽者。

 
當使用者從列表中選擇某項進行編輯時,JComboBox使用
ComboBoxEditor.setItem設定編輯器的初始值。當使用者請求JComboBox擷取當前編輯值時,JComboBox調用
ComboBoxEditor.getItem擷取正在編輯的值,另外JComboBox可以通過ComboBoxEditor的selectAll來請
求全選操作,這時允許如JTextField為編輯組件的編輯器實現全選。

 
ComboBoxEditor介面的方法也暗含幾個關係:

1.setItem、getItem、selectAll的操作對象應該是getEditorComponent返回的同一組件。

2.同樣要實現addActionListener和removeActionListener,一般要實現fireActionPerformed,要偵聽編輯組件的事件,使用fireActionPerformed通知JComboBox做出響應。

 
編輯器工作過程相對比Renderer要複雜一些,主要是因為編輯過程是和使用者進行互動的過程,不像Renderer那樣只是簡單的渲染過程。這個過程是
非過程性的,所以它們的介面也就複雜的多,介面方法之間也暗含這一定的關係。

  
但要正確理解也不難,關鍵要清楚JTable、JTree和JComboBox編輯器工作的過程。知道這些過程並根據以及前所學的事件及事件器處理模型知
識,就應該很容易理解各個介面方法的含義以及它們之間暗含的關係,也就不會在實現自己的Editor時一頭霧水,無所適從。由於篇幅的原因,今天文章就到
此為止了。明天的文章將舉一些具體例子加深對in-place editor的理解。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.