SWT的PaintListener

以前很少用到这个类(org.eclipse.swt.events.PaintListener),利用它可以用来在control上画一些东西,基本方法是在control上 addPaintListener()一个PaintListener,然后在这个listener里做具体的画图工作,listener在control需要绘制的时候调用。

下面例子代码用来在一个composite的中央绘制一行文字。

package com.test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Test3 {

    public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        final Button button = new Button(shell, SWT.PUSH);
        button.setText("This is a button");
        final Composite comp2 = new Composite(shell, SWT.BORDER);
        comp2.addPaintListener(new PaintListener() {
            public void paintControl(PaintEvent e) {
                String text = "This is a composite";
                Rectangle area = comp2.getClientArea();//client area
                int tw = calcTextWidth(e.gc, text);//text width
                int th = e.gc.getFontMetrics().getHeight();//text height
                Rectangle textArea = new Rectangle(area.x + (area.width - tw) / 2,
                        area.y + (area.height - th) / 2, 
                        tw,
                        th);//centerized text area
                e.gc.drawString(text, textArea.x, textArea.y);
                e.gc.drawRectangle(textArea);
            }

            private int calcTextWidth(GC gc, String text) {
                int stWidth = 0;
                for (int i = 0; i < text.length(); i++) {
                    char c = text.charAt(i);
                    stWidth += gc.getAdvanceWidth(c);
                }
                return stWidth;
            }
        });
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();
    }
}

运行结果如下图:

file

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/09/23/242837.html

在SWT里显示AWT对象

今天遇到一个问题,就是要在一个Eclipse插件里显示JFreeChart的图形,因为后者是基于Java2D的,要把图形显示在SWT应用程序里需要利用SWT-AWT桥接器来实现,虽说桥接的方式多半会伴随着性能下降,但总归是一个解决方法。

代码并不复杂,以下是一个片断:

public void createPartControl(Composite parent) {
    parent.setLayout(new FillLayout(SWT.VERTICAL));
    Composite drawarea = new Composite(parent, SWT.EMBEDDED);
    drawarea.setLayout(new FillLayout());
    Frame canvasFrame = SWT_AWT.new_Frame(drawarea);
    canvas = new java.awt.Canvas() {
        public void paint(Graphics g) {
            super.paint(g);
            if (chart != null)
                chart.draw((Graphics2D) g, getBounds());
        }
    };
    canvasFrame.add(canvas);
}

关键之处在于SWT_AWT.new_Frame()方法,得到的是一个java.awt.Frame对象,要显示的AWT内容都放在它上面就好。

BTW, SWT下免费的图表工具好象很少,只能暂时先这样使用JFreeChart了。

Update: 如果要在SWT里显示带有动画效果的AWT图形,最好在Frame上先放一个JPanel这样的带有双缓冲的控件,否则图象在运动时会产生明显的闪烁。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/07/17/194710.html

[Eclipse]处理颜色类型的偏好项

在Eclipse里实现偏好页(PreferencePages)时,我们一般要在Plugin类的start()方法里预先设置好每一项的缺省值,但IPreferenceStore接口只提供了参数为整型、布尔型、字符串等基本类型的setDefault()方法,如果某个偏好项是颜色类型怎么办呢?

这时要使用PreferenceConverter这个类,也是由jface提供的,该类提供了额外的一些setDefault()方法可以接收RGB、Font、Point等类型的参数,所以可以使用下面的方法设置缺省值:

PreferenceConverter.setDefault(getPreferenceStore(), IConstants.PREF_COLOR_PRIORITY_HIGH, new RGB(255, 128, 64));

要取得某个颜色类型的偏好项值,就用下面的语句:

PreferenceConverter.getColor(CbmPlugin.getDefault().getPreferenceStore(), IConstants.PREF_COLOR_PRIORITY_HIGH)

JFace在颜色、图象和字体等资源的管理方面为我们做了很多工作,我们应该尽量利用已有的这些功能。

file
图1 颜色类型的偏好项

顺便说一下,要让editor里的图形在用户更改preference设置后立即反应变化,要在preferenceStore上增加监听器,例如在editor的initializeGraphicalViewer()方法里这样写:

