万星星@豌豆荚 欢迎加入我们
一个吃软饭的男人!!!!!我只想写程序####
微博:http://weibo.com/wanlianwen
posts - 172,  comments - 1253,  trackbacks - 0

一个软件专业与否,在细微之处体现的淋漓精致。目前软件开发基于组件思想,使得软件开发像搭积木一样。软件模块的封装分两种,一种是业务功能的封装(我称它为组件),一种是表现界面的封装(我称它为控件)。

组件的封装因为与界面无关,所以问题大多在接口数据类型上。控件与界面有关,很多朋友在开发控件的时候很有激情,看着自己的东东在什么环境下面都可以使用,很是有成就感。然而稍有专业水准的人应该会发现这不是一件完美的事情,因为microsoft没有为activex控件处理加速键消息处理,以至于导致很多问题:up、down、left、right、home、end、tab、backspace等在自己的控件里面不起作用,编辑框无法删除字符,tab键无法跳转到下一个控件上。我是深受其害,以至于有一年多不敢染指控件开发。这个问题很多人遇见过,但是没见到谁给出个好的方法来。

对于上面的问题,微软也意识到,但是一直没有给出完美的一套方案,只是在msdn里面零星提到一下,给出了一个基于mfc activex的解决办法。由于我一般使用atl开发控件,所以那个办法我一直未曾感到满意过。上网搜索不少,一般都不能解决实质性问题,有甚者把钩子都搬出来,个人觉得没有那么大必要,毕竟我一般不敢将hook技术应用在大软件里面。我依据个人摸索,基本解决了大部分问题,当然任何事情都是不完美的,拿出来为了一个csdn朋友需要,也为了大家提出更好的解决办法。

本篇以vs2005环境,实做出atl标准控件、复合控件,测试环境分别为VB6  VC6(dialog) .net(C#) IE。分别展示出问题以及解决办法,记忆里vb控件在mfc里面也有问题(好像tab键出不去,需要一个隐藏控件),对于此本文不做探讨,如有需要,下次在说。

这里先谈谈做控件的选择:标准控件分无窗口和有窗口。
如果只设计图形操作,不需要窗口,可以通过IOleObject来解决位置以及大小,这样可以减少不少控件的尺寸。
对于有窗口的控件,一般情况是一个做好的窗口类,为了封装以使用于各种开发环境而依附到atl控件窗口上面(至于不创建窗口可否?当然可以,这里不想讲,牵扯太远)。对于这种控件个人认为最好只依附一个窗口,如果想依附几个窗口,请使用复合控件。
复合控件类似一个对话框面板,你可以托放控件到面板上,这种控件问题比较少,我推荐使用窗口控件的人选择此类型,尽管dll尺寸可能大点。

标准带窗口控件问题:
我制作的控件是一个edit创建在atl窗口上面,不作任何处理在各种环境里面使用情况如下:
VB6:Tab正常,但是在atl控件的时候,edit无Caret(不知道怎么翻译)闪烁,并且鼠标点击在里面后有Caret,然而按下左键跑到上一个tab窗口上面去了。
VC6:比VB6好一点,左右键是好的,也是tab后无Caret闪烁
.net:和VB6情况一样,无语,难怪.net和VB6一样好用(^_^,没有瞧不起.net,我深受VC之苦,好想用.net开发界面)
IE:和VB6大致一样就是左右键全部不起作用。

处理方法:
1、添加SetFocuse消息处理:

LRESULT CATLFullCtrl_Step2::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &  bHandled)
{
    
//  TODO: 在此添加消息处理程序代码和/或调用默认值
    LRESULT lRes  =  CComControl < CATLFullCtrl_Step2 > ::OnSetFocus(uMsg, wParam, lParam, bHandled);
    
if  (m_bInPlaceActive)
    
{
        DoVerbUIActivate(
& m_rcPos,  NULL);
        
if ( ! IsChild(::GetFocus()))
        
{
            m_wndEdit.SetFocus();
        }

    }

    
return  lRes;
}

当atl控件接到focuse消息后,把焦点给edit窗口。还不够,接着是主要的:
2、重载加速键需函数:
让我们先看看微软做了什么:
BOOL PreTranslateAccelerator(LPMSG /*pMsg*/, HRESULT& /*hRet*/)
    {
        return FALSE;
    }
