其实回看学习过程,比较像是学怎么使用mfc来做界面,在这个过程中,程序需要什么样的功能、模样,然后就开始对应的去找怎么实现它们,也许问题都解决了,但回想的时候总觉得实际学到的很少。 深入浅出mfc很多人推荐,但一直没看完。很多功能什么的大概属于知道怎么去用,但是从框架什么的来说就觉得所知道的还是太少。
大概总结下过程吧。希望能把学习过程中走过的弯路和收获都记录下,虽然可能多数已经忘了> <~ 可能分几篇,每篇包含一个特定的分类。这篇就是CMFCOutlookBar了。
需要一个类似outlookbar的侧边栏,包含入网、邮件、短信、通话、系统设置等几个大类,点开后显示具体按钮,如邮件点开后出现收件箱/发件箱/草稿箱等。点击左边的按钮对应右边会切换界面。这个当时想了好久怎么实现,大概是单文档多视图的思路 > < 后来通过学习vs的示例OutlookDemo和OutlookMultiViews整合了下,OutlookDemo中有outlookBar的代码部分,OutlookMultiViews有点击按钮切换界面部分。但是! OutlookMultiViews中切换的是CView类型的界面,这里比如说邮件界面,需要上方有一个工具栏(发送邮件回复邮件等),和下面的邮件显示部分(一个list),(参照windows的Outlook), 比如说呼叫界面,左边是通讯记录(list),右边是拨号盘(cfromview)。处理方法改天写在另一篇里面,大概是每个界面用一个CFrameWnd包括起来,里面可以分割界面或者添加工具栏等,然后切换界面的时候切换CFrameWnd。
程序用的文档/视图结构。
OutlookDemo示例中,MainFrm.h中类CMyOutlookBar继承自CMFCOutlookBar (: CBaseTabbedPane : CDockablePane, 这里弄清最初继承自什么类有利于后面的理解)。CMainFrame中有两个CMyOutlookBar类型的成员变量m_wndBarOutlook和m_wndBarOutlook2003, 分别控制两种风格的OutlookBar。区别似乎就只在于CMainFrame的OnCreate实现里, 在创建OutlookBar前调用了下m_wndBarOutlook2003.SetMode2003()。 一个OutlookBar有多个pane,比如上面说的邮件、短信等大类,然后一个pane里包含多个按钮,比如收件箱/发件箱等,或者也可以包含类似日历、tree形控件等,这里只用到按钮。 CreateOutlookBar()中,首先创建pane, 然后通过AddWorkSpace(OutlookDemo中自己实现),给创建的pane添加按钮,然后通过CMFCOutlookBarTabCtrl* pOutlookBar = (CMFCOutlookBarTabCtrl*)bar.GetUnderlyingWindow(); pOutlookBar->AddControl(...)来将pane添加到outlookbar。
这里说说最近的问题。
1. 禁止拖动OutlookBar选项卡。
OutlookBar的选项卡是可以拖动的,拖来拖去容易粗事情,把它固定成不能拖动吧,怎么操作? 尝试了好几个网上搜到的:pane在创建时风格dwStyle里不用AFX_CBRS_FLOAT, 这样似乎会导致拖出去之后就不见了? 去掉pane.EnableDocking之类的地方,导致拖出去之后无法停靠回去。 等等。
后来用了一个比较土鳖的方法,拦截WM_MOUSEMOVE消息。
这里先总结一下,鼠标会产生的消息:WM_LBUTTONDOWN/ WM_LBUTTONUP/ WM_LBUTTONDBLCLK, 鼠标左键在客户区时按下/ 抬起/ 双击。 WM_NCLBUTTONDOWN/ WM_NCLBUTTONUP/ WM_NCLBUTTONDBLCLK, 鼠标左键在非客户区时按下/抬起/双击。
本来想判断下鼠标是否按下,然后在按下状态的时候OnMouseMove就直接返回。 开始想的是,添加一个成员变量m_bIsMouseDown来判断鼠标是否按下,分别重载OnMouseMove, OnLButtonDown, OnLButtonUp等等,在On(NC)LButtonDown中修改值为TRUE, Up中改为FALSE; 但似乎会出问题。其实可以直接判断GetAsyncKeyState(VK_LBUTTON)&0X8000。 因为返回值最高位表示当前是否按下, 所以&0x8000.
另外 直接在CMainFrame里或者CMyOutlookBar里重载这些函数,响应都有点问题。可能是消息直接传递给了例如CMFCOutlookBarPane或者pane里的按钮等控件。
最后用的方法是重载CMyOutlookBar的PreTranslateMessage(MSG* pMsg). 判断pMsg->message == WM_MOUSEMOVE时, 直接return TRUE, 否则调用父类的该函数。
不知是否有其他比较直接的方法,求告知。> <~
待添加~