开发Eclipse自定义控件.docx

上传人:b****2 文档编号:24079164 上传时间:2023-05-24 格式:DOCX 页数:14 大小:19.90KB
下载 相关 举报
开发Eclipse自定义控件.docx_第1页
第1页 / 共14页
开发Eclipse自定义控件.docx_第2页
第2页 / 共14页
开发Eclipse自定义控件.docx_第3页
第3页 / 共14页
开发Eclipse自定义控件.docx_第4页
第4页 / 共14页
开发Eclipse自定义控件.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

开发Eclipse自定义控件.docx

《开发Eclipse自定义控件.docx》由会员分享,可在线阅读,更多相关《开发Eclipse自定义控件.docx(14页珍藏版)》请在冰豆网上搜索。

开发Eclipse自定义控件.docx

开发Eclipse自定义控件

开发Eclipse自定义控件

简介:

 现在基于Eclipse的应用越来越多,很多桌面应用都是用Eclipse开发的。

Eclipse提供了一套SWT/JFACE的控件库,使得人们开发界面应用极大的方便。

但是,SWT/JFACE的控件库毕竟有限,在应用开发是我们不可避免地要自己开发一些自定义的控件。

本文通过开发一个颜色列表控件的实例介绍了Eclipse自定义控件开发中所要用到的技术。

目标读者必须熟悉Java开发,并且有一定的Eclipse开发经验。

在Eclipse网站上有一篇相关的文章"CreatingYourOwnWidgetsusingSWT",该文介绍了开发自己控件的很多基本概念、方法,并且通过实例进行了介绍,非常好。

但是其所用的实例比较简单,还有很多控件开发中所要涉及到的内容,例如键盘、鼠标事件的处理,滚动条、焦点的处理等等没有提及。

本文通过开发一个自定义的颜色列表控件的实例,全面地介绍了自定义控件所涉及的技术。

同时,读者也可以对该实例进行扩展,实现自己的列表控件。

SWT中提供的标准列表控件非常简单,只能提供字符串的选择。

我们经常需要提供一些图形列表供用户选择,这就需要自己开发自定义的列表控件。

颜色选择列表是我们常用的一种图形列表,我们就以此为例进行介绍。

以下是我们将要开发的颜色列表。

我们在开发自定义控件时主要考虑以下问题:

1、自定义控件的绘制:

通常我们需要自己对控件的形状或图案进行绘制;

2、控件对键盘事件的响应:

当焦点进入控件,用户进行键盘操作,通过键盘对控件进行控制时,我们需要让控件对用户的操作进行响应。

例如在列表中,用户会通过上下箭头改变列表的选择项;

3、控件对鼠标事件的响应:

当用户用鼠标选中控件,进行操作时,控件必须作出相应的反应;

4、控件对焦点事件的响应:

当界面焦点进入或移出控件,通常我们需要将控件绘制成得到或失去焦点的形状。

例如,当焦点进入列表时,一般被选中的列表项会有虚框表示选中。

5、响应TAB键:

对于一个可操纵的控件,用户可以用TAB键将焦点移入或移出。

6、响应滚动条事件:

当控件有滚动条时,我们需要响应用户对滚动条的操作,完成对控件的绘制工作。

7、提供事件监听机制:

程序员使用你的控件时通常需要监听控件中发生的一些事件,这样当事件发生时,他们能够进行相应处理。

8、提供辅助功能(Accessibility):

辅助功能是方便残障人士使用时必须的,标准控件都会提供相应的支持,我们自定义的控件也不例外。

9、提供功能接口方便程序员访问:

通常为方便程序员使用时获取控件中的信息或进行设置,我们需要提供一些接口。

首先我们要开发的列表控件是一个基本控件,所以我们选择Canvas作为我们开发的基类。

publicclassColorListextendsCanvas{

Vectorcolors=newVector();//用于保存我们颜色控件中的颜色值

VectorcolorNames=newVector();//用于保存颜色控件中的颜色名字

introwSel=-1;//用于保存当前选中的行号

intoldRowSel=-1;//用于保存上一次选中的行号

intmaxX,maxY;//用于保存列表的宽度和高度

intlineHeight;//用于设置行高

intcx=0;//滚动条滚动后,控件的图形相对于控件可见区域左上角的x坐标

intcy=0;//滚动条滚动后,控件的图形相对于控件可见区域左上角的y坐标

}

