谁能解决这个一直困扰我的问题??!!

时间:2022-04-26 18:34:34
VC中有个问题一直困扰着我,有一次写扑克牌游戏半途而废也是因为这个问题,就是如何使子控件层次化.
比如说在一个窗口上放两个按钮,分别是按钮A、按钮B。
让按钮A压住按钮B的一部分,也就是按钮A在按钮B的上方。
可程序运行后,我点按钮B的时候,按钮A居然跑到按钮B的下面去了。
也就是按钮A根本不能保持在按钮B的上方??!!
谁知道这种问题如何解决??
如何让按钮A始终“摭住”按钮B呢??!!

43 个解决方案

#1


似乎没有这方面的资料
也没有听说啊
只能帮你顶了!

#2


如何让按钮A始终“摭住”按钮B呢??!!
//创建A按钮是B按钮的子窗口应该可以。就好像在Dialog上面放一个按钮,按钮不会被Dialog遮住一样。

不过我感觉这样比较麻烦,我以前写扑克牌游戏没这么做,界面直接用一张内存位图贴上去,有变化就修改内存位图。至于鼠标点击,就判断完鼠标所在位置再触发相关事件。

#3


楼主这样的目的是为了用控件来排扑克牌吧?我以前也试过这么做,但到最后还是改变了方法,如楼上的那位所说,还是直接改图比较好。用鼠标的坐标计算出要按的是哪一个控件。

#4


作为自窗体应该会导致显示区域被限制。
同样,设置按钮B的区域为B-A就可以了,B将不响应且不显示被A遮住的部分。

#5


我查找了关于Z-Order方面的资料,改变控件的z-order也不管用啊.难道没有一种有效的方法来设置控件的相互摭盖吗???!!

#6


当然有了,你可以将Button的父窗口设置成NULL,当然牺牲是很大的,哈哈

#7


不用WS_CHILD来做, 子窗口的Z order是动态改变的,并且不支持TOPMOST, 用弹出窗口试试,B为A的OWNER

#8


我试了,下面这种方法可以解决,不过有点闪:

HBRUSH CLayerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

// TODO: Change any attributes of the DC here
if(pWnd == &m_btnB) 
{
m_btnA.Invalidate();  //  保证画完ButtonA之后重画ButtonB

// //Invalidate();
}

// TODO: Return a different brush if the default is not desired
return hbr;
}

#9


krh2001(边城浪子) 的方法还是不理想,如果控件多了,用这种方法也受不也啊.....
哪位大侠有这方面的经验啊.......
给解决一下啊....

#10


为什么同样的功能在Delphi中是如此地轻松就实现了呢???
而在VC中就这么难实现吗???
大侠快帮帮忙啊!!!!!!!!!!!!!!!!!!!

#11


实际上不用控件也许是更好的方法

#12


象这样的情况,一般不用控件。性能会比用控件高得多,也好控制

#13


用控件的目的是可以更好地响应windows事件.
我已经从CWnd继承下来一些基类,实现了各种点\线\位图等楼空图像的显示.
就是在显示一条线连接两个Bitmap时,连线老是在位图上方,它应该被位图压在下面才对的.
我用setwindowpos函数也不管用.用鼠标点击连线后,它又跑到最顶上来了,气死我了!!!!!!!!!!

#14


比如在一个View上我显示了三个子控件.分别是两个交换机的图象和一条连接线.
交换机控件是从CWnd类继承下来的.连线控件也是从CWnd继承下来的.
我要将连线始终都压在交换机控件的窗口之下.如何实现?

#15


难道没有一个人做过这样的图形系统吗???!!!
救命啊!!!!!!!!!!!!!!!!!!!!!!!!!!!!
大家可以试一试.在窗口上建立三个局部重叠的Button.
我的要求就是这么简单,在单击任何一个Button后,不改变其Z序.但MFC会自动调整控件的Z序????
有什么方法禁止MFC自动调整控件的Z序吗?

