高手不要错过哦

fengjn 2003-09-03 10:57:02
请问
1、TCustomForm 中WantChildKey函数是做什么用的。
2、它在TCustomActiveForm类中有什么特殊的含义。
3、为什么在TCustomActiveForm类的对象中,如果包含编辑控件,并且编辑控件按下方向键,在WantChildKey中的child参数始终是TCustomActiveForm的派生类对象,而并不是相应的编辑控件呢?(只有方向键是这样)
4、如何使其中的编辑控件获得方向键信息?(最关心这条)
...全文
65 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
大地精灵 2003-09-04
  • 打赏
  • 举报
回复
现在没时间,做个记号,中午好好看
fengjn 2003-09-04
  • 打赏
  • 举报
回复
大家还有什么好的方法吗?
fengjn 2003-09-03
  • 打赏
  • 举报
回复
前两条可能你说的对。但3、4肯定你没有实际试验过,根本和你说的不一样。对于3有下面的代码
function TExeTemplet.WantChildKey(Child: TControl;
var Message: TMessage): Boolean;
var i: integer;
begin
Result := false;
if message.WParam in [VK_LEFT..VK_DOWN] then
begin
showmessage(Child.ClassName);
end;
end;
当运行的时候,不论在什么编辑控件按下方向键,弹出的信息都是“TExeTemplet”,并不是TEdit或TMemo什么的。所以说在WantChildKey函数被调用之前,方向键已经被屏蔽掉了。所以想要在该方法中做文章的可能性不大了。
lxpbuaa 2003-09-03
  • 打赏
  • 举报
回复
1、当窗体的子控件接受到键盘事件时(如敲击一个键),会调用窗体的WantChildKey,意思是该事件是否由窗体处理(由WantChildKey的返回值决定)。因此可以覆盖WantChildKey从而接管子控件的一些键盘事件。
2、ActiveForm需要处理子控件的一些键盘事件,所以对WantChildKey作了覆盖。
3、child参数始终是TCustomActiveForm的派生类对象?应该不可能。在TControl.WndProc中是这样调用的:Form.WantChildKey(Self, Message)
4、源代码为:
function TCustomActiveForm.WantChildKey(Child: TControl; var Message: TMessage): Boolean;
begin
Result := ((Message.Msg = WM_CHAR) and (Message.WParam = VK_TAB)) or
(Child.Perform(CN_BASE + Message.Msg, Message.WParam,
Message.LParam) <> 0);
end;
你可以覆盖处理它,当是方向键时返回False.

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
guanghui 2003-09-03
  • 打赏
  • 举报
回复
我还是错过好了,帮你UP一下 :)
fengjn 2003-09-03
  • 打赏
  • 举报
回复
你在干什么呢,刚才明明我上面还有一个回复,怎么没了?

牛歪了 :)
lxpbuaa 2003-09-03
  • 打赏
  • 举报
回复
fengjn(小枫) :
归纳起来,目前就两种方法:
1、覆盖TControl.Perform或者WndProc等,对方法方向键作处理。其缺点是要对很多个类作处理,比如你在ActiveXForm上要使用Edit、Button、Memo,那么必须对这三个类作处理。
2、那就是直接改VCL源代码,然后重新编译。不作覆盖了。这种最省事,但是后患最多。

开始我就考虑这两种方法了,但是缺点很明显,所以希望找到另外的解决办法。我曾考虑在ActiveXForm中对它所有子控件的WndProc作一个替换处理,这样无须处理多个类,

回复人:lxpbuaa(桂枝香在故国晚秋) () 信誉:168 2003-9-3 17:07:02 删除

fengjn(小枫) :
归纳起来,目前就两种方法:
1、覆盖TControl.Perform或者WndProc等,对方法方向键作处理。其缺点是要对很多个类作处理,比如你在ActiveXForm上要使用Edit、Button、Memo,那么必须对这三个类作处理。
2、那就是直接改VCL源代码,然后重新编译。不作覆盖了。这种最省事,但是后患最多。

开始我就考虑这两种方法了,但是缺点很明显,所以希望找到另外的解决办法。我曾考虑在ActiveXForm中对它所有子控件的WndProc作一个替换处理,这样无须处理多个类。

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————

╭ ╭──╮ ╮  
╰═@ @ ═╯  
╭oo  │───╮ 
╰╮ ─╯   ╞╮  
│ ┌─╮ │╰=  
└└┘└└─┘
fengjn 2003-09-03
  • 打赏
  • 举报
回复
re lxpbuaa(桂枝香在故国晚秋)

通过观察发现,在TActiveXControl.TranslateAccelerator中的control实际就是一个tactiveform对象。
“ActiveXForm中根本就没有子控件的概念”着是什么意思?
ActiveControl返回的不是当前焦点控件吗?
lxpbuaa 2003-09-03
  • 打赏
  • 举报
回复
fengjn(小枫) :
归纳起来,目前就两种方法:
1、覆盖TControl.Perform或者WndProc等,对方法方向键作处理。其缺点是要对很多个类作处理,比如你在ActiveXForm上要使用Edit、Button、Memo,那么必须对这三个类作处理。
2、那就是直接改VCL源代码,然后重新编译。不作覆盖了。这种最省事,但是后患最多。

开始我就考虑这两种方法了,但是缺点很明显,所以希望找到另外的解决办法。我曾考虑在ActiveXForm中对它所有子控件的WndProc作一个替换处理,这样无须处理多个类,

回复人:lxpbuaa(桂枝香在故国晚秋) () 信誉:168 2003-9-3 17:07:02 删除

fengjn(小枫) :
归纳起来,目前就两种方法:
1、覆盖TControl.Perform或者WndProc等,对方法方向键作处理。其缺点是要对很多个类作处理,比如你在ActiveXForm上要使用Edit、Button、Memo,那么必须对这三个类作处理。
2、那就是直接改VCL源代码,然后重新编译。不作覆盖了。这种最省事,但是后患最多。

开始我就考虑这两种方法了,但是缺点很明显,所以希望找到另外的解决办法。我曾考虑在ActiveXForm中对它所有子控件的WndProc作一个替换处理,这样无须处理多个类。

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————

╭ ╭──╮ ╮  
╰═@ @ ═╯  
╭oo  │───╮ 
╰╮ ─╯   ╞╮  
│ ┌─╮ │╰=  
└└┘└└─┘
fengjn 2003-09-03
  • 打赏
  • 举报
回复
刚才已经说过,问题关键似乎在TActiveXControl.TranslateAccelerator函数的处理上。
通过上面的比较发现,对于方向键Control.Perform(CM_WANTSPECIALKEY, wParam, 0)的返回值为非0,而home和end返回值是0。这个差异导致了该函数无法调用FOleControlSite.TranslateAccelerator,致使方向键被屏蔽。因此,解决的方案就有两种方法。
1、使Control.Perform调用后返回0。
2、在判断是方向键后,调用完DispatchMessage(msg)并不退出,保证程序可以顺利的执行到FOleControlSite.TranslateAccelerator;
由于时间的关系,我采用了第2种方法。但是建议还是使用方法1比较妥当。(第2种简单啊,哈哈)
代码如下:
function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;
var
Control: TWinControl;
Form: TCustomForm;
HWindow: THandle;
Mask: Integer;
begin
with Msg do
if (Message >= WM_KEYFIRST) and (Message <= WM_KEYLAST) then
begin
Control := FindControl(HWnd);
if Control = nil then
begin
HWindow := HWnd;
repeat
HWindow := GetParent(HWindow);
if HWindow <> 0 then Control := FindControl(HWindow);
until (HWindow = 0) or (Control <> nil);
end;
if Control <> nil then
begin
Result := S_OK;
if (Message = WM_KEYDOWN) and (Control.Perform(CM_CHILDKEY, wParam, Integer(Control)) <> 0) then Exit;
Mask := 0;
case wParam of
VK_TAB:
Mask := DLGC_WANTTAB;
VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_HOME, VK_END:
begin
Mask := DLGC_WANTARROWS;
end;
VK_RETURN, VK_EXECUTE, VK_ESCAPE, VK_CANCEL:
Mask := DLGC_WANTALLKEYS;
end;
if (Mask <> 0) and
((Control.Perform(CM_WANTSPECIALKEY, wParam, 0) <> 0) or
((Control.Perform(WM_GETDLGCODE, 0, 0) and Mask <> 0))) then
begin
TranslateMessage(msg);
DispatchMessage(msg);
if not wParam in [VK_LEFT..VK_DOWN] then
Exit;
end;
if (Message = WM_KEYDOWN) and (Control.Parent <> nil) then
Form := GetParentForm(Control)
else
Form := nil;
if (Form <> nil) and (Form.Perform(CM_DIALOGKEY, wParam, lParam) = 1) then
Exit;
end;
end;
if FOleControlSite <> nil then
begin
Result := FOleControlSite.TranslateAccelerator(@msg, GetKeyModifiers);
end
else
Result := S_FALSE;
end;
大家有兴趣不妨试试第一种方法。
lw549 2003-09-03
  • 打赏
  • 举报
