标题:容器控件拦截容器内控件的方法
只看楼主
sam_jiang
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:542
专家分:781
注 册:2021-10-13
结帖率:97.44%
已结贴  问题点数:20 回复次数:25 
容器控件拦截容器内控件的方法
记得上次发帖求助grid控件的gridhittest事件无法获得正确结果,后来有兄弟用bindevent的方法解决了。但我总记得有简单的方法来传递控件事件给容器控件的,以前在网上有看到过,当时一直没想起来。

最近终于想起来了,分享给大家。今天百度了一下,这个方法叫冒泡事件。。。

想必大家都有用过container,pageframe,commandgroup,grid等容器控件,当点击容器内控件时,首先接收消息的是容器内的最内层的控件,而容器是接收不到的。就像上次我的gridhittest,在grid上点击事件被传递给cell,或者header了,导致gridhittest无法正常工作。而我们编程的过程中,肯定有希望让容器控件来接收用户的鼠标或键盘事件,而不是容器里的控件。举个例子,一个form上有很多控件,用户需要用鼠标动态调整控件的大小,而这些控件是联动的,这就很麻烦,因为要涉及到mousemove事件,当鼠标移动到控件上时,触发的是控件的mousemove事件,移走就触发form的mousemove事件了。。。

最近在写一个prg的文件管理程序,终于实现了!废话不多说,上代码吧。。。

程序代码:
PUBLIC oform1

oform1=NEWOBJECT("form1")
oform1.Show
RETURN


    **************************************************
