请问
1、TCustomForm 中WantChildKey函数是做什么用的。
2、它在TCustomActiveForm类中有什么特殊的含义。
3、为什么在TCustomActiveForm类的对象中,如果包含编辑控件,并且编辑控件按下方向键,在WantChildKey中的child参数始终是TCustomActiveForm的派生类对象,而并不是相应的编辑控件呢?(只有方向键是这样)
4、如何使其中的编辑控件获得方向键信息?(最关心这条)
1、TCustomForm 中WantChildKey函数是做什么用的。
2、它在TCustomActiveForm类中有什么特殊的含义。
3、为什么在TCustomActiveForm类的对象中,如果包含编辑控件,并且编辑控件按下方向键,在WantChildKey中的child参数始终是TCustomActiveForm的派生类对象,而并不是相应的编辑控件呢?(只有方向键是这样)
4、如何使其中的编辑控件获得方向键信息?(最关心这条)
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.————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
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函数被调用之前,方向键已经被屏蔽掉了。所以想要在该方法中做文章的可能性不大了。
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
new --- active form
添加memo在窗体上,memo1.align:= alClient;
注册该activexComponent---添加刚才注册的activex控件new --- application
在窗体上放一个刚添加的activex控件。运行。
使memo获得输入焦点,按下方向键,看memo是否有响应
将TExeTemplet.WantChildKey中的
Result := false;
放到最后。————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
在function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;中
对于方向键调用(包括home和end)
Control.Perform(CM_WANTSPECIALKEY, wParam, 0) <> 0;
对于home和end调用的结果是0,而left..down调用的结果是非0
不过我现在已经感觉很奇怪了。我这里作出来的结果和你相反,就是无论按下什么键,都能正确显示Control.ClassName。
但是开始是不行的,有一次将Result := false; 改为了Result := True; 就可以了。最后再改回去还是可以,即使新建一个ActivexForm也正确!?————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
不过我现在已经感觉很奇怪了。我这里作出来的结果和你相反,就是无论按下什么键,都能正确显示Control.ClassName。
但是开始是不行的,有一次将Result := false; 改为了Result := True; 就可以了。最后再改回去还是可以,即使新建一个ActivexForm也正确!?————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
可不可以把你ocx发给我?
[email protected]
=================================================没有响应!!我觉得应该在注册前先提前把事件写好了,到时候调用就行了
一旦注册以后,……正在研究中
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;
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
Shift: TShiftState);
Begin
Case key Of
VK_UP: showmessage('UP');
VK_DOWN: showmessage('DOWN');
End;
End;在编辑的时候响应??? 在运行以后反而不响应了???
对,我也同意你上面的说法,不过还不知道在什么地方解决
在编辑的时候消息是靠Form.Designer.IsDesignMsg(Self, Message)传递的,好象正好被delphi给搞反了。
通过上面的比较发现,对于方向键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;
大家有兴趣不妨试试第一种方法。
归纳起来,目前就两种方法:
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 │───╮
╰╮ ─╯ ╞╮
│ ┌─╮ │╰=
└└┘└└─┘
“ActiveXForm中根本就没有子控件的概念”着是什么意思?
ActiveControl返回的不是当前焦点控件吗?
归纳起来,目前就两种方法:
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 │───╮
╰╮ ─╯ ╞╮
│ ┌─╮ │╰=
└└┘└└─┘