高手不要错过哦
请问
1、TCustomForm 中WantChildKey函数是做什么用的。
2、它在TCustomActiveForm类中有什么特殊的含义。
3、为什么在TCustomActiveForm类的对象中,如果包含编辑控件,并且编辑控件按下方向键,在WantChildKey中的child参数始终是TCustomActiveForm的派生类对象,而并不是相应的编辑控件呢?(只有方向键是这样)
4、如何使其中的编辑控件获得方向键信息?(最关心这条)
问题点数:50、回复次数:32Top
1 楼guanghui(不归路)回复于 2003-09-03 11:16:03 得分 0
我还是错过好了,帮你UP一下 :)Top
2 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 11:21:02 得分 45
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.
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
3 楼fengjn(颗粒)回复于 2003-09-03 11:38:11 得分 0
前两条可能你说的对。但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函数被调用之前,方向键已经被屏蔽掉了。所以想要在该方法中做文章的可能性不大了。Top
4 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 13:29:50 得分 0
TExeTemplet是什么?你是将一个ActiveXForm放在它上面么?
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
Top
5 楼fengjn(颗粒)回复于 2003-09-03 13:32:41 得分 0
TExeTemplet = class(TActiveForm, IExeTemplet)Top
6 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 13:43:57 得分 0
你可以调试AxCtrls单元的function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;中的代码。我这里无法运行ActivexForm
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
7 楼fengjn(颗粒)回复于 2003-09-03 13:44:28 得分 0
各位大侠,请最好在解决小弟的问题之前先做一个简单的例子。如下
new --- active form
添加memo在窗体上,memo1.align:= alClient;
注册该activex
Component---添加刚才注册的activex控件
new --- application
在窗体上放一个刚添加的activex控件。运行。
使memo获得输入焦点,按下方向键,看memo是否有响应Top
8 楼fengjn(颗粒)回复于 2003-09-03 13:48:30 得分 0
我也想调试那个方法,因为我看到其中调用了oleinpalce……的那个方法,但是我不知道返回S_OK是什么含义。还有就是如何直接调试(不使用载体)Top
9 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 14:06:47 得分 0
我知道问题的原因了。
将TExeTemplet.WantChildKey中的
Result := false;
放到最后。
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
10 楼fengjn(颗粒)回复于 2003-09-03 14:13:32 得分 0
没有用的
在function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;中
对于方向键调用(包括home和end)
Control.Perform(CM_WANTSPECIALKEY, wParam, 0) <> 0;
对于home和end调用的结果是0,而left..down调用的结果是非0Top
11 楼lw549(那个孩子他爹)回复于 2003-09-03 14:14:11 得分 0
MarkTop
12 楼viaboy(平凡)回复于 2003-09-03 14:16:14 得分 0
studyTop
13 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 14:17:02 得分 0
对,上面那个“放到最后”写错了,是没用的。
不过我现在已经感觉很奇怪了。我这里作出来的结果和你相反,就是无论按下什么键,都能正确显示Control.ClassName。
但是开始是不行的,有一次将Result := false; 改为了Result := True; 就可以了。最后再改回去还是可以,即使新建一个ActivexForm也正确!?
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
14 楼fhuibo(永远深爱一个叫“莎”的好女孩儿)回复于 2003-09-03 14:19:18 得分 0
斑竹就是厉害Top
15 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 14:23:51 得分 0
对,上面那个“放到最后”写错了,是没用的。
不过我现在已经感觉很奇怪了。我这里作出来的结果和你相反,就是无论按下什么键,都能正确显示Control.ClassName。
但是开始是不行的,有一次将Result := false; 改为了Result := True; 就可以了。最后再改回去还是可以,即使新建一个ActivexForm也正确!?
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
16 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 14:31:17 得分 0
说明一点,我这里无论如何作不出“弹出的信息都是“TExeTemplet””的效果。如果你测试时,窗体上除了放置ActivexForm,且还有别的窗口控件如TEdit、TButton的话,那么在ActivexForm中的控件上按下方向键时,焦点应该跳转到主窗体的别的控件上(这个是TControl.WndProc处理的,不需要说),因此最后显示最后跳转到的控件的类名,但是应该不可能显示ActivexForm的类名吧(难道焦点跳转到它上面?当然是不可能的,它本身不能获得焦点)。
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
17 楼fengjn(颗粒)回复于 2003-09-03 14:36:59 得分 0
我是delphi6和win2000。按下方向键后无法显示出出类名
可不可以把你ocx发给我?
ffjn@163.comTop
18 楼myling(不理你)回复于 2003-09-03 14:43:09 得分 5
使memo获得输入焦点,按下方向键,看memo是否有响应
=================================================没有响应!!
我觉得应该在注册前先提前把事件写好了,到时候调用就行了
一旦注册以后,……
正在研究中
Top
19 楼fengjn(颗粒)回复于 2003-09-03 14:49:26 得分 0
我认为关键在于
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;
Top
20 楼fengjn(颗粒)回复于 2003-09-03 14:50:47 得分 0
对于方向键,显示的信息是0,对于home和end显示的信息是1。这是为什么?Top
21 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 14:56:35 得分 0
不用发ocx了,本质上就是方向键被TActiveXControl转化为类似TAB键的功能,实现焦点转移,可以看作一个屏蔽。因此需要在这里作文章,其他的如让ActiveXForm.KeyPress=True等都不要考虑。其实方法是有的,待会看能不能给你一段代码。
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————Top
22 楼myling(不理你)回复于 2003-09-03 14:58:11 得分 0
晕
刚刚试了下,在注册前加的事件
Procedure TActiveFormX.Memo1KeyDown(Sender: TObject; Var Key: Word;
Shift: TShiftState);
Begin
Case key Of
VK_UP: showmessage('UP');
VK_DOWN: showmessage('DOWN');
End;
End;
在编辑的时候响应??? 在运行以后反而不响应了???
Top
23 楼fengjn(颗粒)回复于 2003-09-03 15:04:37 得分 0
2 lxpbuaa(桂枝香在故国晚秋)
对,我也同意你上面的说法,不过还不知道在什么地方解决Top
24 楼fengjn(颗粒)回复于 2003-09-03 15:15:11 得分 0
to ad
在编辑的时候消息是靠Form.Designer.IsDesignMsg(Self, Message)传递的,好象正好被delphi给搞反了。Top
25 楼fengjn(颗粒)回复于 2003-09-03 15:21:42 得分 0
哈哈,好象有眉目了。等我整理一下大家在研究研究Top
26 楼lw549(那个孩子他爹)回复于 2003-09-03 15:30:27 得分 0
upTop
27 楼fengjn(颗粒)回复于 2003-09-03 16:27:54 得分 0
刚才已经说过,问题关键似乎在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;
大家有兴趣不妨试试第一种方法。Top
28 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 17:14:27 得分 0
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 │───╮
╰╮ ─╯ ╞╮
│ ┌─╮ │╰=
└└┘└└─┘Top
29 楼fengjn(颗粒)回复于 2003-09-03 17:14:56 得分 0
re lxpbuaa(桂枝香在故国晚秋)
通过观察发现,在TActiveXControl.TranslateAccelerator中的control实际就是一个tactiveform对象。
“ActiveXForm中根本就没有子控件的概念”着是什么意思?
ActiveControl返回的不是当前焦点控件吗?
Top
30 楼lxpbuaa(桂枝香在故国晚秋)回复于 2003-09-03 17:15:26 得分 0
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 │───╮
╰╮ ─╯ ╞╮
│ ┌─╮ │╰=
└└┘└└─┘Top
31 楼fengjn(颗粒)回复于 2003-09-03 17:20:02 得分 0
你在干什么呢,刚才明明我上面还有一个回复,怎么没了?
牛歪了 :)Top
32 楼fengjn(颗粒)回复于 2003-09-04 09:10:19 得分 0
大家还有什么好的方法吗?Top
33 楼geyobing(大地精灵)回复于 2003-09-04 09:14:19 得分 0
现在没时间,做个记号,中午好好看Top