#16


做图形系统也不是你这样做的,所有的图元都是一个控件,你能找出这样的软件来吗?

#17


能实现此功能者,我会另开三贴给分,每贴100分!!!!!!!!!!!!!!
在此也谢谢楼上的各位出谋划策,但都不是解决此问题的好方法..............

#18


唉!暂时不讨论什么图形系统了,只要给我实现下面的功能就行:
一个窗口上有n个button,每个button至少与其他button有一块重叠区域.
在点击任何一个button后,不改变其Z序,行了吗???

#19


如果再不明白的话,就打开Delphi,在窗口上放上几个按钮.再用VC建一个窗口,放上几个按钮,运行一下,一比较就明白我的意思了(一定要让按钮有重叠区域)...........

#20


TO  krh2001(边城浪子):
谢谢你的回答,可我现在已经封装好了许多异型窗口类.有点\线\位图等.它们都是从CWnd继承下来的.而且显示在View上的时候是做为一个子控件来显示的,就象窗口上的button一样......

#21


我试过,这个不是Z次序的问题,其实Z次序总是正确的,只不过,按钮重绘的时候它将其上面的给画了。所以只有重绘它上面的控件了

#22


1.可以重载DrawItem 试试
2.可以使用InvalidateRect试试

#23


用API实现和SETPOSITION作用相同但是那个函数我已经不记得了你可以去查一下这方面的API我帮不了你!!

#24


其实还有一点我不明白:既然a一直是在b的下面,那你为什么不把a和b挨在一起,而非要重叠?

#25


To bobo:
首先谢谢你的回答.
是这样的:我从CWnd类继承,封装了一组异型窗口类(全部为镂空显示的异型窗口类):
CLine类是线类.在View上表现为一条镂空显示的线,CLine类有很多方法,如设置线宽.线型,颜色,起止点等.
CBmpNode类是位图窗口类.在View上表现为一个镂空显示的位图.也有很多方法,如设置中心位置\改变位图等.
现在的问题是当我显示一条CLine连接两个CBmpNode的时候,由于我的CLine的起止点是以CBmpNode的中心位置计算出来的.这样在显示出两个BmpNode和CLine后,CLine好象"长"了一小块,CLine应该在它连接窗口的最外缘做为起止点(但由于它连接的两个窗口都是不规则窗口),这样计算最外缘这两个点实在太麻烦,于是我直接取了所连两个结点窗口的CenterPoint做为CLine的起止点.但这样的后果正如前面所说,CLine好象"长"了一小块.我的意思就是把长出来的这一小块压在BmpNode下面.造成与连接窗口外缘相同的显示效果.
唉,说了这么多,不知道你明白点了没有.我自己都快晕了..........

#26


一个回避问题的做法:
如果线是水平的那你就先用二分法配合PtInRegion找到线和窗口的交点,这样可以避免"长"的问题

让我再想想看还有没有别的方法

#27


再配合使用GetRgnBox能缩小二分的区域

#28


刚把我程序放到网上去,
这是我的程序,大家可以看一看,我要的效果就是网元压住连线的效果.
http://www.tongan-jn.com/_derived/tmn.rar

#29


我程序中的连线的网元结点都是可以实时拖动的!
而且全都是镂空显示的.
但就是不知道如何使网元结点始终"压"住连线......
我是仿着法国ILOG公司的产品做的,他们用JAVA写的,产品非常好.

#30


界面永远是VC的痛啊。

#31


是啊,不过我知道我们这些搞VC的人可都是专捡硬骨头啃的一群人啊.... n_n
楼上这位小哥,快给我看看程序吧:
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar

#32


如krh2001(边城浪子)所言。
Delphi自己完成了一些工作,就像Windows完成了鼠标移过以后画面的恢复一样,VC指望不上了。
既然所有的类都是你自己实现的,应该在绘制连线之后重新绘制连线覆盖的网元。肯定也有办法精确找出需要重绘的对象。

