VB6.0自制Line控件时实现X1,Y1,X2,Y2属性
2024-07-21 02:21:10
供稿:网友
line控件本来是最简单的一个控件,但它太简单了,以至于不提供我们想要的一些事件,为了增强它的功能,我自己制作了一个line控件,还
给她取名叫作mline控件。
制作控件的方法请参看"msdn - visual basic 文档 - 使用visual basic -部件工具指南 - 创建activex部件"中的"创建一个activex控件"和"
建立activex控件"部分。
vb自带的line控件有x1,x2,y1,y2四个属性,没有left,top,width,height这四个属性,通过调整x1-y2四个属性的值,来改变线条的位置和形状
。但,我们的mline控件中只有ltwh这四个属性,所以mline控件的关键在于如何把ltwh四个属性跟x1-y2四个属性联系起来。
很显然,如果mline控件中的线条是从左上角到右下角的话,那么:
a1=left : b1=top : a2=left+width : b2=top+height
这里我用(a1,b1)表示左上角的坐标,(a2,b2)表示右上角的坐标,这样我就可以通过a1-b2来确定控件的区域了,但并不能确定直线的形状,也
就是说直线是撇倾斜还是捺倾斜,通过a1-b2无法确定,我们需要一个标志变量来记录这个倾斜值,下面会说到。
好了,a1-b2显然和ltwh是一一对应的,我们可以写出:
left=a1 : top=b1 : wdith=a2-a1 : height=b2-b1
a1=min(x1,x2) : b1=min(y1,y2) : a2=max(x1,x2) : b2=max(y1,y2)
通过上面的关系,我们把x1-y2和ltwh联系起来了。
那么你去做吧,基本上这个线条可以画出来,但不会太精确,在线条接近水平或垂直的时候就会有误差了,出现误差的原因是,控件有一个最
小宽度和最小高度!你可以随便建立一个exe工程观察一下常用的控件,他们的height/width最小只能设置到15或者更大一些,而usercontrol
,也就是我们的控件,其height/width最小只能设置到30,所以如果没有考虑到这个因素,做出来的mline控件总会出现误差的,如果你把做出
来的mline控件,以(x1,y1)为圆心,让(x2,y2)绕着它画圆,你会发现线条的一些细微变化,这种变化是不能容忍的。
所以mline控件的重点是要理解这个控件的真实形状,它不仅仅是一个长方形的区域内做一条对角线,而是这样的一个样子:
在它的区域当中,有一片冗余区域,我们不能在这里画线,理由是这个冗余区域正是这个控件的最小区域。这个冗余区域我设置它为一个空心
矩形,它和mline控件的整个区域是重合的,它中间的空心区域才是我们画线的地方。空心区域应该是由最小宽度和最小高度决定的,让minwid
th表示最小宽度,minheight表示最小高度,那么空心区域和控件区域的左边界=minwidth/2,右边界=minwidth/2,上边界=minheight/2,下边
界=minheight/2,你应该可以想象出来这个样子。
好了,这就是mline控件的重点所在,我们再来调整一下x1-y2和ltwh之间的关系,当然我还是先用a1-b2来解释,这样清楚一点:
a1=extender.left+minwidth/2
b1=extender.top+minheight/2
a2=extender.left+extender.width-minwidth/2
b2=extender.top+extender.height-minheight/2
a2=a1+extender.width-minwidth
b2=b1+extender.height-minheight
extender.left=a1-minwidth/2
extender.top=b1-minheigth/2
extender.width=a2-a1+minwidth
extender.height=b2-b1+minheight
其中a1=min(x1,x2)
b1=min(y1,y2)
a2=max(x1,x2)
b2=max(y1,y2)
看到了吗?a1-b2和ltwh建立了一一对应的关系,而通过min/max方法的计算,我们也可以使x1-y2和ltwh建立对应的关系,但不是一一对应的。
为什么呢?这里我们需要一个标志变量blnk,它表示直线的倾斜方向,也就是说撇倾斜或者捺倾斜,通过blnk,我们才可以使x1-y2和ltwh建立
一一对应的关系,也就是说,我们既可以改变ltwh来引起x1-y2的变化,也可以通过改变x1-y2来改变ltwh,这样我们就得到了属性x1-y2的get/
let方法如下:
(实际应用中,我没有采用blnk来记录倾斜方向,而是用posx1和posy1来记录x1,y1在四个角的位置)
'客户区位置x1
public property get x1() as single
if posx1 = ls_left then
x1 = extender.left + minwidth / 2
else
x1 = extender.left + extender.width - minwidth / 2
end if
end property
public property let x1(byval newx1 as single)
dim oldx2 as single
oldx2 = x2
if newx1 > oldx2 then
'新的x1在x2右边
posx1 = ls_right
extender.left = oldx2 - minwidth / 2
extender.width = newx1 - oldx2 + minwidth
else
'新的x1在x2左边
posx1 = ls_left
extender.left = newx1 - minwidth / 2
extender.width = oldx2 - newx1 + minwidth
end if
propertychanged "x1"
end property
x2,y1,y2的属性方法与此类似,不再赘述。
在paint事件中我们使用line方法来画线,但要记住不是从x1,y1画到x2,y2,而是从x1-extener.left,y-extender.top到x2-extender.left,y2-
extender.top画线。
值得注意的是,有人可能会不明白属性和属性方法get/let之间的关系,因此而造成许多的误会,应该明白x1-y2的值是保存在get方法中的,每
次读取x1-y2都会调用get方法来求得其值,注意!是求得!所以你也可以认为并没有x1-y2这四个变量。而每次设置x1-y2,其实就是在设置ltw
h和posx1、posy1,希望你能对此明了,有的人会在resize/paint事件中去设置x1-y2,然后在x1-y2中又设置ltwh,这样就又会引起resize/pai
nt事件,中间出现递归调用,虽然通过设置标志变量的方法可以防止无限递归,但那样就复杂多了,很遗憾地说,我一开始就是这样做的。
对于x1-y2的let方法的调用,只有三种情况,第一种情况是readproperties,这时会用form中保存的x1-y2来设置x1-y2的值;第二种情况就是
开发者,第三种情况可能会是使用者。
要明白,每次ltwh的变化都会直接引起x1-y2的变化,知道了这一点,就不会再去resize/paint事件中跟踪ltwh的变化了。
菜鸟学堂: