現在基於 Eclipse 的應用越來越多
很多桌面應用都是用Eclipse開發的
Eclipse提供了一套 SWT/JFACE 的控件庫
使得人們開發界面應用極大的方便
但是
SWT/JFACE的控件庫畢竟有限
在應用開發是我們不可避免地要自己開發一些自定義的控件
本文通過開發一個顏色列表控件的實例介紹了Eclipse自定義控件開發中所要用到的技術
目標讀者必須熟悉Java開發
並且有一定的Eclipse開發經驗
在Eclipse網站上有一篇相關的文章
Creating Your Own Widgets using SWT
該文介紹了開發自己控件的很多基本概念
方法
並且通過實例進行了介紹
非常好
但是其所用的實例比較簡單
還有很多控件開發中所要涉及到的內容
例如鍵盤
鼠標事件的處理
滾動條
焦點的處理等等沒有提及
本文通過開發一個自定義的顏色列表控件的實例
全面地介紹了自定義控件所涉及的技術
同時
讀者也可以對該實例進行擴展
實現自己的列表控件
SWT中提供的標准列表控件非常簡單
只能提供字符串的選擇
我們經常需要提供一些圖形列表供用戶選擇
這就需要自己開發自定義的列表控件
顏色選擇列表是我們常用的一種圖形列表
我們就以此為例進行介紹
以下是我們將要開發的顏色列表
我們在開發自定義控件時主要考慮以下問題 自定義控件的繪制
通常我們需要自己對控件的形狀或圖案進行繪制
控件對鍵盤事件的響應
當焦點進入控件
用戶進行鍵盤操作
通過鍵盤對控件進行控制時
我們需要讓控件對用戶的操作進行響應
例如在列表中
用戶會通過上下箭頭改變列表的選擇項
控件對鼠標事件的響應
當用戶用鼠標選中控件
進行操作時
控件必須作出相應的反應
控件對焦點事件的響應
當界面焦點進入或移出控件
通常我們需要將控件繪制成得到或失去焦點的形狀
例如
當焦點進入列表時
一般被選中的列表項會有虛框表示選中
響應TAB鍵
對於一個可操縱的控件
用戶可以用TAB鍵將焦點移入或移出
響應滾動條事件
當控件有滾動條時
我們需要響應用戶對滾動條的操作
完成對控件的繪制工作
提供事件監聽機制
程序員使用你的控件時通常需要監聽控件中發生的一些事件
這樣當事件發生時
他們能夠進行相應處理
提供輔助功能(Accessibility)
輔助功能是方便殘障人士使用時必須的
標准控件都會提供相應的支持
我們自定義的控件也不例外
提供功能接口方便程序員訪問
通常為方便程序員使用時獲取控件中的信息或進行設置
我們需要提供一些接口
首先我們要開發的列表控件是一個基本控件
所以我們選擇Canvas作為我們開發的基類
public class ColorList extends Canvas {
Vector colors = new Vector(); // 用於保存我們顏色控件中的顏色值
Vector colorNames = new Vector(); // 用於保存顏色控件中的顏色名字
int rowSel =
; // 用於保存當前選中的行號
int oldRowSel =
; // 用於保存上一次選中的行號
int maxX
maxY; // 用於保存列表的寬度和高度
int lineHeight; // 用於設置行高
int cx =
; // 滾動條滾動後
控件的圖形相對於控件可見區域左上角的x坐標
int cy =
; // 滾動條滾動後
控件的圖形相對於控件可見區域左上角的y坐標
}
控件開發最重要的就是控件的繪制了
控件的繪制可以通過添加PaintListener
在它的paintControl方法中進行
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
GC gc = e
gc;
Point size = getSize();
int beginx = e
x;
int beginy = (e
y / lineHeight) * lineHeight;
int beginLine = (e
y
cy) / lineHeight;
int endLine = beginLine + e
height / lineHeight +
;
if (endLine > getItemCount())
endLine = getItemCount();
for (int i = beginLine; i < endLine; i++) {
boolean selected = false;
if (i == rowSel)
selected = true;
onPaint(gc
i
cx
beginy + (i
beginLine) * lineHeight
selected);
}
}
});
這裡要注意的是從PaintEvent中獲取的x
y
height
width是需要重繪的區域
x
y是以控件的左上角為原點的坐標
在我們的程序中
為了性能起見
我們先根據需要重繪的區域計算出需要重繪的行數
只重繪相應的行
而不是將整個控件重繪
我們程序中用到的onPaint用於繪制一行
接下來
我們要讓我們的控件響應鍵盤上下鍵對列表項進行選擇
我們已對向上鍵的處理為例
首先當用戶按了向上鍵時
我們需要改變選擇
並且重繪舊的和新的選擇項
如果選擇項已經到了列表的頂部
我們還需要同時滾動滾動條
addListener(SWT
KeyDown
new Listener() {
public void handleEvent(Event event) {
switch (event
keyCode) {
case SWT
ARROW_UP: // 處理向上鍵
if (rowSel !=
) {
oldRowSel = rowSel;
rowSel
;
if (oldRowSel != rowSel) { //發送消息讓控件重繪
((Canvas) event
widget)
redraw(cx
(rowSel + cy
/ lineHeight)
* lineHeight
maxX
lineHeight*
false);
}
if (rowSel <
cy / lineHeight) { //如果需要
滾動滾動條
ScrollBar bar = ((Canvas) event
widget)
getVerticalBar();
bar
setSelection(bar
getSelection()
lineHeight);
scrollVertical(bar);
}
selectionChanged(); // 發送selectionChanged事件
}
break;
case SWT
ARROW_DOWN: // down arror key
…
break;
}
}
});
接下來
我們要讓我們的控件響應鼠標對列表項進行選擇
首先我們要計算出鼠標選中的行號
注意MouseEvent中的y值只是相對於控件左上角的坐標
我們需要加上滾動出了控件的部分
addMouseListener(new MouseListener() {
public void mouseDoubleClick(MouseEvent e) {
}
public void mouseDown(MouseEvent e) {
int row = (e
y
cy) / lineHeight; //計算選中的行
if (row >=
) {
oldRowSel = rowSel;
rowSel = row;
}
if (oldRowSel != rowSel) { // 重畫舊的和新的選擇項
((Canvas) e
getSource())
redraw(cx
(e
y / lineHeight)
* lineHeight
maxX
lineHeight
false);
((Canvas) e
getSource())
redraw(cx
(oldRowSel + cy
/ lineHeight)
* lineHeight
maxX
lineHeight
false);
}
selectionChanged();
}
public void mouseUp(MouseEvent e) {
}
});
當我們的控件獲得焦點時
選中的列表項需要有虛框表示控件得到焦點
當獲得或失去焦點是
我們這裡只需要簡單的通知選中的項重畫
addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
((Canvas) e
getSource())
redraw(cx
rowSel * lineHeight
maxX
lineHeight
true);
}
public void focusLost(FocusEvent e) {
((Canvas) e
getSource())
redraw(cx
rowSel * lineHeight
maxX
lineHeight
true);
}
});
我們在繪制每一個列表項時可以加入判斷當前控件是否得到焦點
如果控件得到了焦點
我們就在選中的項目上畫一個虛框
下面是我們繪制一個列表項的代碼
注意在代碼的最後繪制焦點的虛框
void onPaint(GC gc
int row
int beginx
int beginy
boolean isSelected) {
Color initColor = gc
getBackground();
Color initForeColor = gc
getForeground();
if (isSelected) {
gc
setBackground(Display
getCurrent()
getSystemColor(
SWT
COLOR_LIST_SELECTION));
gc
fillRectangle(beginx
beginy
maxX
lineHeight);
gc
setForeground(Display
getCurrent()
getSystemColor(
SWT
COLOR_LIST_SELECTION_TEXT));
} else {
gc
setBackground(initColor);
}
gc
drawString((String) colorNames
get(row)
beginx +
beginy);
Color color = Display
getCurrent()
getSystemColor(
((Integer) colors
get(row))
intValue());
gc
setBackground(color);
gc
fillRectangle(beginx +
beginy +
lineHeight
);
gc
setBackground(initColor);
gc
setForeground(initForeColor);
if (isFocusControl() && isSelected)
gc
drawFocus(cx
beginy
maxX
lineHeight);
}
作為一個可操作的控件
TAB鍵的支持也是很重要的
由於我們的控件是從Canvas繼承過來的
不支持TAB鍵
下面的代碼使我們的控件有TAB鍵的支持
addTraverseListener(new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (e
detail == SWT
TRAVERSE_TAB_NEXT
|| e
detail == SWT
TRAVERSE_TAB_PREVIOUS) {
e
doit = true;
}
};
});
From:http://tw.wingwit.com/Article/program/Java/ky/201311/28014.html