[gdi] 绘制矩形和椭圆,并实现鼠标缩放、拖动

Mr_MAO 2023-10-24 1013

import win.ui;
/*DSG{{*/
var winform=win.form(text="简单的形状画板练习 (点右键弹菜单)"; right=775; bottom=479)
/*}}*/

winform.enableDpiScaling("init");

var shapes= {}; //存储需要绘制形状的表
/**表中内容
[1]={
	style = 1/*rect*/|2/*ellipse*/; //形状样式
	color=0x0000ff;  //形状颜色
	rect= ::RECT();  //形状区域
	z=#shapes+1      //形状z序
};
... 
**/ 
var selID=0;
var newStyle=1; //新建图形的样式
var newColor=1; //新建图形的颜色

var selRc=false //鼠标正在选中的形状
var isDrawing=false //鼠标正在绘制形状

var tmpRc= ::RECT() //存储橡皮筋矩形框

var hdc= ::GetDC(winform.hwnd);
//初始化弹出菜单项
var popmenu=win.ui.popmenu(winform);

popmenu.add("绘制矩形", function(id) {
	newStyle=1;
});

popmenu.add("绘制椭圆", function(id) {
	newStyle=2;
});

//下面代码控制矩形的【缩放】
//小方块gif
var imggp='GIF89a\x07\0\x07\0\x80\0\0\xFF\xFF\xFF\0\0\x80!\xF9\x04\0\0\0\0\0,\0\0\0\0\x07\0\x07\0\0\x02\x0C\x84o\xA1\x9A\x1B\xBD \x03\xEE\xA1S\0\0;';

winform.add(
	gpTopLeft= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=1;
	}

	gpTop= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=2;
	}

	gpTopRight= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=3;
	}

	gpLeft= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=4;
	}

	gpRight= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=5;
	}

	gpBottomLeft= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=6;
	}

	gpBottom= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=7;
	}

	gpBottomRight= {
		cls="picturebox"; left=0; top=0; right=0; bottom=0; image=imggp; autoResize=0; notify=1; z=8;
	}
) 

{
	var gps= {
		winform.gpTopLeft;
		winform.gpTop;
		winform.gpTopRight;
		winform.gpLeft;
		winform.gpRight;
		winform.gpBottomLeft;
		winform.gpBottom;
		winform.gpBottomRight;
	};

	showgps=function(rc) {
		var left=rc.left - 7;
		var top=rc.top - 7;
		var right=rc.right;
		var bottom=rc.bottom;
		var center=rc.left / 2+rc.right / 2 - 3;
		var middle=rc.top / 2+rc.bottom / 2 - 3;

		winform.gpTopLeft.setPos(left, top, 7, 7, 0);
		winform.gpTop.setPos(center, top, 7, 7, 0);
		winform.gpTopRight.setPos(right, top, 7, 7, 0);
		winform.gpLeft.setPos(left, middle, 7, 7, 0);
		winform.gpRight.setPos(right, middle, 7, 7, 0);
		winform.gpBottomLeft.setPos(left, bottom, 7, 7, 0);
		winform.gpBottom.setPos(center, bottom, 7, 7, 0);
		winform.gpBottomRight.setPos(right, bottom, 7, 7, 0);
	}

	hidegps=function() {
		winform.gpTopLeft.setPos(0, 0, 0, 0, 1);
		winform.gpTop.setPos(0, 0, 0, 0, 1);
		winform.gpTopRight.setPos(0, 0, 0, 0, 1);
		winform.gpLeft.setPos(0, 0, 0, 0, 1);
		winform.gpRight.setPos(0, 0, 0, 0, 1);
		winform.gpBottomLeft.setPos(0, 0, 0, 0, 1);
		winform.gpBottom.setPos(0, 0, 0, 0, 1);
		winform.gpBottomRight.setPos(0, 0, 0, 0, 1);
	}

	var minW, minH = 30, 30;

	var limitbound= {
		//限制边界位置
		function(x, y, rc, fRc) {
			if(x<0)x=0;
			if(y<0)y=0;
			if(x>=rc.right)x=rc.right-minW;
			if(y>=rc.bottom)y=rc.bottom-minH;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(y<0)y=0;
			if(y>=rc.bottom)y=rc.bottom-minH;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(x<=rc.left)x=rc.left+minW;
			if(y<0)y=0;
			if(x>fRc.right)x=fRc.right;
			if(y>=rc.bottom)y=rc.bottom-minH;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(x<0)x=0;
			if(x>=rc.right)x=rc.right-minW;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(x<=rc.left)x=rc.left+minW;
			if(x>fRc.right)x=fRc.right;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(x<0)x=0;
			if(y<=rc.top)y=rc.top+minH;
			if(x>=rc.right)x=rc.right-minW;
			if(y>fRc.bottom)y=fRc.bottom;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(y<=rc.top)y=rc.top+minH;
			if(y>fRc.bottom)y=fRc.bottom;
			return x, y;
		};

		function(x, y, rc, fRc) {
			if(x<=rc.left)x=rc.left+minW;
			if(y<=rc.top)y=rc.top+minH;
			if(x>fRc.right)x=fRc.right;
			if(y>fRc.bottom)y=fRc.bottom;
			return x, y;
		};
	};

	var newRect={
		function(rc, x1, y1, x2, y2) {
			rc.move(x2-x1, y2-y1);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.move(0, y2-y1);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.move(0, y2-y1);
			rc.expand(x2-x1, 0);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.move(x2-x1, 0);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.expand(x2-x1, 0);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.move(x2-x1, 0);
			rc.expand(0, y2-y1);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.expand(0, y2-y1);
			return rc;
		};

		function(rc, x1, y1, x2, y2) {
			rc.expand(x2-x1, y2-y1);
			return rc;
		};
	};

	var loadcurse= {
		//cursestyle
		0x7F82;
		0x7F85;
		0x7F83;
		0x7F84;
		0x7F84;
		0x7F83;
		0x7F85;
		0x7F82;
	}

	for (i=1; #gps) {
		gps[ i].wndproc= {
			[0x201 /*_WM_LBUTTONDOWN*/]=function () {
				gps[ i].isDown=true gps[ i].capture=true isDrawing=false;

				var x, y=win.getMessagePos() gps[i].x1,
				gps[i].y1=win.toClient(winform.hwnd, x, y);

				tmpRc=shapes[selID].rect.copy()
				::DrawFocusRect(hdc, tmpRc);
			};
			[0x200 /*_WM_MOUSEMOVE*/]=function() {
				if(gps[i].isDown) {
					var x, y=win.toClient(winform.hwnd, win.getMessagePos())
					::DrawFocusRect(hdc, tmpRc);

					x, y=limitbound[i](x, y, shapes[selID].rect, winform.clientRect) //边界限制
					tmpRc=newRect[i](tmpRc, gps[i].x1, gps[i].y1, x, y)
					::DrawFocusRect(hdc, tmpRc);

					gps[i].x1, gps[i].y1=x, y
				}
			};

			[0x202 /*_WM_LBUTTONUP*/]=function() {
				shapes[selID].rect=tmpRc.copy() 
				showgps(shapes[selID].rect) 
				gps[i].isDown=false 
				gps[i].capture=false 
				winform.redraw()
			}

			[0x20 /*_WM_SETCURSOR*/]=function() {
				win.cur.setCur(win.cur.load(loadcurse[i]));
				return true;
			}
		}
	}
}

