java SWT入门:自定义背景透明且可鼠标拖动改变尺寸和位置的Composite

来源:互联网 发布:汽车cae软件 编辑:程序博客网 时间:2024/05/19 07:27

下面的代码实现了一个透明可移动可改变尺寸的Composite窗体,如下图
这里写图片描述
鼠标点击窗口获取焦点,在获取焦点时会显示9个锚点用于改变窗口的位置和尺寸。
可以通过鼠标拖动锚点来改变窗口的位置或尺寸,也可以通过上下左右键来移动窗口

ActiveRectangle.java

package net.gdface.ui;import org.eclipse.swt.SWT;import org.eclipse.swt.widgets.Composite;import org.eclipse.swt.widgets.Control;import org.eclipse.swt.widgets.Display;import org.eclipse.wb.swt.SWTResourceManager;import org.eclipse.swt.events.MouseMoveListener;import org.eclipse.swt.events.MouseEvent;import org.eclipse.swt.events.MouseAdapter;import org.eclipse.swt.events.FocusAdapter;import org.eclipse.swt.events.FocusEvent;import org.eclipse.swt.events.PaintListener;import org.eclipse.swt.graphics.Color;import org.eclipse.swt.graphics.Cursor;import org.eclipse.swt.graphics.Point;import org.eclipse.swt.graphics.Rectangle;import org.eclipse.swt.events.PaintEvent;import org.eclipse.swt.events.KeyAdapter;import org.eclipse.swt.events.KeyEvent;/** * 自定义透明窗口, * 窗口位置和尺寸可以通过鼠标和上下左右键修改 * @author gudong */public class ActiveRectangle extends Composite {    /**     * 锚点对象     * @author guyadong     */    private class Anchor {        /**         * 描述锚点位置尺寸的矩形对象         */        final Rectangle rect=new Rectangle(0, 0, anchorSize, anchorSize);        /**         * 锚点的光标对象         */        final Cursor cusor;        /**         * 锚点位置计算的掩码         */        final Rectangle mask;        Anchor(Cursor cusor, Rectangle mask) {            this.cusor = cusor;            this.mask=mask;        }    }    /**     * 焦点矩形边框颜色     */    private static Color focusRectColor=SWTResourceManager.getColor(SWT.COLOR_GREEN);    /**     * 非焦点矩形边框颜色     */    private static Color nofocusRectColor=SWTResourceManager.getColor(SWT.COLOR_RED);    /**     * 矩形边框线宽     */    private static int lineWidth=1;     /**     * 锚点矩形尺寸     */    private static int anchorSize=8;    /**     * 上下左右键移动窗口的步长     */    private static int arrowStep=1;    /**     * 是否焦点     */    boolean focus=true;    /**     * 当前鼠标位置所在的锚点索引 {@link #anchors}      */    private int anchorIndex=-1;    // 光标定义    private final Cursor CURSOR_SIZENESW=new Cursor(Display.getDefault(),SWT.CURSOR_SIZENESW);    private final Cursor CURSOR_SIZENS=new Cursor(Display.getDefault(),SWT.CURSOR_SIZENS);    private final Cursor CURSOR_SIZENWSE=new Cursor(Display.getDefault(),SWT.CURSOR_SIZENWSE);    private final Cursor CURSOR_SIZEWE=new Cursor(Display.getDefault(),SWT.CURSOR_SIZEWE);    private final Cursor CURSOR_SIZEALL=new Cursor(Display.getDefault(),SWT.CURSOR_SIZEALL);        //lt+-------+-------+rt    //  |       t       |    //  |               |    //  |       c       |    //l +       +       +r    //  |               |    //  |               |    //  |       b       |    //lb+-------+-------+rb    enum AnchorType{        LT,T,RT,L,C,R,LB,B,RB    }    /**     * 9个锚点位置({@link Anchor})对象数组(按从左到右从上到下顺序排序)     */    private final Anchor[] anchors=new Anchor[]{            new Anchor(CURSOR_SIZENWSE,new Rectangle(1,1,-1,-1)),            new Anchor(CURSOR_SIZENS,new Rectangle(0,1,0,-1)),            new Anchor(CURSOR_SIZENESW,new Rectangle(0,1,1,-1)),            new Anchor(CURSOR_SIZEWE,new Rectangle(1,0,-1,0)),            new Anchor(CURSOR_SIZEALL,new Rectangle(1,1,0,0)),            new Anchor(CURSOR_SIZEWE,new Rectangle(0,0,1,0)),            new Anchor(CURSOR_SIZENESW,new Rectangle(1,0,-1,1)),            new Anchor(CURSOR_SIZENS,new Rectangle(0,0,0,1)),            new Anchor(CURSOR_SIZENWSE,new Rectangle(0,0,1,1))};;       /**     * 矩形修改标记,为true时,处于鼠标拖动修改窗口位置和尺寸的状态,     * 鼠标位于9个锚点区域({@link Anchor})之一,且鼠标键按下(mouseDown)     */    private boolean onMouseModfied;    /**     * 矩形修改状态下({@link #onMouseModfied}为true),记录上次鼠标位置     */    private Point lastPos;    /**     * 真实的窗口位置和尺寸     */    protected Rectangle originalBounds;    private boolean originalBoundsNeedupdate=false;    /**     * 父窗口x轴缩放比例     */    private float zoomY;    /**     * 父窗口y轴缩放比例     */    private float zoomX;    /**     * Create the composite.     * @param parent     * @param isFocus 是否为焦点对象     * @param originalBounds 对象原始位置尺寸     */    public ActiveRectangle(Composite parent, boolean isFocus, Rectangle originalBounds) {        // 透明背景样式        super(parent, SWT.TRANSPARENT);        this.originalBounds = originalBounds;        this.focus=isFocus;             addPaintListener(new PaintListener() {            public void paintControl(PaintEvent e) {                // 绘制透明矩形窗口                e.gc.setLineStyle(SWT.LINE_SOLID);                e.gc.setLineWidth(lineWidth);                e.gc.setForeground(focus?focusRectColor:nofocusRectColor);                Point size = getSize();                             e.gc.drawRectangle(new Rectangle(0,0,--size.x,--size.y));                if(focus){                    Color bc = e.gc.getBackground();                                        e.gc.setBackground(focusRectColor);                    e.gc.fillRectangle(anchors[AnchorType.LT.ordinal()].rect.x, anchors[AnchorType.LT.ordinal()].rect.y, anchorSize, anchorSize);                    e.gc.fillRectangle(anchors[AnchorType.T.ordinal()].rect.x, anchors[AnchorType.T.ordinal()].rect.y, anchorSize, anchorSize);                    e.gc.fillRectangle(anchors[AnchorType.RT.ordinal()].rect.x, anchors[AnchorType.RT.ordinal()].rect.y, anchorSize, anchorSize);                                       e.gc.fillRectangle(anchors[AnchorType.L.ordinal()].rect.x, anchors[AnchorType.L.ordinal()].rect.y, anchorSize, anchorSize);                    // 画中心十字                    e.gc.drawLine(anchors[AnchorType.C.ordinal()].rect.x+(anchorSize>>1), anchors[AnchorType.C.ordinal()].rect.y, anchors[AnchorType.C.ordinal()].rect.x+(anchorSize>>1), anchors[AnchorType.C.ordinal()].rect.y+anchorSize);                    e.gc.drawLine(anchors[AnchorType.C.ordinal()].rect.x, anchors[AnchorType.C.ordinal()].rect.y+(anchorSize>>1), anchors[AnchorType.C.ordinal()].rect.x+anchorSize, anchors[AnchorType.C.ordinal()].rect.y+(anchorSize>>1));                    e.gc.fillRectangle(anchors[AnchorType.R.ordinal()].rect.x, anchors[AnchorType.R.ordinal()].rect.y, anchorSize, anchorSize);                    e.gc.fillRectangle(anchors[AnchorType.LB.ordinal()].rect.x, anchors[AnchorType.LB.ordinal()].rect.y, anchorSize, anchorSize);                    e.gc.fillRectangle(anchors[AnchorType.B.ordinal()].rect.x, anchors[AnchorType.B.ordinal()].rect.y, anchorSize, anchorSize);                    e.gc.fillRectangle(anchors[AnchorType.RB.ordinal()].rect.x, anchors[AnchorType.RB.ordinal()].rect.y, anchorSize, anchorSize);                                       // 恢复背景色                    e.gc.setBackground(bc);                                 }            }        });        // 当获取/失去焦点时重绘窗口        addFocusListener(new FocusAdapter() {            @Override            public void focusGained(FocusEvent e) {                focus=true;                // 将对象设置到顶层,否则无法响应所有的mouseMove事件                moveAbove(null);                ((Control)(e.widget)).redraw();            }            @Override            public void focusLost(FocusEvent e) {                focus=false;                ((Control)(e.widget)).redraw();            }        });        // 实现上下左右键移动窗口        addKeyListener(new KeyAdapter() {            @Override            public void keyPressed(KeyEvent e) {                switch(e.keyCode){                case SWT.ARROW_LEFT:                    modify(-arrowStep,0,anchors[AnchorType.C.ordinal()].mask);                    break;                case SWT.ARROW_RIGHT:                    modify(arrowStep,0,anchors[AnchorType.C.ordinal()].mask);                    break;                case SWT.ARROW_UP:                    modify(0,-arrowStep,anchors[AnchorType.C.ordinal()].mask);                    break;                case SWT.ARROW_DOWN:                    modify(0,arrowStep,anchors[AnchorType.C.ordinal()].mask);                    break;                default:                }            }        });        // 加入mouseMove事件处理,实现鼠标拖动锚点改变窗口位置和尺寸        addMouseMoveListener(new MouseMoveListener() {            private final Cursor defCursor=getCursor();                     public void mouseMove(MouseEvent e) {                if(focus){                    if(onMouseModfied){                        // 计算鼠标移动的距离                        Point pos=((Control)(e.widget)).toDisplay(e.x, e.y);                        modify(pos.x-lastPos.x,pos.y-lastPos.y,anchors[anchorIndex].mask);                        // 记录当前鼠标位置,以供下次mouseMove消息时计算鼠标移动距离                        lastPos=pos;                    }else   if((anchorIndex=anchored(e.x, e.y))>=0&&anchors[anchorIndex].cusor!=getCursor()){                        // 当鼠标位置某个锚点时,更新鼠标形状                        setCursor(anchors[anchorIndex].cusor);                    }else   if(defCursor!=getCursor())                        // 鼠标不在锚点时,恢复默认鼠标形状                        setCursor(defCursor);                }else                     anchorIndex=-1;            }        });        // 配合MouseMoveListener实现鼠标改变窗口位置和尺寸        addMouseListener(new MouseAdapter() {                       @Override            public void mouseDown(MouseEvent e) {                if(anchorIndex>=0){                    // 记录当前鼠标位置,以供mouseMove消息时计算鼠标移动距离                    lastPos=((Control)(e.widget)).toDisplay(e.x, e.y);                    onMouseModfied=true;                }else if(!isFocusControl()){                    // 当前对象非焦点对象时,设置当前对象为焦点对象                    setFocus();                }            }            @Override            public void mouseUp(MouseEvent e) {                onMouseModfied=false;            }        });    }    @Override    protected void checkSubclass() {        // Disable the check that prevents subclassing of SWT components    }    /**     * 改变窗口位置和尺寸     * @param x x轴移动距离     * @param y y轴移动距离     * @param mask 锚点位置计算的掩码     */    private void modify(int x,int y,Rectangle mask){        // 计算出新的窗口位置和尺寸        Rectangle bound = getBounds();        bound.x+=x*mask.x;        bound.y+=y*mask.y;        bound.width+=x*mask.width;        bound.height+=y*mask.height;        // 设置新的窗口位置        this.originalBoundsNeedupdate=true;        setBounds(bound);        this.originalBoundsNeedupdate=false;    }    @Override    public void dispose() {        // 释放光标资源        CURSOR_SIZENESW.dispose();        CURSOR_SIZENS.dispose();        CURSOR_SIZENWSE.dispose();        CURSOR_SIZEWE.dispose();        CURSOR_SIZEALL.dispose();        super.dispose();    }    /**     * 根据窗口尺寸计算各个{@link Anchor}的位置     */    private void setAnchors(){        Point size = getSize();        setAnchorPos(anchors[AnchorType.LT.ordinal()].rect,0, 0);        setAnchorPos(anchors[AnchorType.T.ordinal()].rect,(size.x-anchorSize)>>1, 0);        setAnchorPos(anchors[AnchorType.RT.ordinal()].rect,size.x-anchorSize, 0);        setAnchorPos(anchors[AnchorType.L.ordinal()].rect,0, (size.y-anchorSize)>>1);        setAnchorPos(anchors[AnchorType.C.ordinal()].rect,(size.x-anchorSize)>>1, (size.y-anchorSize)>>1);        setAnchorPos(anchors[AnchorType.R.ordinal()].rect,size.x-anchorSize, (size.y-anchorSize)>>1);        setAnchorPos(anchors[AnchorType.LB.ordinal()].rect,0, size.y-anchorSize);        setAnchorPos(anchors[AnchorType.B.ordinal()].rect,(size.x-anchorSize)>>1, size.y-anchorSize);        setAnchorPos(anchors[AnchorType.RB.ordinal()].rect,size.x-anchorSize, size.y-anchorSize);    }    private void setAnchorPos(Rectangle anchorRect,int x,int y){        anchorRect.x=x;        anchorRect.y=y;    }    /**     * 计算指定的坐标(x,y)是否位于某个{@link Anchor}区域     * @param x     * @param y     * @return 返回 {@link #anchors}的索引值,不在任何一个{@link Anchor}则返回-1     */    private int anchored(int x,int y){        for(int i=0;i<anchors.length;++i){if(anchors[i].rect.contains(x, y))return i;}        return -1;    }    private void setOriginalBounds(Rectangle rect){        // 如果originalBounds没有初始化,则用第一次调用setBounds的参数来初始化        if(null==originalBounds)            originalBounds=rect;        else if(originalBoundsNeedupdate)// 非zoom状态下更新将当前窗口的尺寸换算后更新originalBounds            originalBounds=unZoom(zoomX,zoomY);    }    @Override    public void setBounds(int x, int y, int width, int height) {        super.setBounds(x, y, width, height);        // 重写setBounds方法,修改窗口位置和尺寸时同步重新计算所有锚点位置        setAnchors();        setOriginalBounds(new Rectangle(x, y, width, height));    }    @Override    public void setBounds(Rectangle rect) {        super.setBounds(rect);        // 重写setBounds方法,修改窗口位置和尺寸时同步重新计算所有锚点位置        setAnchors();        setOriginalBounds(rect);    }    /**     * 根据zoom缩放比例缩放矩形显示     * @param zoomX x轴缩放比例     * @param zoomY y轴缩放比例     */    protected void zoom(float zoomX, float zoomY) {        if(null!=originalBounds){            this.zoomX=zoomX;            this.zoomY=zoomY;            setBounds(new Rectangle((int)(originalBounds.x*zoomX),(int)(originalBounds.y*zoomY),(int)(originalBounds.width*zoomX),(int)(originalBounds.height*zoomY)));        }    }    /**     * x,y轴等比例缩放     * @param rect     * @param zoom x,y轴缩放比例     * @see #zoom(float, float)     */    void zoom(Rectangle rect, float zoom) {             zoom(zoom,zoom);    }    /**     * 根据zoom缩放比例返回缩放前的矩形对象({@link Rectangle})     * @param zoomX x轴缩放比例     * @param zoomY y轴缩放比例     * @return     */    protected Rectangle unZoom(float zoomX, float zoomY) {          Rectangle bounds = getBounds();        return new Rectangle((int)(bounds.x/zoomX),(int)(bounds.y/zoomY),(int)(bounds.width/zoomX),(int)(bounds.height/zoomY));         }    /**     * x,y轴等比例缩放     * @param zoom x,y轴缩放比例     * @return     * @see #unZoom(float, float)     */    protected Rectangle unZoom(float zoom) {            return unZoom(zoom,zoom);           }}

测试代码
TestActiveRectangle.java

package testwb;import org.eclipse.swt.widgets.Dialog;import org.eclipse.swt.widgets.Display;import org.eclipse.swt.widgets.Shell;import net.gdface.ui.ActiveRectangle;import org.eclipse.swt.widgets.Composite;import org.eclipse.swt.SWT;import org.eclipse.swt.widgets.Group;import org.eclipse.swt.widgets.Control;public class TestActiveRectangle extends Dialog {    protected Object result;    protected Shell shell;    /**     * Create the dialog.     * @param parent     * @param style     */    public TestActiveRectangle(Shell parent, int style) {        super(parent, style);        setText("SWT Dialog");    }    /**     * Open the dialog.     * @return the result     */    public Object open() {        createContents();        shell.open();        shell.layout();        Display display = getParent().getDisplay();        while (!shell.isDisposed()) {            if (!display.readAndDispatch()) {                display.sleep();            }        }        return result;    }    /**     * Create contents of the dialog.     */    private void createContents() {        shell = new Shell(getParent(), getStyle());        shell.setSize(463, 366);        shell.setText(getText());        Group group = new Group(shell, SWT.NONE);        group.setBounds(10, 10, 423, 302);        Composite composite2 = new ActiveRectangle(group, false, null);        composite2.setBounds(81, 102, 51, 90);        Composite composite1 = new ActiveRectangle(group, true, null);        composite1.setBounds(24, 141, 147, 90);        group.setTabList(new Control[]{composite2, composite1});        shell.setTabList(new Control[]{group});    }}
0 0