#33


呵呵,如果所谓网元也有次序的话,嘿嘿,怕要连锁反应啦:)
那还不如建立一个链表每次挨个刷^_^

#34


记录每个网元区域,在每个网元创建、删除、移动时修改其区域。
在每次重绘一条线的时候遍历网元计算连线途径项,重绘之。
看你程序中的连线只是可以拖动,并不能缩放、旋转,所以可以在改变连线时计算一次,应该另外开一个线程,第一次计算虽然慢,但是这样不影响其他功能的渐次刷新是可以接受的。

#35


学习

#36


难道问题就这样了吗?我没有得到我想要的解决方法啊..............

#37


VB里有种解决的方法,比如按钮A压住B,B压住C,如果这时按了C,一般情况下C就跑最上面来了,但是可以在C被Click的时候按照Z次序依次呼叫按钮的ZOrder方法,就可以保持各按钮的重叠状态保持原样了.比如按C,就要依次呼叫B.Zorder和A.Zorder,如果按了B,就要呼叫A.Zorder,楼主可以跟一下窗口的消息,看看这Zorder方法干了些什么事.

#38


唉!愁啊愁,愁啊愁,愁啊愁,愁啊愁...........
为着这么一个看起来不起眼的小问题,愁啊愁,愁啊愁,愁啊愁.........
愁白了少年头.................

#39


如果你急着实现的话,其实没必要把线连到站标上,让线只能到达图标的边沿又怎么样呢

#40


或者让线与其他控件重合的部分透明也行吧

#41


按钮控件也是窗口呀 用ShowWindow(SW_HIDE)吧
需要用到的时候再SHOW_NORMAL咯

#42


这个问题说来话长.
控制的层次化并不是在WIN API层次实现的,它是在OLE CONTROL中实现的
因为DELPHI,VB都是基于组件开发的,所以没这问题.
VC是基于API的,所以要你自已实现类似于IOleInplaceSite...这系列接口的功能.

就你的情况而言,全部改成OLE 好象工作量太大.

建义作如下改进:
在框架窗口中加入对控制的位置维护,对控制的重绘进行裁剪,对MOUSE消息进行过滤.

在子控制中实现一个类似IViewObject::Draw的接口.重绘代码放在这里.由框架调用绘制.

重绘示例:

框架窗口截获所有子控制的WM_PAINT消息,根据窗口查表调用对应控制的DRAW方法,
将之画在一个内存DC上,然后框架窗口根据子控制的位置信息裁剪后贴到窗口上.

MOUSE KEYBORDER等消息处理与之同理:根据CURSOR的坐标,找到相应的子控制再将消息发给它.

还有什么问题发站内消息给我

#43


roscoe(草上飞) 说得很有道理。

不过,我始终认为在这个应用中对于每个图元做一个HWND不合理。

我觉得不如这样:
class CBase
{
HWND m_hwndParent;//父窗口
DWORD m_dwZorder;
RECT m_rect;//该图元所占据得区域
...
public:
CLine(HWND hParent);
~CLine();
DWORD getType();
....

virtual void OnDraw(HDC hDC)=0;
virtual void OnMouseUp(LPPOINT ppt)=0;
....
};

class CLine
{
DWORD m_dwType;//是否镂空等等
DWORD m_dwLineWidth;
POINT m_ptStart,m_ptEnd;
...
virtual void OnDraw(HDC hDC);//在hDC上的m_rect里绘制线条。
virtual void OnMouseUp(LPPOINT ppt)=0;//执行鼠标触发的操作。
};

在程序里面维护一个所有图元的列表。在父窗口的WM_PAINT,WM_LMOUSECLICK等等消息中检索该列表,确定需要作出反应的图元,然后调用该图元相关的函数。对于WM_PAINT,只需在图元里面维护一个ZORDER,然后绘制的时候按ZORDER来绘制就可以了。

