成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

開發Eclipse自定義控件

開發 后端
現在基于Eclipse的應用越來越多,很多桌面應用都是用Eclipse開發的。Eclipse提供了一套SWT/JFACE 的控件庫,使得人們開發界面應用極大的方便。但是,SWT/JFACE的控件庫畢竟有限,在應用開發是我們不可避免地要自己開發一些自定義的控件。本文通過開發一個顏色列表控件的實例介紹了Eclipse自定義控件開發中所要用到的技術。

目標讀者必須熟悉Java開發,并且有一定的Eclipse開發經驗。

在 Eclipse網站上有一篇相關的文章"Creating Your Own Widgets using SWT",該文介紹了開發自己控件的很多基本概念、方法,并且通過實例進行了介紹,非常好。但是其所用的實例比較簡單,還有很多控件開發中所要涉及到的內容,例如鍵盤、鼠標事件的處理,滾動條、焦點的處理等等沒有提及。本文通過開發一個自定義的顏色列表控件的實例,全面地介紹了自定義控件所涉及的技術。同時,讀者也可以對該實例進行擴展,實現自己的列表控件。

SWT中提供的標準列表控件非常簡單,只能提供字符串的選擇。我們經常需要提供一些圖形列表供用戶選擇,這就需要自己開發自定義的列表控件。顏色選擇列表是我們常用的一種圖形列表,我們就以此為例進行介紹。以下是我們將要開發的顏色列表。

我們在開發自定義控件時主要考慮以下問題:

1、 自定義控件的繪制:通常我們需要自己對控件的形狀或圖案進行繪制;

2、 控件對鍵盤事件的響應:當焦點進入控件,用戶進行鍵盤操作,通過鍵盤對控件進行控制時,我們需要讓控件對用戶的操作進行響應。例如在列表中,用戶會通過上下箭頭改變列表的選擇項;

3、 控件對鼠標事件的響應:當用戶用鼠標選中控件,進行操作時,控件必須作出相應的反應;

4、 控件對焦點事件的響應:當界面焦點進入或移出控件,通常我們需要將控件繪制成得到或失去焦點的形狀。例如,當焦點進入列表時,一般被選中的列表項會有虛框表示選中。

5、 響應TAB鍵:對于一個可操縱的控件,用戶可以用TAB鍵將焦點移入或移出。

6、 響應滾動條事件:當控件有滾動條時,我們需要響應用戶對滾動條的操作,完成對控件的繪制工作。

7、 提供事件監聽機制:程序員使用你的控件時通常需要監聽控件中發生的一些事件,這樣當事件發生時,他們能夠進行相應處理。

8、 提供輔助功能(Accessibility):輔助功能是方便殘障人士使用時必須的,標準控件都會提供相應的支持,我們自定義的控件也不例外。

9、 提供功能接口方便程序員訪問:通常為方便程序員使用時獲取控件中的信息或進行設置,我們需要提供一些接口。

首先我們要開發的列表控件是一個基本控件,所以我們選擇Canvas作為我們開發的基類。

  public class ColorList extends Canvas {
Vector colors = new Vector(); // 用于保存我們顏色控件中的顏色值
Vector colorNames = new Vector(); // 用于保存顏色控件中的顏色名字

int rowSel = -1; // 用于保存當前選中的行號
int oldRowSel = -1; // 用于保存上一次選中的行號

int maxX, maxY; // 用于保存列表的寬度和高度
int lineHeight; // 用于設置行高

int cx = 0; // 滾動條滾動后,控件的圖形相對于控件可見區域左上角的x坐標
int cy = 0; // 滾動條滾動后,控件的圖形相對于控件可見區域左上角的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 + 1;
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 != 0) {
oldRowSel = rowSel;
rowSel--;
if (oldRowSel != rowSel) { //發送消息讓控件重繪
((Canvas) event.widget).redraw(cx, (rowSel + cy
/ lineHeight)
* lineHeight, maxX, lineHeight*2, 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 >= 0) {
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 + 24, beginy);
Color color = Display.getCurrent().getSystemColor(
((Integer) colors.get(row)).intValue());
gc.setBackground(color);
gc.fillRectangle(beginx + 2, beginy + 2, 20, lineHeight - 4);
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;
}
};
});

 

很多時候,我們需要有滾動條的支持。對于滾動條,我們只要在上面加上selectionListener,處理它的widgetSelected事件就可以。