//下面代码控制矩形的【选中&移动&右键菜单&删除】
import win.cur;
var moveCur=win.cur.load(32646/*_IDC_SIZEALL*/) 
import win.ui.menu;

winform.wndproc=function(hwnd, message, wParam, lParam) {
	select(message) {
		case 0x201 /*_WM_LBUTTONDOWN*/ {
			x1, y1=win.getMessagePos(lParam);

			if(#shapes>0) {
				for(i=#shapes; 1; -1) {
					//判断鼠标是否在矩形内
					if(shapes[i].style==1 and shapes[i].rect.contains(x1, y1)) {
						selRc=true;
						selID=i break;
					}

					//判断鼠标是否在椭圆内
					if(shapes[i].style==2 and shapes[i].rect.contains(x1, y1)) {
						var a=shapes[i].rect.width() / 2;
						var b=shapes[i].rect.height() / 2;
						var x=x1 - shapes[i].rect.left - a;
						var y=y1 - shapes[i].rect.top - b;

						if(((x/a)**2+(y/b)**2)<=1) {
							//判断鼠标在有效的椭圆面积内
							selRc=true;
							selID=i break;
						}
					}
				}

			}

			if(selRc) {
				winform.capture=true win.cur.setCur(moveCur);
				isDrawing=false;

				var v=shapes[selID] 
				tmpRc=v.rect.copy() //图像前置一下

				select(v.style) {
					case 1 /*rect*/ {
						gdi.fillRect(hdc, v.color, v.rect)
					}

					case 2 /*ellipse*/ {
						var brush=::CreateSolidBrush(v.color)
						::SelectObject(hdc, brush)
						::Ellipse(hdc, v.rect.ltrb())
						::DeleteObject(brush)
					}

					case 3 /*line*/ {}
				}

				//画一个选中的边框
				var hBrush= ::CreateSolidBrush(0x0000FF) //red
				::SelectObject(hdc, hBrush)
				::FrameRect(hdc, tmpRc)
				::DeleteObject(hBrush);

				showgps(tmpRc)
			}

			else {
				hidegps(); selID=0
			}
		}

		case 0x200/*_WM_MOUSEMOVE*/ {
			if(selRc) {
				win.cur.setCur(moveCur);

				::DrawFocusRect(hdc, tmpRc) 
				var x, y=win.getMessagePos(); 
				x, y=win.toClient(hwnd, x, y); 
				tmpRc.offset(x-x1, y-y1) //移动tmpRc

				//边界限制
				if(tmpRc.right<=0) tmpRc.setPos(30-tmpRc.width(), , , ) 
				if(tmpRc.bottom<=0) tmpRc.setPos(, 30-tmpRc.height(), , ) 
				if(tmpRc.left>=winform.clientRect.width()) tmpRc.setPos(winform.clientRect.width()-30, , , ) 
				if(tmpRc.top>=winform.clientRect.height()) tmpRc.setPos(, winform.clientRect.height()-30, , )
				::DrawFocusRect(hdc, tmpRc);
				x1, y1 = x, y;
			}
		}

		case 0x202 /*_WM_LBUTTONUP*/ {
			if(selRc) {
				shapes[selID].rect=tmpRc.copy() 
				showgps(shapes[selID].rect) 
				selRc=false 
				winform.capture=false 
				winform.invalidate()
			}
		}

		case 0x205 /*_WM_RBUTTONUP*/ {
			if(selID) {
				//在选中的形状上弹出
				var popmenu2=win.ui.popmenu(winform);

				popmenu2.add("删除此形状", function() {
					table.remove(shapes, selID) selID=0 selRc=false hidegps() winform.invalidate()
				}) 
				var x, y=win.getMessagePos(lParam);
				if(shapes[selID].rect.contains(x, y)) popmenu2.popup()
			}

			else {
				//在窗体在空白位置(无形状位置)弹出
				var mouseOnsharp=false;
				var x, y=win.getMessagePos(lParam);

				for(k, v in shapes) {
					if(v.rect.contains(x, y)) {
						mouseOnsharp=true break;
					}
				}

				if(not mouseOnsharp) {
					//修改菜单项的checked状态
					popmenu.check(1, (newStyle==1)) popmenu.check(2, (newStyle==2)) popmenu.popup()
				}
			}
		}

		case 0xF /*_WM_PAINT*/ {
			var ps=PAINTSTRUCT();
			var hdc, ps= ::BeginPaint(hwnd, ps) //绘制所有形状

			for(k, v in shapes) {
				select(v.style) {
					case 1 /*rect*/ {
						gdi.fillRect(hdc, v.color, v.rect)
					}
					case 2 /*ellipse*/ {
						var brush=::CreateSolidBrush(v.color)
						::SelectObject(hdc, brush)
						::Ellipse(hdc, v.rect.ltrb())
						::DeleteObject(brush)
					}
					case 3 /*line*/ {}
				}
			}
			::EndPaint(hwnd, ps);
		}
	}
}