可以封装一个CElementList类,在该类中处理对父窗口的各种消息的分解,图元的检索等等.

感觉如此一来,使用也方便,性能显然要高得多(可使用双缓冲等等),同样可实现各图元对消息的响应,当然可以拖动,稍微花点时间,缩放什么的都是可以实现的。你的问题也自然解决。

#1


似乎没有这方面的资料
也没有听说啊
只能帮你顶了!

#2


如何让按钮A始终“摭住”按钮B呢??!!
//创建A按钮是B按钮的子窗口应该可以。就好像在Dialog上面放一个按钮,按钮不会被Dialog遮住一样。

不过我感觉这样比较麻烦,我以前写扑克牌游戏没这么做,界面直接用一张内存位图贴上去,有变化就修改内存位图。至于鼠标点击,就判断完鼠标所在位置再触发相关事件。

#3


楼主这样的目的是为了用控件来排扑克牌吧?我以前也试过这么做,但到最后还是改变了方法,如楼上的那位所说,还是直接改图比较好。用鼠标的坐标计算出要按的是哪一个控件。

#4


作为自窗体应该会导致显示区域被限制。
同样,设置按钮B的区域为B-A就可以了,B将不响应且不显示被A遮住的部分。

#5


我查找了关于Z-Order方面的资料,改变控件的z-order也不管用啊.难道没有一种有效的方法来设置控件的相互摭盖吗???!!

#6


当然有了,你可以将Button的父窗口设置成NULL,当然牺牲是很大的,哈哈

#7


不用WS_CHILD来做, 子窗口的Z order是动态改变的,并且不支持TOPMOST, 用弹出窗口试试,B为A的OWNER

#8


我试了,下面这种方法可以解决,不过有点闪:

HBRUSH CLayerDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

// TODO: Change any attributes of the DC here
if(pWnd == &m_btnB) 
{
m_btnA.Invalidate();  //  保证画完ButtonA之后重画ButtonB

// //Invalidate();
}

// TODO: Return a different brush if the default is not desired
return hbr;
}

#9


krh2001(边城浪子) 的方法还是不理想,如果控件多了,用这种方法也受不也啊.....
哪位大侠有这方面的经验啊.......
给解决一下啊....

#10


为什么同样的功能在Delphi中是如此地轻松就实现了呢???
而在VC中就这么难实现吗???
大侠快帮帮忙啊!!!!!!!!!!!!!!!!!!!

#11


实际上不用控件也许是更好的方法

#12


象这样的情况,一般不用控件。性能会比用控件高得多,也好控制

#13


用控件的目的是可以更好地响应windows事件.
我已经从CWnd继承下来一些基类,实现了各种点\线\位图等楼空图像的显示.
就是在显示一条线连接两个Bitmap时,连线老是在位图上方,它应该被位图压在下面才对的.
我用setwindowpos函数也不管用.用鼠标点击连线后,它又跑到最顶上来了,气死我了!!!!!!!!!!

#14


比如在一个View上我显示了三个子控件.分别是两个交换机的图象和一条连接线.
交换机控件是从CWnd类继承下来的.连线控件也是从CWnd继承下来的.
我要将连线始终都压在交换机控件的窗口之下.如何实现?

#15


难道没有一个人做过这样的图形系统吗???!!!
救命啊!!!!!!!!!!!!!!!!!!!!!!!!!!!!
大家可以试一试.在窗口上建立三个局部重叠的Button.
我的要求就是这么简单,在单击任何一个Button后,不改变其Z序.但MFC会自动调整控件的Z序????
有什么方法禁止MFC自动调整控件的Z序吗?

#16


做图形系统也不是你这样做的,所有的图元都是一个控件,你能找出这样的软件来吗?

#17


能实现此功能者,我会另开三贴给分,每贴100分!!!!!!!!!!!!!!
在此也谢谢楼上的各位出谋划策,但都不是解决此问题的好方法..............

#18


