製作更酷的JList介面 (轉)
內容:
1。繪製器的工作原理。
2。用自訂的繪製器更換JList和JComboBox的外觀。
3。讓新的外觀響應滑鼠事件。
藉助swing
體系的mvc設計理念,為組件
更換不同的外觀成為輕而易舉事情。本文主要以JList和JComboBox為例講解ListCellRenderer的原理與用法.
一、繪製器的工作原理
不管是JList還是JComboBox,它們都用到了ListCellRenderer,因為JComboBox本身就是由一個下拉式的JList和TextField組成的. 在這裡,它們使用了callback的機制。
callback的一是種常見的方式是在A類中調用
B類中的方法,在A類中先要登記一個(也可以是多個)B類的執行個體引用,在需要調用時再通過該執行個體來調用它的內部方法.這樣的機制在很多的設計模式
中都有用到,如Observer等.還有AWT的事件機制也用到了callback.
要實現callback,通常將B類設計成一個能被callback的介面.在JList的繪製器中,swing提供了一個ListCellRenderer介面,
public interface ListCellRenderer {
Component getListCellRendererComponent(
JList list,
object
value,
int index,
boolean isselect
ed,
boolean cellHasf
ocus);
}
這個介面只提供一個方法,我們只要實現了這個介面,並將它的執行個體引用傳給JList,就可以將JList替換成不同的樣式了.看一下ListCellRenderer是如何工作的,
.NET/turbochen/images/renderer1.gif">
在繪製JList的每個Cell之前,它會去調用getListCellComponent( ),得到一個Component,並
將這個Component繪製在正確的位置.因為getListCellComponent( )返回的是Component,所以我們幾乎可以擴充任意一個Component,來改變JList,JComboBox等的外觀.
二、製作自已的繪製器
我們現在要想讓JList中顯示一組學生名單,同時每個名單前顯示該學生的表徵圖.如所示
我們先來想一想,Swing中有什麼組件既可以顯示表徵圖也可以顯示文字? JLabel.對了。我們就用JLabel作為JList的繪製器, 看看我擴充的JLabel類,它實現了ListCellRenderer介面:
/* 可以顯示表徵圖的ListCell繪製器 */
public class IconListItemRenderer extends JLabel implements ListCellRenderer
{
private Border
selectedb
order = BorderFactory.createLineBorder(Color.blue,1),
emptyBorder = BorderFactory.createEmptyBorder(1,1,1,1);
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
IconListItem item = (IconListItem)value;
this.setIcon(item.getIcon());
this.setText(item.getText());
if ( isSelected ) setBorder (selectedBorder);
else setBorder(emptyBorder);
return this;
}
}
大家看到,getListCellRendererComponent方法會傳入幾個參數,我們就用它傳入的幾個參數設定JLabel的外觀:表徵圖與文字。在這個類中,我們用一個IconListItem接收調用者傳過來的value,
IconListItem item = (IconListItem) value;
IconListItem是我另外定義好的一個類,它用來存放每一個List Item的值,
import Java
x.swing.*;
public class IconListItem
{
Icon icon;
String text;
public IconListItem(Icon icon, String text)
{
this.icon = icon;
this.text = text;
}
public Icon getIcon() { return icon;}
public String getText() { return text;}
public void setIcon(Icon icon){ this.icon = icon;}
public void setText(String text){ this.text = text; }
}
這樣的話,我就可以用getIcon()和getText()方法取得每個List Item的值了,
IconListItem item = (IconListItem) value;
this.setIcon(item.getIcon());
this.setText(item.getText());
至此,我們就可以用以下方法方便的更換JList的外觀了,
JList list = new JList();
list.setCellRenderer(new IconListItemRenderer()); file://安
裝我們自訂的cellRenderer
DefaultListModel listModel = new DefaultListModel();
list.setModel(listModel);
IconListItem item = new IconListItem(new ImageIcon(...),"John");
listModel.addElement(item); // 為List增加Item
...
由於JComboBox也有一個下拉式清單,所以它的清單也是用ListCellRenderer來繪製的,所以我們也可以將這個IconListItemRenderer給它用:
JComboBox list = new JComboBox();
list.setRenderer(new IconListItemRenderer()); //
裝我們自訂的cellRenderer
DefaultComboBoxModel comboModel = new DefaultComboBoxModel();
list.setModel(comboModel);
IconListItem item = new IconListItem(new ImageIcon(...),"John");
comboModel.addElement(item); // 為List增加Item
...
注意,JComboBox安裝
繪製器時是用setRenderer()方法,JList是用setCellRenderer()方法,名字稍有不同.
以上大家看到的是可顯示一個表徵圖的List, 下面我們再看一個可顯示CheckBox的List是如何?的,以下是例圖:
代碼實現:
import javax.swing.*;
import java.awt.*;
import javax.swing.border.*;
import java.awt.event.*;
/* 可以顯示CheckBox的ListCell繪製器 */
public class CheckListItemRenderer extends JCheckBox implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
CheckListItem item = (CheckListItem)value;
this.setSelected(item.getCheck());
this.setText(item.getText());
this.setFont(list.getFont());
this.setEnabled(list.isEnabled());
return this;
}
}
同樣這個繪製器中用一個CheckListItem存放每個List Item的值:
public class CheckListItem
{
boolean check;
String text;
public CheckListItem(boolean check, String text)
{
this.check = check;
this.text = text;
}
public boolean getCheck() { return check; }
public void setCheck(boolean _check) { check = _check; }
public String getText() { return text; }
public void setText(String _text) { text = _text; }
}
這個繪製器的用法同IconListItemRenderer一樣,不多講了.
三、讓自訂的繪製器響就滑鼠事件
使用以上的CheckListItemRenderer時,大家會發現,雖然List中可以顯示CheckBox了,但是用滑鼠點擊時,沒有反應! 現在我就來解決這個問題.要澄清的是,ListCellRenderer本身是只返回一個組件用來繪製一個儲存格,不能對使用者
動作作出反應。為些我們必須在JList上下功夫.JList有一個addMouseListener()方法可以為自身安裝一個滑鼠監聽
器,在這裡,我實現了一個MouseAdapter,並讓它對mousePressed作出響應:
class CheckListMouseListener extends MouseAdapter
{
public void mousePressed(MouseEvent e) {
JList list = (JList) e.getsource
();
int index = list.locationToIndex(e.getPoint());
CheckListItem item = (CheckListItem)list.getModel().getElementAt(index);
item.setCheck(! item.getCheck());
Rectangle rect = list.getCellBounds(index, index);
list.repaint(rect);
}
}
使用時, 用addMouseListener(new CheckListMouseListener())就行了.
除了包含CheckBox的JList外,許多情況下,我們需要為自製的繪製器加上動作響應,如我們要實現一個可編輯的JList, 除了要擴充
JTextField及實現ListCellRenderer之外,還要寫一個滑鼠監聽器和鍵盤監聽器,當雙擊時,JList變成可編輯狀態,當斷行符號時,
還原成不可編輯狀態.具體的實現過程,我就不詳敘了,留給大家作練習.
上面內容,我寫了一個示範程式
,下面是它的示範畫面,
你可以從這裡DOWNLOAD
/CellRenderer.rar">下載
完整的示範程式.
以上文章為Turbo Chen原作,著作權。如需轉載,請註明來源.