*-- Form:         form1 (d:\documents\visual foxpro 项目\bubbledevent.scx)
*-- ParentClass:  form
*-- BaseClass:    form
*-- Time Stamp:   11/16/22 09:52:11 PM
*
DEFINE CLASS form1 AS form


    Height = 750
    Width = 1057
    DoCreate = .T.
    AutoCenter = .T.
    Caption = "Form1"
    WindowState = 0
    Name = "Form1"


    ADD OBJECT olecontrol1 AS olecontrol WITH ;
        Top = 35, ;
        Left = 1, ;
        Height = 24, ;
        Width = 280, ;
        Anchor = 0, ;&&当form调整大小时,控件也随之调整
        Name = "Olecontrol1"


    ADD OBJECT olecontrol3 AS olecontrol WITH ;
        Top = 61, ;
        Left = 1, ;
        Height = 688, ;
        Width = 280, ;
        Anchor = (64+2+1), ;&&当form调整大小时,控件也随之调整
        Name = "Olecontrol3"


    ADD OBJECT edit1 AS editbox WITH ;
        Anchor = (64+8+2+1), ; &&当form调整大小时,控件也随之调整
        Height = 714, ;
        Left = 284, ;
        Top = 35, ;
        Width = 771, ;
        Name = "Edit1"


    ADD OBJECT commandgroup1 AS commandgroup WITH ;
        ButtonCount = 6, ;
        Value = 1, ;
        Height = 30, ;
        Left = 1, ;
        Top = 2, ;
        Width = 154, ;
        Name = "Commandgroup1", ;
        Command1.Top = 2, ;
        Command1.Left = 3, ;
        Command1.Height = 25, ;
        Command1.Width = 25, ;
        Command1.Picture = "graphics\bitmaps\offctlbr\small\color\new.bmp", ;
        Command1.Caption = "", ;
        Command1.StatusBarText = "新建一个文件!", ;
        Command1.Alignment = 2, ;
        Command1.Name = "Command1", ;
        Command2.Top = 2, ;
        Command2.Left = 28, ;
        Command2.Height = 25, ;
        Command2.Width = 25, ;
        Command2.Picture = "graphics\bitmaps\offctlbr\small\color\open.bmp", ;
        Command2.Caption = "", ;
        Command2.StatusBarText = "打开一个文件!", ;
        Command2.Alignment = 2, ;
        Command2.Name = "Command2", ;
        Command3.Top = 2, ;
        Command3.Left = 53, ;
        Command3.Height = 25, ;
        Command3.Width = 25, ;
        Command3.Picture = "graphics\bitmaps\offctlbr\small\color\save.bmp", ;
        Command3.Caption = "", ;
        Command3.StatusBarText = "保存文件", ;
        Command3.Alignment = 2, ;
        Command3.Name = "Command3", ;
        Command4.Top = 2, ;
        Command4.Left = 78, ;
        Command4.Height = 25, ;
        Command4.Width = 25, ;
        Command4.Picture = "graphics\bitmaps\offctlbr\small\color\copy.bmp", ;
        Command4.Caption = "", ;
        Command4.StatusBarText = "复制选择的文字", ;
        Command4.Alignment = 2, ;
        Command4.Name = "Command4", ;
        Command5.Top = 2, ;
        Command5.Left = 103, ;
        Command5.Height = 25, ;
        Command5.Width = 25, ;
        Command5.Picture = "graphics\bitmaps\offctlbr\small\color\print.bmp", ;
        Command5.Caption = "", ;
        Command5.StatusBarText = "打印", ;
        Command5.Alignment = 2, ;
        Command5.Name = "Command5", ;
        Command6.Top = 2, ;
        Command6.Left = 128, ;
        Command6.Height = 25, ;
        Command6.Width = 25, ;
        Command6.Picture = "graphics\bitmaps\tlbr_w95\delete.bmp", ;
        Command6.Caption = "", ;
        Command6.StatusBarText = "删除当前文件", ;
        Command6.Name = "Command6"


    ADD OBJECT line1 AS line WITH ;
        Anchor = 10, ;
        Height = 0, ;
        Left = 1, ;
        Top = 32, ;
        Width = 1054, ;
        Name = "Line1"


    ADD OBJECT line2 AS line WITH ;
        Anchor = 10, ;
        Height = 0, ;
        Left = 1, ;
        Top = 33, ;
        Width = 1054, ;
        BorderColor = RGB(255,255,255), ;
        Name = "Line2"


    PROCEDURE Resize
        this.olecontrol1.Width=this.olecontrol3.Width
    ENDPROC


    PROCEDURE MouseMove &&当鼠标移动至2个控件之间,鼠标指针变成可调整边界的形状,进而动态调整控件的边界
        LPARAMETERS nButton, nShift, nXCoord, nYCoord
        IF nxcoord<this.edit1.Left+3 AND nxcoord>this.olecontrol3.Left+this.olecontrol3.Width-3
            this.MousePointer= 9
        *!*        IF nbutton=1 AND this.MousePointer=9
        *!*            this.olecontrol3.Width=nxcoord-this.olecontrol3.left
        *!*            this.olecontrol1.Width=this.olecontrol3.width
        *!*            x=this.edit1.left
        *!*            this.edit1.Left=this.olecontrol3.left+this.olecontrol3.width+3
        *!*            this.edit1.Width=this.edit1.Width+x-nxcoord-3
        *!*        ENDIF
        *!*    ELSE 
        *!*        this.MousePointer= 0 &&不能加这句,否则边框只能向右移,不能左移
        ENDIF

        IF this.MousePointer=9 AND nbutton=1 &&这两个条件顺序不一样居然效果不一样,我也是醉了。
            this.olecontrol3.Width=nxcoord-this.olecontrol3.left
            this.olecontrol1.Width=this.olecontrol3.width
            x=this.edit1.left
            nwidth=this.edit1.width 
            this.edit1.Left=this.olecontrol3.left+this.olecontrol3.width+3
            this.edit1.Width=nwidth+x-nxcoord-3
        ENDIF
    ENDPROC


    PROCEDURE olecontrol1.Refresh
        *** ActiveX 控件方法程序 ***
    ENDPROC


    PROCEDURE olecontrol1.Change
        *** ActiveX 控件事件 ***
    ENDPROC


    PROCEDURE olecontrol1.Init
    ENDPROC


    PROCEDURE olecontrol1.GetFirstVisible
        *** ActiveX 控件方法程序 ***
    ENDPROC


    PROCEDURE olecontrol3.MouseMove
        *** ActiveX 控件事件 ***
        LPARAMETERS button, shift, x, y
        thisform.MouseMove(button,shift,x,y)  &&向容器传递mousemove事件,冒泡。如果容器控件中还有控件,那么继续冒泡
    ENDPROC


    PROCEDURE olecontrol3.DblClick
        *** ActiveX 控件事件 ***
    ENDPROC


    PROCEDURE olecontrol3.Init
        this.Nodes.Add(,,"Root","我的电脑",,)
        DECLARE integer GetLogicalDriveStrings IN WIN32API integer,string@
        cstr=REPLICATE(CHR(0),40)
        n=getlogicaldrivestrings(40,@cstr)
        FOR i=1 TO n STEP 4
            this.nodes.Add(1,4,,SUBSTR(cstr,i,2),,)
        ENDFOR
        this.Nodes.Item(1).Expanded=.t.
    ENDPROC


    PROCEDURE olecontrol3.HitTest
        *** ActiveX 控件方法程序 ***
        LPARAMETERS x, y
    ENDPROC


    PROCEDURE edit1.MouseMove
        LPARAMETERS nButton, nShift, nXCoord, nYCoord

        thisform.MouseMove(nbutton,nshift,nxcoord,nycoord) &&向容器传递mousemove事件,冒泡。如果容器控件中还有控件,那么继续冒泡
    ENDPROC


ENDDEFINE
*
*-- EndDefine: form1
**************************************************