唉!暂时不讨论什么图形系统了,只要给我实现下面的功能就行:
一个窗口上有n个button,每个button至少与其他button有一块重叠区域.
在点击任何一个button后,不改变其Z序,行了吗???

#19


如果再不明白的话,就打开Delphi,在窗口上放上几个按钮.再用VC建一个窗口,放上几个按钮,运行一下,一比较就明白我的意思了(一定要让按钮有重叠区域)...........

#20


TO  krh2001(边城浪子):
谢谢你的回答,可我现在已经封装好了许多异型窗口类.有点\线\位图等.它们都是从CWnd继承下来的.而且显示在View上的时候是做为一个子控件来显示的,就象窗口上的button一样......

#21


我试过,这个不是Z次序的问题,其实Z次序总是正确的,只不过,按钮重绘的时候它将其上面的给画了。所以只有重绘它上面的控件了

#22


1.可以重载DrawItem 试试
2.可以使用InvalidateRect试试

#23


用API实现和SETPOSITION作用相同但是那个函数我已经不记得了你可以去查一下这方面的API我帮不了你!!

#24


其实还有一点我不明白:既然a一直是在b的下面,那你为什么不把a和b挨在一起,而非要重叠?

#25


To bobo:
首先谢谢你的回答.
是这样的:我从CWnd类继承,封装了一组异型窗口类(全部为镂空显示的异型窗口类):
CLine类是线类.在View上表现为一条镂空显示的线,CLine类有很多方法,如设置线宽.线型,颜色,起止点等.
CBmpNode类是位图窗口类.在View上表现为一个镂空显示的位图.也有很多方法,如设置中心位置\改变位图等.
现在的问题是当我显示一条CLine连接两个CBmpNode的时候,由于我的CLine的起止点是以CBmpNode的中心位置计算出来的.这样在显示出两个BmpNode和CLine后,CLine好象"长"了一小块,CLine应该在它连接窗口的最外缘做为起止点(但由于它连接的两个窗口都是不规则窗口),这样计算最外缘这两个点实在太麻烦,于是我直接取了所连两个结点窗口的CenterPoint做为CLine的起止点.但这样的后果正如前面所说,CLine好象"长"了一小块.我的意思就是把长出来的这一小块压在BmpNode下面.造成与连接窗口外缘相同的显示效果.
唉,说了这么多,不知道你明白点了没有.我自己都快晕了..........

#26


一个回避问题的做法:
如果线是水平的那你就先用二分法配合PtInRegion找到线和窗口的交点,这样可以避免"长"的问题

让我再想想看还有没有别的方法

#27


再配合使用GetRgnBox能缩小二分的区域

#28


刚把我程序放到网上去,
这是我的程序,大家可以看一看,我要的效果就是网元压住连线的效果.
http://www.tongan-jn.com/_derived/tmn.rar

#29


我程序中的连线的网元结点都是可以实时拖动的!
而且全都是镂空显示的.
但就是不知道如何使网元结点始终"压"住连线......
我是仿着法国ILOG公司的产品做的,他们用JAVA写的,产品非常好.

#30


界面永远是VC的痛啊。

#31


是啊,不过我知道我们这些搞VC的人可都是专捡硬骨头啃的一群人啊.... n_n
楼上这位小哥,快给我看看程序吧:
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar
http://www.tongan-jn.com/_derived/tmn.rar

#32


如krh2001(边城浪子)所言。
Delphi自己完成了一些工作,就像Windows完成了鼠标移过以后画面的恢复一样,VC指望不上了。
既然所有的类都是你自己实现的,应该在绘制连线之后重新绘制连线覆盖的网元。肯定也有办法精确找出需要重绘的对象。

#33


呵呵,如果所谓网元也有次序的话,嘿嘿,怕要连锁反应啦:)
那还不如建立一个链表每次挨个刷^_^

#34