bar = getVerticalBar();
if (bar != null) {
bar.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
scrollVertical((ScrollBar) event.widget);
}
});
}

 

下面是函數scrollVertical的代碼。一旦用戶對滾動條操作,我們就可以計算出要滾動的區域,然后調用scroll函數。對函數scroll函數的調用會導致相應區域的重繪。

void scrollVertical(ScrollBar scrollBar) {
  Rectangle bounds = getClientArea();
  int y = -scrollBar.getSelection();
  if (y + maxY < bounds.height) {
   y = bounds.height - maxY;
  }
  if( y%lineHeight !=0 )
   y = y - y % lineHeight - lineHeight;
scroll(cx, y, cx, cy, maxX, maxY, false);
  cy = y;
}


 

現在我們的程序已經基本成形了,我們來進一步完善它。由于我們開發的控件是提供給程序員的,我們需要提供接口,讓外部知道控件中發生的事件。其中最重要的是列表項的選中事件。我們需要提供接口讓程序員能夠添加事件監控器(listener)來監控發生的事件,并且一旦發生事件,我們需要通知監控器。

首先,我們添加一個成員來保存添加的事件監控器:

Vector selectionListeners = new Vector();

 

我們再增加一個函數addSelectionListener,讓程序員可以添加監控器

public void addSelectionListener(SelectionListener listener) {
  selectionListeners.addElement(listener);
}


 

在我們前面的代碼中,我們注意到每次選擇項改變,我們都會調用selectionChanged函數。下面是selectionChanged函數代碼。這里,我們會生成一個 SelectionEvent事件,并且逐個調用事件監控器的widgetSelected方法。這樣別人就可以監聽到我們的事件了。

public void selectionChanged() {
  Event event = new Event();
  event.widget = this;
  SelectionEvent e = new SelectionEvent(event);
  for (int i = 0; i < selectionListeners.size(); i++) {
   SelectionListener listener = (SelectionListener) selectionListeners.elementAt(i);
   listener.widgetSelected(e);
  }
}


 

現在輔助功能(Accessibility)也日益成為軟件重要的部分,它是的殘疾人也能夠方便的使用我們的軟件。美國已經立法,不符合Accessibility規范的軟件不能夠在政府部門銷售。我們開發的控件也需要支持Accessibility.下面的代碼使我們的控件有Accessibility支持。其中最重要的是getRole和getValue函數。我們的控件是從Canvas繼承,我們在getRole函數中返回ACC.ROLE_LIST,這樣我們的控件才能讓屏幕閱讀軟件將我們的控件作為列表控件對待。

Accessible accessible = getAccessible();
accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
public void getRole(AccessibleControlEvent e) {
int role = 0;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
role = ACC.ROLE_LIST;
} else if (childID >= 0 && childID < colors.size()) {
role = ACC.ROLE_LISTITEM;
}
e.detail = role;
}

public void getValue(AccessibleControlEvent e){
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
e.result = getText();
} else if (childID >= 0 && childID < colors.size()) {
e.result = (String)colorNames.get(childID);
}
}

public void getChildAtPoint(AccessibleControlEvent e) {
Point testPoint = toControl(new Point(e.x, e.y));
int childID = ACC.CHILDID_NONE;
childID = (testPoint.y - cy)/lineHeight;
if (childID == ACC.CHILDID_NONE) {
Rectangle location = getBounds();
location.height = location.height - getClientArea().height;
if (location.contains(testPoint)) {
childID = ACC.CHILDID_SELF;
}
}
e.childID = childID;
}

public void getLocation(AccessibleControlEvent e) {
Rectangle location = null;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
location = getBounds();
}
if (childID >= 0 && childID < colors.size()) {
location = new Rectangle(cx,childID*lineHeight+cy,maxX,lineHeight);
}
if (location != null) {
Point pt = toDisplay(new Point(location.x, location.y));
e.x = pt.x;
e.y = pt.y;
e.width = location.width;
e.height = location.height;
}
}

public void getChildCount(AccessibleControlEvent e) {
e.detail = colors.size();
}

