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
- java SWT入门:自定义背景透明且可鼠标拖动改变尺寸和位置的Composite
- java SWT:基于Composite定制背景透明的浮动图像按钮(image button)
- Qt 背景透明、无边框标题栏、鼠标拖动、定时器、获取屏幕分辨率,设置初始位置
- Qt 背景透明、无边框标题栏、鼠标拖动、定时器、获取屏幕分辨率,设置初始位置
- 自定义导航栏的返回按钮,扩大点击区域,不改变图片的尺寸比例,同时可设置title和image的位置关系
- html可移动的表格,鼠标拖动改变大小
- 鼠标拖动Panel控件,鼠标拖动改变位置
- 鼠标拖动,可改变首列宽度
- AndEngine进阶之自定义可拖动的背景
- 无需自定义UITabbar也可改变UITabbarController的背景和点击和的颜色
- MFC在鼠标自定义的一定的范围内实现拖动窗口移动、错误:不支持尝试执行的操作、实现进度条颜色的渐变或者背景和前景色的改变
- 控件的鼠标拖动和改变大小实现的思考
- 通过鼠标的拖动改变DOM的高度和宽度
- ListView在拖动的时候背景透明
- 【iOS】自定义控件入门:可拖动的环形进度
- VC制作可鼠标拖动及改变大小的矩形:CRectTracker“橡皮筋类”的应用
- 在运行时通过鼠标拖动移动控件位置及改变控件的大小
- 在运行时通过鼠标拖动移动控件位置及改变控件的大小
- PAT 1010. Radix (25)
- scrapy(一)爬取动态网站
- 使用Jersey和Apache Tomcat构建RESTful Web服务
- 继承
- die和exit的区别
- java SWT入门:自定义背景透明且可鼠标拖动改变尺寸和位置的Composite
- 第十四周项目1(1)-验证折半算法
- PAT 1119. Pre- and Post-order Traversals (30)
- Harris角点检测完以后如何进行配准
- android重启应用的方法
- Springboot ServletContextListener 注入失败解决方案
- 有个空语句的问题
- MPEG-7实例入门
- response.setHeader各种用法