记录每个网元区域,在每个网元创建、删除、移动时修改其区域。
在每次重绘一条线的时候遍历网元计算连线途径项,重绘之。
看你程序中的连线只是可以拖动,并不能缩放、旋转,所以可以在改变连线时计算一次,应该另外开一个线程,第一次计算虽然慢,但是这样不影响其他功能的渐次刷新是可以接受的。

#35


学习

#36


难道问题就这样了吗?我没有得到我想要的解决方法啊..............

#37


VB里有种解决的方法,比如按钮A压住B,B压住C,如果这时按了C,一般情况下C就跑最上面来了,但是可以在C被Click的时候按照Z次序依次呼叫按钮的ZOrder方法,就可以保持各按钮的重叠状态保持原样了.比如按C,就要依次呼叫B.Zorder和A.Zorder,如果按了B,就要呼叫A.Zorder,楼主可以跟一下窗口的消息,看看这Zorder方法干了些什么事.

#38


唉!愁啊愁,愁啊愁,愁啊愁,愁啊愁...........
为着这么一个看起来不起眼的小问题,愁啊愁,愁啊愁,愁啊愁.........
愁白了少年头.................

#39


如果你急着实现的话,其实没必要把线连到站标上,让线只能到达图标的边沿又怎么样呢

#40


或者让线与其他控件重合的部分透明也行吧

#41


按钮控件也是窗口呀 用ShowWindow(SW_HIDE)吧
需要用到的时候再SHOW_NORMAL咯

#42


这个问题说来话长.
控制的层次化并不是在WIN API层次实现的,它是在OLE CONTROL中实现的
因为DELPHI,VB都是基于组件开发的,所以没这问题.
VC是基于API的,所以要你自已实现类似于IOleInplaceSite...这系列接口的功能.

就你的情况而言,全部改成OLE 好象工作量太大.

建义作如下改进:
在框架窗口中加入对控制的位置维护,对控制的重绘进行裁剪,对MOUSE消息进行过滤.

在子控制中实现一个类似IViewObject::Draw的接口.重绘代码放在这里.由框架调用绘制.

重绘示例:

框架窗口截获所有子控制的WM_PAINT消息,根据窗口查表调用对应控制的DRAW方法,
将之画在一个内存DC上,然后框架窗口根据子控制的位置信息裁剪后贴到窗口上.

MOUSE KEYBORDER等消息处理与之同理:根据CURSOR的坐标,找到相应的子控制再将消息发给它.

还有什么问题发站内消息给我

#43


roscoe(草上飞) 说得很有道理。

不过,我始终认为在这个应用中对于每个图元做一个HWND不合理。

我觉得不如这样:
class CBase
{
HWND m_hwndParent;//父窗口
DWORD m_dwZorder;
RECT m_rect;//该图元所占据得区域
...
public:
CLine(HWND hParent);
~CLine();
DWORD getType();
....

virtual void OnDraw(HDC hDC)=0;
virtual void OnMouseUp(LPPOINT ppt)=0;
....
};

class CLine
{
DWORD m_dwType;//是否镂空等等
DWORD m_dwLineWidth;
POINT m_ptStart,m_ptEnd;
...
virtual void OnDraw(HDC hDC);//在hDC上的m_rect里绘制线条。
virtual void OnMouseUp(LPPOINT ppt)=0;//执行鼠标触发的操作。
};

在程序里面维护一个所有图元的列表。在父窗口的WM_PAINT,WM_LMOUSECLICK等等消息中检索该列表,确定需要作出反应的图元,然后调用该图元相关的函数。对于WM_PAINT,只需在图元里面维护一个ZORDER,然后绘制的时候按ZORDER来绘制就可以了。

可以封装一个CElementList类,在该类中处理对父窗口的各种消息的分解,图元的检索等等.

感觉如此一来,使用也方便,性能显然要高得多(可使用双缓冲等等),同样可实现各图元对消息的响应,当然可以拖动,稍微花点时间,缩放什么的都是可以实现的。你的问题也自然解决。

相关文章