请问
1、TCustomForm 中WantChildKey函数是做什么用的。
2、它在TCustomActiveForm类中有什么特殊的含义。
3、为什么在TCustomActiveForm类的对象中,如果包含编辑控件,并且编辑控件按下方向键,在WantChildKey中的child参数始终是TCustomActiveForm的派生类对象,而并不是相应的编辑控件呢?(只有方向键是这样)
4、如何使其中的编辑控件获得方向键信息?(最关心这条)

解决方案 »

  1.   

    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.————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  2.   

    前两条可能你说的对。但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函数被调用之前,方向键已经被屏蔽掉了。所以想要在该方法中做文章的可能性不大了。
      

  3.   

    TExeTemplet是什么?你是将一个ActiveXForm放在它上面么?————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  4.   

    TExeTemplet = class(TActiveForm, IExeTemplet)
      

  5.   

    你可以调试AxCtrls单元的function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;中的代码。我这里无法运行ActivexForm————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  6.   

    各位大侠,请最好在解决小弟的问题之前先做一个简单的例子。如下
    new --- active form
    添加memo在窗体上,memo1.align:= alClient;
    注册该activexComponent---添加刚才注册的activex控件new --- application
    在窗体上放一个刚添加的activex控件。运行。
    使memo获得输入焦点,按下方向键,看memo是否有响应
      

  7.   

    我也想调试那个方法,因为我看到其中调用了oleinpalce……的那个方法,但是我不知道返回S_OK是什么含义。还有就是如何直接调试(不使用载体)
      

  8.   

    我知道问题的原因了。
    将TExeTemplet.WantChildKey中的
    Result := false;
    放到最后。————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  9.   

    没有用的
    在function TActiveXControl.TranslateAccelerator(var msg: TMsg): HResult;中
    对于方向键调用(包括home和end)
    Control.Perform(CM_WANTSPECIALKEY, wParam, 0) <> 0;
    对于home和end调用的结果是0,而left..down调用的结果是非0
      

  10.   

    对,上面那个“放到最后”写错了,是没用的。
    不过我现在已经感觉很奇怪了。我这里作出来的结果和你相反,就是无论按下什么键,都能正确显示Control.ClassName。
    但是开始是不行的,有一次将Result  :=  false;  改为了Result  :=  True;  就可以了。最后再改回去还是可以,即使新建一个ActivexForm也正确!?————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  11.   

    对,上面那个“放到最后”写错了,是没用的。
    不过我现在已经感觉很奇怪了。我这里作出来的结果和你相反,就是无论按下什么键,都能正确显示Control.ClassName。
    但是开始是不行的,有一次将Result  :=  false;  改为了Result  :=  True;  就可以了。最后再改回去还是可以,即使新建一个ActivexForm也正确!?————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  12.   

    说明一点,我这里无论如何作不出“弹出的信息都是“TExeTemplet””的效果。如果你测试时,窗体上除了放置ActivexForm,且还有别的窗口控件如TEdit、TButton的话,那么在ActivexForm中的控件上按下方向键时,焦点应该跳转到主窗体的别的控件上(这个是TControl.WndProc处理的,不需要说),因此最后显示最后跳转到的控件的类名,但是应该不可能显示ActivexForm的类名吧(难道焦点跳转到它上面?当然是不可能的,它本身不能获得焦点)。————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  13.   

    我是delphi6和win2000。按下方向键后无法显示出出类名
    可不可以把你ocx发给我?
    [email protected]
      

  14.   

    使memo获得输入焦点,按下方向键,看memo是否有响应
    =================================================没有响应!!我觉得应该在注册前先提前把事件写好了,到时候调用就行了
    一旦注册以后,……正在研究中
      

  15.   

    我认为关键在于
    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;
      

  16.   

    对于方向键,显示的信息是0,对于home和end显示的信息是1。这是为什么?
      

  17.   

    不用发ocx了,本质上就是方向键被TActiveXControl转化为类似TAB键的功能,实现焦点转移,可以看作一个屏蔽。因此需要在这里作文章,其他的如让ActiveXForm.KeyPress=True等都不要考虑。其实方法是有的,待会看能不能给你一段代码。————————————————————————————————————
    宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
    ————————————————————————————————————
      

  18.   

    晕刚刚试了下,在注册前加的事件Procedure TActiveFormX.Memo1KeyDown(Sender: TObject; Var Key: Word;
       Shift: TShiftState);
    Begin
       Case key Of
         VK_UP: showmessage('UP');
         VK_DOWN: showmessage('DOWN');
       End;
    End;在编辑的时候响应??? 在运行以后反而不响应了???
      

  19.   

    2  lxpbuaa(桂枝香在故国晚秋) 
    对,我也同意你上面的说法,不过还不知道在什么地方解决
      

  20.   

    to ad
    在编辑的时候消息是靠Form.Designer.IsDesignMsg(Self, Message)传递的,好象正好被delphi给搞反了。
      

  21.   

    刚才已经说过,问题关键似乎在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;
    大家有兴趣不妨试试第一种方法。
      

  22.   

    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   │───╮   
           ╰╮  ─╯    ╞╮    
                 │ ┌─╮    │╰=    
               └└┘└└─┘
      

  23.   

    re lxpbuaa(桂枝香在故国晚秋) 通过观察发现,在TActiveXControl.TranslateAccelerator中的control实际就是一个tactiveform对象。
    “ActiveXForm中根本就没有子控件的概念”着是什么意思?
    ActiveControl返回的不是当前焦点控件吗?
      

  24.   

    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   │───╮   
           ╰╮  ─╯    ╞╮    
                 │ ┌─╮    │╰=    
               └└┘└└─┘