靠,明显不作为嘛!什么都不处理,怎么可能正确啊......
我来试一试:
BOOL CATLFullCtrl_Step2::PreTranslateAccelerator(LPMSG pMsg, HRESULT& hRet)
{
    // TODO: 在此添加专用代码和/或调用基类
    if(pMsg->message == WM_KEYDOWN &&
        (pMsg->wParam == VK_LEFT ||
        pMsg->wParam == VK_RIGHT ||
        pMsg->wParam == VK_UP ||
        pMsg->wParam == VK_DOWN))
    {
        hRet = S_FALSE;
        return TRUE;
    }
    return __super::PreTranslateAccelerator(pMsg, hRet);
}
为什么??还记得前面的问题嘛??Tab键好像是好的,就是左右键不正确啊,^_^,这里我假设处理拉,你就别跳别处了好嘛???
下面来看看各种环境里面使用情况:
VB6:正常
VC6:正常
.net:正常
IE:第一此tab到控件焦点控件外框,点击编辑框之后下次就是好的了。不晓得是不是我没有处理好。

复合控件的问题:
我制作的复合控件是一个按钮、一个复选框、一个编辑框、一个单选框。不作任何处理在各种环境里面使用情况如下:
VB6:没大毛病,就是默认焦点在复合控件第一个tab窗口上(假象,你切换一下窗口就恢复到正常情况下,但是复合控件button里面按钮的默认黑色外框还有,我实在处理不好),且编辑框输入汉语是乱码(好像与Unicode编码有关)。
VC6:很完美,还是自产自消比较对路。
.net:和VB6情况差不多,但是没有乱码问题。
IE:问题不大,你自己看看,实在不好描述,我保证不影响使用。

处理方法:
1、乱码问题,不要问我为什么,我也是瞎蒙的,^_^。不过你要想知道为什么复合控件问题这么少,我建议你看看基类CComCompositeControl的PreTranslateAccelerator实现,晕,那么多判断代码,还有问题,咳,不说了。
STDMETHOD(TranslateAccelerator)(LPMSG pMsg)
    {
        if(pMsg->message == WM_CHAR)
        {
            return S_FALSE;
        }
        HRESULT        hr    = NO_ERROR;
        hr = IOleInPlaceActiveObjectImpl
<CATLCompoundCtrl_Step2>::TranslateAccelerator(pMsg);
        if(hr != S_OK)
        {
            CComQIPtr
<IOleControlSite,&IID_IOleControlSite>    spCtrlSite(m_spClientSite);
            if(spCtrlSite)
            {
                hr = spCtrlSite->TranslateAccelerator(pMsg, 0);
                if(hr != S_OK)
                {
                    IsDialogMessage(pMsg);
                }
            }
        }
        return S_OK;
    }
主要解决乱码的就是那段判断WM_CHAR消息返回S_FALSE的代码。下面那段代码借用microsoft的,呵呵。
2、VB6那个假象focus处理,这个我是在VB6里面做的,就是强制focus到form第一个tab窗口上,焦点倒是对了,但是复合控件上面那个按钮的默认黑色外框在tab一个轮回后才正常。处理代码:
Private Sub Form_Activate()
    Command1.SetFocus
End Sub
3、.net以及IE的我没有解决掉那个假focus,望高人支招。
下面来看看各种环境里面使用情况:
VB6:那个默认按钮黑色外框没解决掉,其他ok
VC6:完美
.net:假focuse没有解决掉
IE:假focuse没有解决掉

下面来总结一下:
好像没有一种万能办法可以解决掉所有情况下的问题,我尝试很久总结出这些东西不知道算不算好的办法,但是还算是消除了一些关键问题,不知道是否使用你遇到的问题。.net控件好像很方便也没有那么多资源切换啊,加速键消息处理问题啊。没办法,我们这些it“马崽”很多事情是不由自己的。

遗留问题:
假focuse、默认按钮黑色外框没有处理好。

代码下载

说明:包括activex控件、VB6测试、VC6测试、.net测试。
posted on 2006-11-17 21:40 万连文 阅读(2287) 评论(1)  编辑 收藏 引用 所属分类: ATL

FeedBack:
# re: activex控件加速键消息处理不完全方案
2007-01-08 19:45 | Philip
同感,我做一个看似简单的按纽控件的加速键,也是头大,最后用hook处理的,为避免窗体中有多个按纽时相互转发重复消息,就采用指定第一个按纽实例负责转发消息的古怪方式,而且按纽在vba中还处理不了加速键.  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


简历下载
联系我

<2006年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

常用链接

留言簿(66)

随笔分类

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