protected void initializeGraphicalViewer() {

    Activator.getDefault().getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() {
        public void propertyChange(PropertyChangeEvent event) {
            // You may refresh some editparts only for better performance
            //    if(IConstants.PREF_SHOW_ACTIVITIES.equals(event.getProperty()))
                refreshAllEditParts(getGraphicalViewer().getRootEditPart());
        }

        private void refreshAllEditParts(EditPart part) {
            part.refresh();
            List children = part.getChildren();
            for (Iterator iter = children.iterator(); iter.hasNext();) {
                EditPart child = (EditPart) iter.next();
                refreshAllEditParts(child);
            }
        }

    });
}

最后,org.eclipse.ui.preferencePages扩展点的page元素的category属性的值应该是另一个page的id值。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/04/12/136105.html

SWT的GridData中一个需要注意的地方

如果在界面上有一个大文本框,一般我们会指定它的GridData为GridData.FILL_BOTH,这样在窗口改变大小时它的大小会随着变化。但在同一个GridLayout里,如果有多个这样的文本框,一定要注意它们的GridData中的grabExcessHorizontalSpace属性,该属性指出当一行中所有单元格的大小(宽/高)还不足以填充父控件时,是否增大其尺寸。

举一个具体的例子,有两行控件,父控件的Layout定义为new GridLayout(4,false),既有四列。第一行控件依次为Label0、Text1和Button2,其中Text3占2列;第二行为Text2,独占4列,我们希望第一行中的按钮右端和第二行中的文本框右端对齐,两个文本框都随窗口变宽而变宽,代码如下:

import org.eclipse.swt.*; 
import org.eclipse.swt.custom.*; 
import org.eclipse.swt.graphics.*; 
import org.eclipse.swt.layout.*; 
import org.eclipse.swt.widgets.*; 

public class MyLayout { 
    public static void main (String [] args) { 
        Display display = new Display (); 
        Shell shell = new Shell (display); 
        GridLayout gridLayout = new GridLayout (); 
        gridLayout.numColumns = 4; 
        shell.setLayout (gridLayout); 

        Label label0 = new Label (shell, SWT.NONE); 
        label0.setText ("label0"); 

        Text text1 = new Text (shell, SWT.BORDER); 
        text1.setText ("text1"); 
        GridData data = new GridData (); 
        data.horizontalAlignment = GridData.FILL; 
        data.horizontalSpan = 2; 
        data.grabExcessHorizontalSpace = true; 
        text1.setLayoutData (data); 

        Button button2 = new Button (shell, SWT.PUSH); 
        button2.setText ("button2"); 

        Text text3 = new Text (shell, SWT.BORDER); 
        text3.setText ("text3"); 
        data = new GridData (); 
        data.horizontalAlignment = GridData.FILL; 
        data.verticalAlignment = GridData.FILL; 
        data.horizontalSpan = 4; 
        data.grabExcessHorizontalSpace = true; //Wrong! 
        text3.setLayoutData (data); 

        shell.pack (); 
        shell.open (); 

        while (!shell.isDisposed ()) { 
            if (!display.readAndDispatch ()) 
                display.sleep (); 
        } 
        display.dispose (); 
    } 
}

因为想到两个文本框的宽度要变大,所以指定它们的GridData的grabExcessHorizontalSpace属性为true,而运行结果却与我们想的有差别。原因是下面的文本框实际上在宽度上占据了第一行中最靠两边的两个单元格,使得第一行中间的两个单元格宽度变小。为了解决这个问题,只要把定义第二个文本框Text3的grabExcessHorizontalSpace的语句去掉即可(缺省值为false)。

还需要注意,有时候为了简单起见,我们常使用GridData data=new GridData(GridData.FILL_BOTH)来定义GridData,这个FILL_BOTH上包含了FILL_HORIZONTAL和FILL_VERTICAL,而它们各自又包含了HORIZONTAL_ALIGN_FILL、GRAB_HORIZONTAL以及VERTICAL_ALIGN_FILL、GRAB_VERTICAL。所以,如果你是用构造方法定义的GridData,并且又希望不要grabExcessHorizontalSpace,则应该手动指定它为false才行。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2005/01/17/93269.html