控件开发最重要的就是控件的绘制了。

控件的绘制可以通过添加PaintListener,在它的paintControl方法中进行。

addPaintListener(newPaintListener(){

publicvoidpaintControl(PaintEvente){

GCgc=e.gc;

Pointsize=getSize();

intbeginx=e.x;

intbeginy=(e.y/lineHeight)*lineHeight;

intbeginLine=(e.y-cy)/lineHeight;

intendLine=beginLine+e.height/lineHeight+1;

if(endLine>getItemCount())

endLine=getItemCount();

for(inti=beginLine;i

booleanselected=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,newListener(){

publicvoidhandleEvent(Eventevent){

switch(event.keyCode){

caseSWT.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){//如果需要,滚动滚动条

ScrollBarbar=((Canvas)event.widget)

.getVerticalBar();

bar.setSelection(bar.getSelection()-lineHeight);

scrollVertical(bar);

}

selectionChanged();//发送selectionChanged事件

}

break;

caseSWT.ARROW_DOWN:

//downarrorkey

break;

}

}

});

接下来,我们要让我们的控件响应鼠标对列表项进行选择。

首先我们要计算出鼠标选中的行号,注意MouseEvent中的y值只是相对于控件左上角的坐标,我们需要加上滚动出了控件的部分。

addMouseListener(newMouseListener(){

publicvoidmouseDoubleClick(MouseEvente){

}

publicvoidmouseDown(MouseEvente){

introw=(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();

}

publicvoidmouseUp(MouseEvente){

}

});

当我们的控件获得焦点时,选中的列表项需要有虚框表示控件得到焦点。

当获得或失去焦点是,我们这里只需要简单的通知选中的项重画。

addFocusListener(newFocusListener(){

publicvoidfocusGained(FocusEvente){

((Canvas)e.getSource()).redraw(cx,rowSel*lineHeight,maxX,

lineHeight,true);

}

publicvoidfocusLost(FocusEvente){

((Canvas)e.getSource()).redraw(cx,rowSel*lineHeight,maxX,

lineHeight,true);

}

});

我们在绘制每一个列表项时可以加入判断当前控件是否得到焦点,如果控件得到了焦点,我们就在选中的项目上画一个虚框。

下面是我们绘制一个列表项的代码,注意在代码的最后绘制焦点的虚框。

voidonPaint(GCgc,introw,intbeginx,intbeginy,booleanisSelected){

ColorinitColor=gc.getBackground();

ColorinitForeColor=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);

Colorcolor=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(newTraverseListener(){

publicvoidkeyTraversed(TraverseEvente){

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(newSelectionAdapter(){

publicvoidwidgetSelected(SelectionEventevent){

scrollVertical((ScrollBar)event.widget);

}

});

}

下面是函数scrollVertical的代码。

一旦用户对滚动条操作,我们就可以计算出要滚动的区域,然后调用scroll函数。

对函数scroll函数的调用会导致相应区域的重绘。

voidscrollVertical(ScrollBarscrollBar){

Rectanglebounds=getClientArea();

inty=-scrollBar.getSelection();

if(y+maxY

y=bounds.height-maxY;

}

if(y%lineHeight!

=0)

y=y-y%lineHeight-lineHeight;

scroll(cx,y,cx,cy,maxX,maxY,false);

cy=y;

}

现在我们的程序已经基本成形了,我们来进一步完善它。

由于我们开发的控件是提供给程序员的,我们需要提供接口,让外部知道控件中发生的事件。

其中最重要的是列表项的选中事件。

我们需要提供接口让程序员能够添加事件监控器(listener)来监控发生的事件,并且一旦发生事件,我们需要通知监控器。

首先,我们添加一个成员来保存添加的事件监控器:

VectorselectionListeners=newVector();

我们再增加一个函数addSelectionListener,让程序员可以添加监控器

publicvoidaddSelectionListener(SelectionListenerlistener){

selectionListeners.addElement(listener);

}

在我们前面的代码中,我们注意到每次选择项改变,我们都会调用selectionChanged函数。

下面是selectionChanged函数代码。

这里,我们会生成一个SelectionEvent事件,并且逐个调用事件监控器的widgetSelected方法。

这样别人就可以监听到我们的事件了。

publicvoidselectionChanged(){

Eventevent=newEvent();

event.widget=this;

SelectionEvente=newSelectionEvent(event);

for(inti=0;i

SelectionListenerlistener=(SelectionListener)selectionListeners.elementAt(i);

listener.widgetSelected(e);

}

}

现在辅助功能(Accessibility)也日益成为软件重要的部分,它是的残疾人也能够方便的使用我们的软件。

美国已经立法,不符合Accessibility规范的软件不能够在政府部门销售。

我们开发的控件也需要支持Accessibility.下面的代码使我们的控件有Accessibility支持。

其中最重要的是getRole和getValue函数。

我们的控件是从Canvas继承,我们在getRole函数中返回ACC.ROLE_LIST,这样我们的控件才能让屏幕阅读软件将我们的控件作为列表控件对待。

Accessibleaccessible=getAccessible();

accessible.addAccessibleControlListener(newAccessibleControlAdapter(){

publicvoidgetRole(AccessibleControlEvente){

introle=0;

intchildID=e.childID;

if(childID==ACC.CHILDID_SELF){

role=ACC.ROLE_LIST;

}elseif(childID>=0&&childID

role=ACC.ROLE_LISTITEM;

}

e.detail=role;

}

publicvoidgetValue(AccessibleControlEvente){

intchildID=e.childID;

if(childID==ACC.CHILDID_SELF){

e.result=getText();

}elseif(childID>=0&&childID

e.result=(String)colorNames.get(childID);

}

}

publicvoidgetChildAtPoint(AccessibleControlEvente){

PointtestPoint=toControl(newPoint(e.x,e.y));

intchildID=ACC.CHILDID_NONE;

childID=(testPoint.y-cy)/lineHeight;

if(childID==ACC.CHILDID_NONE){

Rectanglelocation=getBounds();

location.height=location.height-getClientArea().height;

if(location.contains(testPoint)){

childID=ACC.CHILDID_SELF;

}

}

e.childID=childID;

}

publicvoidgetLocation(AccessibleControlEvente){

Rectanglelocation=null;

intchildID=e.childID;

if(childID==ACC.CHILDID_SELF){

location=getBounds();

}

if(childID>=0&&childID

location=newRectangle(cx,childID*lineHeight+cy,maxX,lineHeight);

}

if(location!

=null){

Pointpt=toDisplay(newPoint(location.x,location.y));

e.x=pt.x;

e.y=pt.y;

e.width=location.width;

e.height=location.height;

}

}

publicvoidgetChildCount(AccessibleControlEvente){

e.detail=colors.size();

}

publicvoidgetState(AccessibleControlEvente){

intstate=0;

intchildID=e.childID;

if(childID==ACC.CHILDID_SELF){

state=ACC.STATE_NORMAL;

}elseif(childID>=0&&childID

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;

}

});

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

publicvoidsetSelection(intindex){

if(index>=getItemCount()||index<0)

return;

oldRowSel=rowSel;

rowSel=index;

selectionChanged();

}

publicintgetSelectionIndex(){

returnrowSel;

}

publicintgetItemHeight(){

returnlineHeight;

}

publicvoidsetItemHeight(intheight){

lineHeight=height;

}

publicintgetItemCount(){

returncolors.size();

}

publicvoidadd(intcolorIndex,StringcolorName){

colorNames.add(colorName);

colors.add(newInteger(colorIndex));

}

我们开发的控件的使用也是非常简单的。

CustomListcustomlist=newCustomList(parent,SWT.V_SCROLL|SWT.H_SCROLL);

customlist.add(SWT.COLOR_BLACK,"BLACK");

customlist.add(S

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 演讲主持

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1