现在就可以动态调整edit控件的大小,以及treeview控件的大小了,所有控件都会随之调整大小。同理如果是grid控件,那么把cell,以及header的事件传递column,再把column的事件传递给grid,如果grid在container里面,或者pageframe里面,那么继续一级一级上传,直到传递给表单,然后我们在表单的事件中统一处理。

如果你们觉得这个方法有用,点个赞吧。。。


[此贴子已经被作者于2022-11-16 22:13编辑过]

收到的鲜花
  • 厨师王德榜2022-11-17 09:11 送鲜花  1朵   附言:有价值的文章
搜索更多相关主题的帖子: 控件 this Left 容器 事件 
2022-11-16 22:11
sam_jiang
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:542
专家分:781
注 册:2021-10-13
得分:0 
刚才贴的代码有个小bug,form的mousemove方法要加一句话,代码如下:
程序代码:
    PROCEDURE MouseMove &&当鼠标移动至2个控件之间,鼠标指针变成可调整边界的形状,进而动态调整控件的边界
        LPARAMETERS nButton, nShift, nXCoord, nYCoord
        IF nxcoord<this.edit1.Left+3 AND nxcoord>this.olecontrol3.Left+this.olecontrol3.Width-3
            this.MousePointer= 9
        ENDIF

        IF this.MousePointer=9 AND nbutton=1 &&这两个条件顺序不一样居然效果不一样,我也是醉了。
            this.olecontrol3.Width=nxcoord-this.olecontrol3.left
            this.olecontrol1.Width=this.olecontrol3.width
            x=this.edit1.left
            nwidth=this.edit1.width 
            this.edit1.Left=this.olecontrol3.left+this.olecontrol3.width+3
            this.edit1.Width=nwidth+x-nxcoord-3
        ELSE
            this.mousepointer =0
        ENDIF
    ENDPROC
2022-11-16 22:31
schtg
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:https://t.me/pump_upp
等 级:贵宾
威 望:67
帖 子:1355
专家分:2534
注 册:2012-2-29
得分:5 
谢谢分享!
2022-11-17 05:50
cssnet
Rank: 4
等 级:业余侠客
威 望:4
帖 子:317
专家分:203
注 册:2013-10-4
得分:5 
这个例子相当于“分割条控件”。
若能将它通用化,做成一个“分割条控件类”,那就用处大大的!
当然,那样一来,还需保存或传递一对“左边那一个、右边那一个,俩邻居对象控件”的参数或者表单自定义属性(后者可能更好些),以记录两个相邻的控件对象引用。
此外,还需考虑增加另一种情况:
不仅仅是左右拖动,上下拖动也应该能同样地处理——对吧?

感谢分享!学习了。
2022-11-17 09:04
厨师王德榜
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:版主
威 望:183
帖 子:942
专家分:4724
注 册:2013-2-16
得分:5 
好帖.我也思考过类似的问题,但没有你想得那么透彻.
2022-11-17 09:11
cssnet
Rank: 4
等 级:业余侠客
威 望:4
帖 子:317
专家分:203
注 册:2013-10-4
得分:0 
以下是引用cssnet在2022-11-17 09:04:35的发言:
若能将它通用化,做成一个“分割条控件类”,那就用处大大的!


发完上一帖后,我才想起来,楼主“一路冒泡往上传递”的目标,最终指向了表单事件。这个恐怕有些不易实现子类化。
先前我们的思路僵化,一心只想着如何用一个可见的图象控件去实现“分割条”,从没想过用表单MouseMove事件去统一调度协调处理邻居控件的位置和大小。确实是个大失误!
这帖子确实有着“一语点醒梦中人”的意义!

2022-11-17 10:52
sam_jiang
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:542
专家分:781
注 册:2021-10-13
得分:0 
回复 4楼 cssnet
上下拖动也是一样的,道理一样!
2022-11-17 11:36
sam_jiang
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:542
专家分:781
注 册:2021-10-13
得分:0 
回复 6楼 cssnet
应该可以做成类,设置2个参数,分别为2个相邻的object! 并不一定是由form来处理,看使用者需求,也可以由某个container控件来统一处理。
2022-11-17 11:44
sam_jiang
Rank: 8Rank: 8
等 级:贵宾
威 望:10
帖 子:542
专家分:781
注 册:2021-10-13
得分:0 
不光是mousemove事件可以这样冒泡处理,click事件也经常有需求从控件传递给容器控件,比如commandgroup,只需在command控件的click事件中加一句,this.parent.click(),然后在commandgroup控件中,根据它的value值,对每个不同的command编写click事件。
2022-11-17 11:50
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:432
帖 子:10064
专家分:41463
注 册:2014-5-20
得分:5 
有点象消息反弹
在表单定义响应反弹的方法,用这个方法来接收反弹对象的数据(包括反弹对象等等),这样表单就可以明确是什么对象弹过来的,之后再作其他处理。
2022-11-17 11:55



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-510672-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018716 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved