您的位置:首页 > 其它

activex控件加速键消息处理不完全方案

2013-11-29 09:03 260 查看
转载地址:

http://blog.csdn.net/wlwlxj/article/details/1393152

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

组件的封装因为与界面无关,所以问题大多在接口数据类型上。控件与界面有关,很多朋友在开发控件的时候很有激情,看着自己的东东在什么环境下面都可以使用,很是有成就感。然而稍有专业水准的人应该会发现这不是一件完美的事情,因为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测试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: