帮顶有分。制作组合控件,捕获事件的难题。

iamduo 2009-04-27 01:02:31
参考TLabeledEdit控件,我写了一个 TControl+TcxDBTreeList(类似树枝型的DBGrid),这样一个组合控件。
目的是,通过TControl控件点一下鼠标后,后者能下拉显示出来……基本类似TComboBox的下拉效果。
基本都ok了,唯独TControl.OnMouseDown事件的赋值不是在设定属性的时候,而是在调试界面上代码给的。
我尝试了GetWindowLong来截获消息。是TWinControl的时候是可以的。如果是TLabel之类的图形控件的时候,就没有Handle可抓。
我只是想捕获TControl的WM_LBUTTONDOWN,有什么办法吗?
以下贴出,主要结构代码。
...全文
128 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
iamduo 2009-05-05
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 dinoalex 的回复:]
在帮顶,老哥,你的IBM买了没?
[/Quote]
T400 A82,正在用莱。
总体还好,就是有时候键盘会丢失。
呵呵,我还是只懂软件皮毛,硬件一窍不通呐。
iamduo 2009-05-05
  • 打赏
  • 举报
回复
FTargetWCtrl:TWinControl;
FTargetHWND:HWND;//保存DropDown的Handle
FTargetProc:TFarProc;//保存DropDown的原有WndProc
//Assign控件的时候
if not (csSubComponent in FDropListControl.ComponentStyle) then
begin
if FDropListControl is TWinControl then
FTargetWCtrl:=(FDropListControl as TWinControl)
else
FTargetWCtrl:=FDropListControl.Parent;
FTargetHWND:=FTargetWCtrl.Handle;
FTargetProc:=Pointer(GetWindowLong(FTargetHWND,GWL_WNDPROC));
{$WARN SYMBOL_DEPRECATED OFF}
p:=MakeObjectInstance(DropListProc);
{$WARN SYMBOL_DEPRECATED ON}
SetWindowLong(FTargetHWND,GWL_WNDPROC,LongInt(p));
end;
//点击目标控件,使我的TreeList下拉
procedure TCustomDuoDBTreeList.DropListProc(var Msg: TMessage);
function IsControlMouseMsg(var Message: TWMMouse): Boolean;
var Control:TControl;P:TPoint;
begin
Control:=FTargetWCtrl.ControlAtPos(SmallPointToPoint(Message.Pos), False);
Result := False;
if Control <> nil then
begin
P.X := Message.XPos - Control.Left;
P.Y := Message.YPos - Control.Top;
Message.Result := Control.Perform(Message.Msg, Message.Keys, Longint(PointToSmallPoint(P)));
Result := True;
end;
end;
begin
Msg.Result:=CallWindowProc(FTargetProc,FTargetHWND,Msg.Msg,Msg.WParam,Msg.LParam);
case Msg.Msg of
WM_LBUTTONDOWN:begin
if IsControlMouseMsg(TWMMouse(Msg)) then
self.DoDropDown
else if FDropListControl=FTargetWCtrl then
self.DoDropDown;
end;
end;
end;

destructor TCustomDuoDBTreeList.Destroy;
begin
if Assigned(FTargetProc) then SetWindowLong(FTargetHWND,GWL_WNDPROC,LongInt(FTargetProc));
inherited;
end;
//这里稍微说明一下,我有可能设置Button(TWinControl),也有可能设置成Label(TControl)
//前者的消息很好理解,而后者,其实消息是在它的Parent上的。所以,FTargetHWND是Parent.Handle
//只要截获到了消息,想干嘛就干嘛。
//谢谢各位D友。我的多选树枝,和多选下拉树枝同时完成了。

yct0605 2009-04-28
  • 打赏
  • 举报
回复
帮你顶了。
不得闲 2009-04-28
  • 打赏
  • 举报
回复
TControl有自己的消息的都以CM开头
至于,你说的那个可以直接转换一下应该
自己定义一个OnMouseDown事件,用来覆盖原来的事件就可以了
property OnMouseDown: TMouseEvent read GetOnMouseDown write SetOnMouseDown;

procedure GetOnMouseDown;
begin
result := Label.OnMouseDown;
end;

procedure SetOnMouseDown(DownEvent: TMouseEvent);
begin
Label.OnMouseDown : DownEvent;
end;

边缘998 2009-04-28
  • 打赏
  • 举报
回复
顶上先,有等详研究
dinoalex 2009-04-27
  • 打赏
  • 举报
回复
在帮顶,老哥,你的IBM买了没?
数字蛋糕 2009-04-27
  • 打赏
  • 举报