public void getState(AccessibleControlEvent e) {
int state = 0;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
state = ACC.STATE_NORMAL;
} else if (childID >= 0 && childID < colors.size()) {
state = ACC.STATE_SELECTABLE;
if (isFocusControl()) {
state |= ACC.STATE_FOCUSABLE;
}
if (rowSel == childID) {
state |= ACC.STATE_SELECTED;
if (isFocusControl()) {
state |= ACC.STATE_FOCUSED;
}
}
}
e.detail = state;
}
});

 

最后,我們需要提供一些方法方便程序員使用我們的控件。

public void setSelection(int index) {
  if (index >= getItemCount() || index < 0)
   return;
  oldRowSel = rowSel;
  rowSel = index;
  selectionChanged();
}
public int getSelectionIndex() {
  return rowSel;
}
public int getItemHeight() {
  return lineHeight;
}
public void setItemHeight(int height) {
  lineHeight = height;
}
public int getItemCount() {
  return colors.size();
}
public void add(int colorIndex, String colorName) {
  colorNames.add(colorName);
  colors.add(new Integer(colorIndex));
}
 

 

我們開發的控件的使用也是非常簡單的。

CustomList customlist = new CustomList( parent, SWT.V_SCROLL | SWT.H_SCROLL );
customlist.add(SWT.COLOR_BLACK,"BLACK");
customlist.add(SWT.COLOR_BLUE,"BLUE");
customlist.setSelection(1);
customlist.setSize(400,400);
customlist.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));


以上我們介紹了如何開發一個簡單的自定義控件所需要涉及的技術。這里我們只以一個簡單的顏色控件為例,但是一旦我們掌握了方法,我們很容易就可以開發出各種不同的漂亮控件。

整個程序完整的代碼清參考:ColorList.java

【編輯推薦】

  1. Eclipse中perspective的兩種使用方法詳解
  2. 在Eclipse中使用JUnit4進行單元測試(1)
  3. 在Eclipse中使用JUnit4進行單元測試(2)
  4. 在Eclipse中使用JUnit4進行單元測試(3)
  5. 奇怪的Eclipse debug異常
責任編輯:book05 來源: 163博客
相關推薦

2009-07-28 09:32:41

ASP.NET自定義控

2013-04-19 10:14:24

2009-08-06 09:18:01

ASP.NET自定義控ASP.NET控件開發

2011-04-19 10:33:16

ASP.NET自定義控

2017-02-17 09:37:12

Android自定義控件方法總結

2011-08-18 09:44:33

iPhone SDK儀表控件UIDialView

2009-08-03 14:46:12

C#自定義控件

2009-09-17 09:51:18

Eclipse JDT自定義跳轉

2009-08-06 17:52:45

ASP.NET控件開發自定義控件

2009-09-03 13:34:03

.NET自定義控件

2009-08-03 13:34:06

自定義C#控件

2015-02-11 17:49:35

Android源碼自定義控件

2009-08-03 13:39:46

C#自定義用戶控件

2014-09-24 11:42:46

AndroidButton

2011-07-05 18:51:51

QT 控件 鼠標

2021-08-16 14:45:38

鴻蒙HarmonyOS應用

2021-08-25 10:14:51

鴻蒙HarmonyOS應用

2009-08-06 17:13:56

ASP.NET自定義控

2009-02-10 12:55:39

自定義控件AJAX.NET

2009-08-05 17:03:37

C#自定義控件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91福利网 | 久久男人 | 欧美色成人 | 国产精品亚洲欧美日韩一区在线 | 一级片成人 | a在线观看免费 | 一级毛片在线播放 | 日本三级在线网站 | 成人在线观看免费 | 国产91丝袜在线播放 | 亚洲第一在线视频 | 婷婷午夜天 | 欧美日韩在线一区二区 | 日韩在线视频一区二区三区 | 欧美一页 | 日批日韩在线观看 | 亚洲日本中文字幕在线 | 日日操操| 久久丝袜| 每日在线更新av | 中文字幕99| 一区二区三区视频在线观看 | 国产欧美精品一区二区 | 午夜精品一区二区三区在线播放 | 91精品国产综合久久精品 | 精品国产乱码一区二区三 | 亚洲一区二区精品 | 天天射美女 | av大片 | 日韩国产在线观看 | 在线午夜 | 国产精品99| 日韩影院在线观看 | 国产综合精品一区二区三区 | 国产精品精品久久久久久 | 精品一区二区三区日本 | 一区二区三区四区在线视频 | 97超碰人人 | www.亚洲| 精精国产xxxx视频在线播放 | 一区二区视频 |