JFC/Swing活學活用系列之定製JList顯示

來源:互聯網
上載者:User
顯示

  點擊這裡下載源檔案

  引言

  在圖形化使用者介面方面(GUI),Java一直無法與C++、PB、Delphi之類抗衡,使用早期Java/AWT包所開發的介面實在是讓人不敢恭維。隨著JFC/Swing的日趨成熟,開發出與可以與C++媲美的GUI不再是"不可能完成的任務"。除了具有豐富的介面組件之外,以下優秀的特性更讓Swing如虎添翼。Swing是以100%純Java實現的,且輔以JDK 1.1 輕量級UI架構為基礎,沒有本地代碼,獨立於作業系統之外,基於MVC設計模式、採用可插入的外觀感覺(PL&F),這都讓我們忍不住去感受一下她的魅力。

  完整的JFC十分巨大,Swing只是其中的一部分,本文將著重於Swing包中的JList組件以及如何定製顯示。

  JList基礎知識

  由JList類代表的Swing列表顯示一個可選取對象列表,它支援三種選模數式:單選取、單間隔選取、多間隔選取。

  基於MVC的構建思想,JList類不維護對它所顯示的那些對象的引用,而是把資料管理工作委託給一個實現ListModel介面的對象;JList類不對其顯示對象的選取操作進行跟蹤和維護,而是把選取管理的工作委託給一個實現ListSelectionModel介面的對象;JList類不繪製其所顯示的對象,而是把列表單元的繪製工作委託給一個實現ListCellRenderer介面的對象。

  JList組件把三個主要的工作(資料處理、清單項目選取、單元繪製)交給其它對對象來完成,JList的每個執行個體都維護對上述對象的引用,這樣大大降低了各個功能模組的耦合度,易於擴充和維護。

  JList如何顯示對象列表?

  預設情況下,JList對象對表徵圖和字串對象會按照原樣顯示,而對於其它所有對象只顯示對象toString()方法的傳回值。舉個例子吧,有這樣一個應用程式顯示java.util.Locale對象列表給使用者,使用者可以通過挑選清單中的項目來改變應用程式所的處的語言環境。

  想象一下,JList將如何顯示一個包含了Locale對象的資料模型呢?JList委派javax.swing.ListCellRenderer來顯示這些對象。正如我們所料,ListCellRenderer將把對象toString()方法的傳回值顯示出來。然而,Locale對象返回的是ISO代碼,這樣的顯示肯定是不符合"介面互動友好"原則的。預設情況下JList所顯示的內容讓大多數使用者感到莫名其妙,如下圖所示:


  再來看下面這個例子,更恰如其分地說明了JList對象的預設顯示並不能對使用者提供任何有意義的資料。假設一個繪圖程式提供了顏色挑選清單,也許你會從中選擇一種顏色用於填充,也許用於繪製線條,或者幹什麼都可以。儘管我們將java.awt.Color對象執行個體放入JList中的作法是中規中矩的,但使用者卻不能從中得到任何的協助,這背離了我們的初衷。如下圖所示:


  Color對象toString()方法返回的是三原色紅、綠、藍(RGB)各分量的亮度值,而不論它所表現的具體顏色是什麼。除非使用者知道所選取的第六行0、255、0所代表的是綠顏色,要麼我們就應該在這個位置顯示一些對使用者更有協助的資訊。

  誠然,你也許可以把java.lang.String對象的執行個體放入JList中以替代Color對象的執行個體,但這麼做卻放棄了使用JList的目的:使用者是要從列表中選用一種顏色並非是選取一段文本描述。

  當使用Color對象時,JList的監聽變化的監聽器返回的是使用者實際看到的顏色。如果用String對象來替代的話,JList將把String對象返回到監聽器,然後監聽器再去匹配與之對應的顏色來完成填充操作,有點多此一舉的感覺。

  尋求解決方案

  作為使用者,我們希望的應用程式應該是介面互動清晰明了的,而不是把Locale對象的ISO代碼或者是顏色的RGB值顯示出來,介面互動友好的軟體才能吸引使用者。ISO代碼或者RGB值對編程的人來說或許有用,但並不適合於終端使用者。

  幸運的是,Locale對象有個displayName屬性適合用來為使用者顯示資訊。我們可用該屬性來替代toString()方法用於JList的顯示,這樣一來就能使得JList更具可讀性。比較以下程式碼片段中Locale對象的toString()方法和getDisplayName方法的傳回值:

