站内搜索: 请输入搜索关键词

当前页面: 开发资料首页Eclipse 专题开发Eclipse下的自定义控件

开发Eclipse下的自定义控件

摘要: 本文首先介绍模型转换的基本概念,然后介绍RSA模型转换框架,之后本文以两个具体的例子介绍如何在RSA开发平台中以模型转换框架为基础创建和扩展模型转换。
<table cellSpacing=1 cellPadding=2 width=600 align=center bgColor=#ff3300 border=0> <tr bgColor=#ffffff> <td bgColor=#cc0000 colSpan=4>天极软件专题专区精选     到天极软件“读编交流区”畅所欲言</td></tr> <tr bgColor=#ffffff> <td width="25%">Google专区 </td> <td width="23%">POPO专区</td> <td width="24%">QQ专区 QQ挂机</td> <td width="28%">了解Web2.0</td></tr> <tr bgColor=#ffffff> <td width="25%">Flash MX 视频教程</td> <td width="23%">Photoshop视频教程</td> <td width="24%">网页设计视频教程</td> <td width="28%">照片处理数字暗房</td></tr> <tr bgColor=#ffffff> <td width="25%">PPT动画演示教程</td> <td width="23%">Excel动画教程集</td> <td width="24%">Word动画演示教程</td> <td width="28%">Windows Vista专区 </td></tr> <tr bgColor=#ffffff> <td width="25%" height=18>特洛伊木马专区</td> <td width="23%" height=18>黑客知识教程专区</td> <td width="24%" height=18>防火墙应用专区</td> <td width="28%" height=18>注册表应用专区</td></tr> <tr bgColor=#ffffff> <td width="25%">Windows API开发专区</td> <td width="23%">网络编程专区</td> <td width="24%">VB数据库编程专区</td> <td width="28%">图像处理与多媒体编程</td></tr></table>
  本文首先介绍模型转换的基本概念,然后介绍RSA模型转换框架,之后本文以两个具体的例子介绍如何在RSA开发平台中以模型转换框架为基础创建和扩展模型转换。

  现在基于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作为我们开发的基类。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



  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坐标

 }

 
</td></tr></table>

  控件开发最重要的就是控件的绘制了。控件的绘制可以通过添加PaintListener,在它的paintControl方法中进行。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



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

    }

   }

  });

  
</td></tr></table>

  这里要注意的是从PaintEvent中获取的x,y,height,width是需要重绘的区域,x,y是以控件的左上角为原点的坐标。在我们的程序中,为了性能起见,我们先根据需要重绘的区域计算出需要重绘的行数,只重绘相应的行,而不是将整个控件重绘。我们程序中用到的onPaint用于绘制一行。

  接下来,我们要让我们的控件响应键盘上下键对列表项进行选择。我们已对向上键的处理为例,首先当用户按了向上键时,我们需要改变选择,并且重绘旧的和新的选择项。如果选择项已经到了列表的顶部,我们还需要同时滚动滚动条。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



  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;

    }

   }

  });

  
</td></tr></table>

  接下来,我们要让我们的控件响应鼠标对列表项进行选择。首先我们要计算出鼠标选中的行号,注意MouseEvent中的y值只是相对于控件左上角的坐标,我们需要加上滚动出了控件的部分。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



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

   }

  });

  
</td></tr></table>

  当我们的控件获得焦点时,选中的列表项需要有虚框表示控件得到焦点。当获得或失去焦点是,我们这里只需要简单的通知选中的项重画。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



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

   }

  });

  
</td></tr></table>

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

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



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

 }

 
</td></tr></table>

  作为一个可操作的控件,TAB键的支持也是很重要的。由于我们的控件是从Canvas继承过来的,不支持TAB键。下面的代码使我们的控件有TAB键的支持:

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



addTraverseListener(new TraverseListener() {

   public void keyTraversed(TraverseEvent e) {

    if (e.detail == SWT.TRAVERSE_TAB_NEXT

      || e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {

     e.doit = true;

    }

   };

  });

</td></tr></table>

  很多时候,我们需要有滚动条的支持。对于滚动条,我们只要在上面加上selectionListener,处理它的widgetSelected事件就可以。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>



bar = getVerticalBar();

  if (bar != null) {

   bar.addSelectionListener(new SelectionAdapter() {

    public void widgetSelected(SelectionEvent event) {

     scrollVertical((ScrollBar) event.widget);

    }

   });

  }

</td></tr></table>

  下面是函数scrollVertical的代码。一旦用户对滚动条操作,我们就可以计算出要滚动的区域,然后调用scroll函数。对函数scroll函数的调用会导致相应区域的重绘。

<table cellSpacing=0 cellPadding=5 width="100%" bgColor=#eeeeee border=1> <tr> <td>


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;

 }

</td></tr></table>

  现在我们的程序已经基本成形了,我们来进一步完善它。由于我们开发的控件是提供给程序员的,我们需要提供接口,让外部知道控件中发生的事件。其中最重要的是列表项的选中事件。我们需要提供接口让程序员能够添加事件监控器(listener)来监控发生的事件,并且一旦发生事件,我们需要通知监控器。




↑返回目录
前一篇: Eclipse3.1中体验J2SE5.0之泛型
后一篇: 扩展Eclipse辅助和规范开发流程