回复
up
fengjn 2003-09-03
  • 打赏
  • 举报
回复
哈哈,好象有眉目了。等我整理一下大家在研究研究
fengjn 2003-09-03
  • 打赏
  • 举报
回复
to ad
在编辑的时候消息是靠Form.Designer.IsDesignMsg(Self, Message)传递的,好象正好被delphi给搞反了。
fengjn 2003-09-03
  • 打赏
  • 举报
回复
2 lxpbuaa(桂枝香在故国晚秋)
对,我也同意你上面的说法,不过还不知道在什么地方解决
myling 2003-09-03
  • 打赏
  • 举报
回复


刚刚试了下,在注册前加的事件

Procedure TActiveFormX.Memo1KeyDown(Sender: TObject; Var Key: Word;
Shift: TShiftState);
Begin
Case key Of
VK_UP: showmessage('UP');
VK_DOWN: showmessage('DOWN');
End;
End;

在编辑的时候响应??? 在运行以后反而不响应了???

lxpbuaa 2003-09-03
  • 打赏
  • 举报
回复
不用发ocx了,本质上就是方向键被TActiveXControl转化为类似TAB键的功能,实现焦点转移,可以看作一个屏蔽。因此需要在这里作文章,其他的如让ActiveXForm.KeyPress=True等都不要考虑。其实方法是有的,待会看能不能给你一段代码。

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
fengjn 2003-09-03
  • 打赏
  • 举报
回复
对于方向键,显示的信息是0,对于home和end显示的信息是1。这是为什么?
fengjn 2003-09-03
  • 打赏
  • 举报
回复
我认为关键在于
function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;函数
function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;
begin
//……前面被省略了
if Control <> nil then
begin
Result := S_OK;
if (Message = WM_KEYDOWN) and (Control.Perform(CM_CHILDKEY, wParam, Integer(Control)) <> 0) then Exit;
Mask := 0;
case wParam of
VK_TAB:
Mask := DLGC_WANTTAB;
VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_HOME, VK_END:
begin
Mask := DLGC_WANTARROWS;
showmessage(inttostr(wParam));
end;
VK_RETURN, VK_EXECUTE, VK_ESCAPE, VK_CANCEL:
Mask := DLGC_WANTALLKEYS;
end;
if (Mask <> 0) then //为了便于观察,在这里改变了原来的结构
begin
if (Control.Perform(CM_WANTSPECIALKEY, wParam, 0) <> 0) then
begin
TranslateMessage(msg);
DispatchMessage(msg);
showmessage('0');
Exit;
end else
begin
showmessage('1');
if (Control.Perform(WM_GETDLGCODE, 0, 0) and Mask <> 0) then
begin
TranslateMessage(msg);
DispatchMessage(msg);
showmessage('2');
Exit;
end;
end;
//……后面被省略了
end;
myling 2003-09-03
  • 打赏
  • 举报
回复
使memo获得输入焦点,按下方向键,看memo是否有响应


=================================================没有响应!!



我觉得应该在注册前先提前把事件写好了,到时候调用就行了


一旦注册以后,……

正在研究中


fengjn 2003-09-03
  • 打赏
  • 举报
回复
我是delphi6和win2000。按下方向键后无法显示出出类名
可不可以把你ocx发给我?
ffjn@163.com
加载更多回复(13)

5,388

社区成员

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

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