Locale[] locales = { new Locale("en", "US"), new Locale("fr", "FR"),
new Locale("th", "TH"), new Locale("es", "MX"),
new Locale("ja", "JP") };
System.out.printf("%-10s\t%s\n", "toString", "getDisplayName");
System.out.printf("%-10s\t%s\n", "--------", "--------------");
for (Locale l : locales)
{
 System.out.printf("%-10s\t%s\n", l.toString(), l.getDisplayName());
}


  在將有中文Windows XP的機器上,運行結果如下所示:

toString getDisplayName
-------- --------------
en_US 英文 (美國)
fr_FR 法文 (法國)
th_TH 泰文 (泰國)
es_MX 西班牙文 (墨西哥)
ja_JP 日文 (日本)

  Locale對象的displayName屬性對使用者來說更具可讀性,也更貼近使用者。如果應用程式裡的JList使用displayName屬性,那麼看起來會是下面的樣子:


  那麼這個效果是怎麼實現的呢?為了讓列表在使用者介面上有更好的表現,我們要建立自己的ListCellRenderer,這樣在上面的例子中就可以通過displayName屬性來替代預設的toString()方法的傳回值。

  類似地,如果我們的選擇顏色的應用程式,我們也可以用定製的ListCellRenderer來顯示Color對象對應的名稱和它們的顏色。如下圖所示:


  我們先來瞭解一下ListCellRenderer的工作原理,ListCellRenderer介面只定義了一個方法,該方法返回一個組件:

Public abstract Component getListCellRendererComponent(JList list,Object value,Int index,boolean isSelected
boolean cellHasFocus)


  由getListCellRendererComponent返回的組件的作用就像一個像皮圖章,它把這個組件繪製到列表中清單項目所佔的地區。要注意的一點是,列表單元並不包含這個組件,這個組件只是繪製到列表單元上。這是很重要的,因為不能操縱這個組件,只能使用這個組件的可見代表來繪製列表單元。

  預設情況下,JList的執行個體配備一個繪製器,它是ListCellRenderer介面的一個簡單實現,即DefaultListCellRenderer類。該類擴充了JLabel類,而且可以顯示字串或表徵圖,但不能在一個單元中同時顯示字串和表徵圖。

  雖然自訂的ListCellRenderer可繼承任何Component,但對於上述應用我們選取的解決方案還是使用DefaultListCellRenderer的好,因為繼承了JLabel,可以方便的設定文本、顏色,甚至圖片。參考下面這段代碼:

public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus)
{
 super.getListCellRendererComponent(list, value, index, isSelected,cellHasFocus);
 Locale l = (Locale) value;
 setText(l.getDisplayName());
 return this;
}


  renderer先調用它的超類的getListCellRendererComponent()方法來繪製組件,接下來只需要進行一些簡單的設定就可以了,這裡我們使用被選中的Locale對象的getDisplayName()方法的傳回值來設定文本。

  有了定製的ListCellRenderer,讓JList來使用這個新的renderer就更簡單了,調用JList對象的setCellRenderer()方法並且把新建立的ListCellRenderer執行個體作為參數傳遞進去,就足夠了。JList對象將用定製的renderer來展現列表裡每個Locale對象。參考下面的程式碼片段:

ListCellRenderer localeRenderer = new LocaleRenderer();
localeList.setCellRenderer(localeRenderer);


  定製Color選取器的例子與Locale的例子有點不同。不同之處在於,裝飾器不僅設定了選項單元的常值內容,還設定了它的顏色與對應的背景色。因為Color對象本身裡沒有內建的文本名,所以我們需要在顏色名和顏色之間建立映射關係。在這裡我們使用HashMap來完成映射操作。具體代碼執行個體請見參考資料。

   結束語

  最後再提一下對象在JList中是如何顯示的。不必非得依賴對象提供的toString()方法,因為我們可以用ListCellRenderer來顯示任何想要顯示的和對象相關的文本。此外,我們也可以在選取的作為ListCellRenderer的組件上選用任何顏色或圖形來繪製。我們也可以將同樣的繪製器應用於JComboBox。使用定製的ListCellRenderer,可以使用JList和JComboBox組件來編寫使用者介面更加友好的應用程式。



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

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

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