//下面代码控制【新建形状】
z_max=0;

winform.wndproc=function(hwnd, message, wParam, lParam) {

	select(message) {
		case 0x201 /*_WM_LBUTTONDOWN*/ {
			if( !selRc) {
				isDrawing=true;
				x1, y1=win.getMessagePos(lParam);
				tmpRc=::RECT(x1, y1, x1, y1)
			}
		}

		case 0x200 /*_WM_MOUSEMOVE*/ {
			if( !selRc && isDrawing) {
				var x, y=win.getMessagePos(lParam);
				::DrawFocusRect(hdc, tmpRc) tmpRc.expand(x-x1, y-y1)
				::DrawFocusRect(hdc, tmpRc) x1, y1=x, y
			}
		}

		case 0x202 /*_WM_LBUTTONUP*/ {
			if( !selRc && isDrawing) {
				isDrawing=false;

				if(tmpRc.left>tmpRc.right) {
					var t=tmpRc.left 
					tmpRc.left=tmpRc.right 
					tmpRc.right=t
				}

				if(tmpRc.top>tmpRc.bottom) {
					var t=tmpRc.top 
					tmpRc.top=tmpRc.bottom 
					tmpRc.bottom=t
				}

				newColor=gdi.RGB(math.random(150, 250), math.random(50, 250), math.random(0, 150));
				z_max++;

				var arr= {
					style=newStyle;
					color=newColor;
					rect=tmpRc;
					z=z_max;
				};
				
				table.push(shapes, arr);
				winform.invalidate()
			}
		}
	}
}

winform.show();
win.loopMessage();


最新回复 (6)
  • 小光芒 2023-10-24
    0 2
    顶一个
  • 光庆 2023-10-24
    0 3
    顶两个
  • Viewer8122 2023-10-24
    0 4
    支持。
  • netfox 2023-10-24
    0 5

    刚看到了js用canvs画这样的东西,aar就写有实例了,都说抖音会推你想看的,难道aar资料网也是吗

  • tanzh 2023-10-25
    0 6
    不错不错
  • ccbwx 2023-10-25
    0 7
返回