回复
找不到OnMouseDown的话可能是因为你没有在published区段中声明这个事件。
用GetWindowLong截获消息是不是舍近求远了?你直接重载TControl的Click方法不就行了?
xjq2003 2009-04-27
  • 打赏
  • 举报
回复
共同学习
帮你顶
taxi 2009-04-27
  • 打赏
  • 举报
回复
对于TGraphicControl,可以拦截父控件的消息,然后判断鼠标位置是否在该控件上。
iamduo 2009-04-27
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 sanguomi 的回复:]
你得检查 FDropListControl的PARENT是否处理了这个消息,他本身是可以触发的
[/Quote]
我查到的先是 WM_PARENTNOTIFY
然后是 TWMParentNotify
仔细研究一下,估计就有戏了。
待解决后赠分。
kye_jufei 2009-04-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 jason_28693 的回复:]
tcontrol 没有 handle 可以自己构造一个! create的时候分配一个handle, destroy 时候销毁, 并修改一下winproc


private
F_Handle:integer;

Procedure WriteSqlLog(const Str:String);


f_Handle:=classes.AllocateHWnd(wndProc);
classes.DeallocateHWnd(F_Handle);


procedure TSqlFuns.WndProc(var Msg: TMessage);
begin
if Msg.Msg = MSG_RECV_DATA then //转发消息…
[/Quote]
支持
sanguomi 2009-04-27
  • 打赏
  • 举报
回复
你得检查 FDropListControl的PARENT是否处理了这个消息,他本身是可以触发的
iamduo 2009-04-27
  • 打赏
  • 举报
回复
我的意思是TControl可以是TLabel,TImage之类。
鼠标按一下它们,我就ShowList。
请注意一下结构。
TCustomDuoDBTreeList = class(TcxCustomDBTreeList)
private
FDropListControl: TControl;

我要的是FDropListControl的消息,而不是TCustomDuoDBTreeList的消息。

也可能是我理解错了。
请多一点指示。
愿意加分。
sanguomi 2009-04-27
  • 打赏
  • 举报
回复
象二楼说的,创建个句柄应该就可以响应那消息了
sanguomi 2009-04-27
  • 打赏
  • 举报
回复
捕获TControl的WM_LBUTTONDOWN 是可以截下来的,是不是你的父窗口把那消息给截了,没有派发?
我早几天也碰到这问题,不过我的是把控件拉到非客户区去了,结果 CM_MOUSELEAVE类消息可以响应, WM_LBUTTONDOWN类的消息响应不到。
sparklerl 2009-04-27
  • 打赏
  • 举报
回复
Mark

学习
jason_28693 2009-04-27
  • 打赏
  • 举报
回复
tcontrol 没有 handle 可以自己构造一个! create的时候分配一个handle, destroy 时候销毁, 并修改一下winproc


private
F_Handle:integer;

Procedure WriteSqlLog(const Str:String);


f_Handle:=classes.AllocateHWnd(wndProc);
classes.DeallocateHWnd(F_Handle);


procedure TSqlFuns.WndProc(var Msg: TMessage);
begin
if Msg.Msg = MSG_RECV_DATA then //转发消息到调用窗口
begin
.......
end
else
DefWindowProc(F_Handle, Msg.Msg, Msg.wParam, Msg.lParam);
end;
iamduo 2009-04-27
  • 打赏
  • 举报
回复

TCustomDuoDBTreeList = class(TcxCustomDBTreeList)
private
FDropListControl: TControl;
FOldProc:TFarProc;
procedure SetDropListControl(const Value: TControl);
protected
procedure DropListProc(var Msg: TMessage);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property DropListControl:TControl read FDropListControl write SetDropListControl;
end;


procedure TCustomDuoDBTreeList.SetDropListControl(const Value: TControl);
var pp:TPoint;f:TCustomForm;//p:Pointer;
begin
FDropListControl := Value;
// FOldProc:=Pointer(FDropListControl.WindowProc);
// FDropListControl.WindowProc:=DropListProc;
// if FDropListControl is TWinControl then
// begin
// FOldProc:=Pointer(GetWindowLong((FDropListControl as TWinControl).Handle,GWL_WNDPROC));
// p:=MakeObjectInstance(DropListProc);
// SetWindowLong((FDropListControl as TWinControl).Handle,GWL_WNDPROC,LongInt(p));
// end;
end;

procedure TCustomDuoDBTreeList.DropListProc(var Msg: TMessage);
begin
case Msg.Msg of
WM_LBUTTONDOWN:ShowMessage('鼠标按下');
else
Msg.Result:=DefWindowProc((FDropListControl as TWinControl).Handle,Msg.Msg,Msg.WParam,Msg.LParam);// 其它消息做默认处理
end;
end;

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