近期做东西所遇到的几个MFC恼火的问题及解决方法

来源:互联网 发布:cocos2d游戏源码 编辑:程序博客网 时间:2024/05/17 07:11

可能是心态不太平静,最近写代码效率如此的低,遇到了很多问题,解决起来着实痛苦,耗费了很多时间。

下面列举出来,对网上方法进行总结,顺便记录一下

1.对于单文档中非view,doc,frame,app类的自定义类,继承view,framewnd等中的消息响应

   自己做了个窗口分割,所以需要新加一个视图类,这个视图类继承了CView类,添加之后,可能需要在自定义类中生成一些自己的按钮,或者菜单响应。

  按向导添加ON_COMMAND(最简单的,也比较熟悉,在MFC默认生成的类中会屡试不爽),但这时问题就来了,自定义类中的消息不能正确响应,可以正确添加,首先是无论是菜单还是按钮的图标都是灰色的,无法点击。

  原因:网上说的原因很多,自己理解的是在框架构建完成之后菜单不能自动刷新,导致按钮为灰色,本身可能是只有框架类自己关联的默认类才会有正确的响应。

 解决方法:上述原因自己也不是太清除,但下面的改正方法是没问题,成功解决了问题,就是在MainFrame的构造函数中添加m_bAutoMenuEnable = FALSE;

2.上面的方法解决了按钮为灰色的问题,但是虽然按钮不会灰色,进行点击之后会出现没有反映,也就是无法正确响应

   原因:个人觉得比较靠谱的一个说法就是,在进行消息映射的时候,MFC会自动去系统默认的类中去寻找消息映射,自定义类除非自己添加映射路径,才会被映射到。

   解决方法:重写CMainframe类中的OnCmdMsg()函数,这个函数如果不手动复写在这个类中是看不到的,执行其默认的操作。其中m_MyClass指针就是自定义的类,需要在CMainFrame中    进行声明。

   BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
   {
// 让自定义类第一次尝试该命令,不加这一句,收不到命令
if (m_MyClass->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// 否则,执行默认处理
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
   }

 3.还有一个问题就是头文件相互包含的问题,两个类的头文件相互包含,编译的时候就可能出错,具体的原因不再赘述,自己想一下就会想通,但有时候会忽视,所以需要注意,这种错误出现的时候会很恼火,命名没有问题,却提示缺少‘;’之类的错误。

   解决方法:可以不再头文件中进行包含,在cpp中进行包含就可以避免编译时候出现的问题。

4.下面这个问题困扰了很久,曾几何时因为这个问题有种想砸电脑的冲动

 问题的背景是这样的,自己在自动生成的MFC单文档程序中新添加了一个自定义的视图类,此视图类继承 于CView类。然后在框架中将原来的视图窗口分割成两个视图窗口,一个跟原来保持一致,一个用自定义的视图类进行填充。代码如下红色字体

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
CRect rect;     
GetClientRect(rect);
if(!m_wndSplitter.CreateStatic(this,1,2))
{         
return FALSE;    
}
if(!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CMainView),CSize(rect.Width()/2,100),pContext))     
{         
return FALSE;     
}

if(!m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CCustomView),CSize(100,100),pContext))     
{         
return FALSE;     
}

m_MainView = (CView*)m_wndSplitter.GetPane(0,0);
m_CustomView1 = (CView*)m_wndSplitter.GetPane(0,1);
m_CustomView2 = (CCustomView*)m_wndSplitter.GetPane(0,1);

return TRUE;
}

这里需要注意在窗口分割之后进行视图关联的时候,其实就已经在框架中定义了一个视图对象CMainViewCCustomView(调试的过程中调用了视图类的析构函数暂且这么理解),分别标记为m_CMainView1和m_CustomView1。

然而在上面问题2中,为了自定义的视图类进行正常的消息响应,在框架类中重写了OnCmdMsg()函数,这个函数中使用了框架类中自定义的成员变量m_MyClass,这个成员变量在使用之前需要初始化,比较容易想到的是在框架类构造函数中进行new MyClass,这里是new CCustomView,这样就相当于内存中又分配了一个CCustomView类对象内存,现在就有另一个自定义视图类的对象为m_CustomView2。到这里,框架生成之后,就会有两个视图类的对象。

问题:现在问题就来了,在自定义视图类中定义一个自定义的类,这个类中写一些自己想要实现的算法功能,然后在自定义的视图类进行显示(也就是分割之后的右边的视图窗口进行显示)。视图类中显示,绘制操作所关联的窗口是m_CustomView1(因为其是通过原窗口分割得来的,所以显示的时候会关联到这个对象)。然而在菜单消息映射的时候,其实进入的时候m_CustomView2,因为方法2中已经进行了描述

if (m_MyClass->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;

这里的m_MyClass其实就是m_CustomView2;

现在问题就是通过消息映射进行操作视图类的过程中,实在m_CustomView2中进行的,然而进行显示的过程中是在m_CustomView1中进行的。这个时候就是无论怎么样都没办法正常显示,m_CustomView1中的变量全都是空值。这个问题真是纠结,搞的我郁闷了很久,以后再遇到这种多个类对象的时候,对其进行操作的时候一定要注意。

解决方法,不要单独生成m_CustomView2,将m_CustomView2和m_CustomView1赋成一样的值,只是加个类型的转换。如上面蓝色的代码部分。


5.下面这个问题从其他网站copy出来的,在自己用MFC在视图中添加一个矩形选框的时候,选框绘制出来了,但当鼠标放上面去的时候鼠标会小时。

CRectTracker类的使用方法及其静态库下CRectTracker无法显示鼠标光标解决方案 一 使用方法

1 定义成员变量

CRectTracker m_RectTracker;

2 构造函数设置样式

m_RectTracker.m_nStyle = CRectTracker::resizeOutside|CRectTracker::solidLine;
m_RectTracker.m_nHandleSize = 6;
m_RectTracker.m_rect.SetRect(0,0,0,0);



3 覆盖OnSetCursor 函数,显示鼠标指针形状,修改为如下
BOOL CXX::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (pWnd == this && m_RectTracker.SetCursor(this, nHitTest))
{
return TRUE;
}

return CXX::OnSetCursor(pWnd, nHitTest, message);
}



4 覆盖OnLButtonDown函数,添加如下代码
void CXX::OnLButtonDown(UINT nFlags, CPoint point)
{
if(m_RectTracker.HitTest(point)<0) // 画选择框
{
m_RectTracker.TrackRubberBand(this,point,TRUE);
m_RectTracker.m_rect.NormalizeRect();
}
else // 点矩形选择框
{
m_RectTracker.Track(this,point,TRUE);
m_RectTracker.m_rect.NormalizeRect();
}

Invalidate(); //刷新窗口
return; // 由于鼠标被接管,所以可以直接返回。
CXX::OnLButtonDown(nFlags, point);
}



5 在OnPaint或者OnDraw函数添加

m_RectTracker.Draw(&dc); // 画矩形框



二 解决非控件(对话框,单文档等)静态库中鼠标不见的问题(转自微软)

1 原因:当应用程序通过使用静态库链接到 MFC 时, MFC 资源被编译到应用程序的可执行文件。 应用程序的可执行文件将包括在 Afxres.rc 文件。 若要检查这,单击 资源包含 在 视图 菜单上。 在 Afxres.rc 文件拥有 CRectTracker 使用 MFC 源代码中的资源。 这些资源不是是 _AFX_NO_TRACKER_RESOURCES 时,包括只定义的。 BLOCKS32 项目具有 _AFX_NO_TRACKER_RESOURCES 定义的。 因此,它确实不置于应用程序的可执行映像 CRectTracker 需要的资源。 因此,没有任何所使用的 CRectTracker 游标会在生成该示例通过使用 MFC 静态时显示。


2 解决方案

在资源视图中,在rc中点击 Resource Includes,然后 删除以下行: #define _AFX_NO_TRACKER_RESOURCES。



三 解决控件中静态库鼠标不见的问题

由于在控件的资源里没有_AFX_NO_TRACKER_RESOURCES,所以需要添加#undef _AFX_NO_TRACKER_RESOURCES\r\n。

在资源视图中,在rc中点击 Resource Includes,在3 TEXTINCLUDE 下面添加如下语句,注意斜体部分,一定要有。

3 TEXTINCLUDE
BEGIN
"1 TYPELIB ""test.tlb""\r\n"
"\r\n"
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
"#define _AFX_NO_OLE_RESOURCES\r\n"
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
"#undef _AFX_NO_TRACKER_RESOURCES\r\n"
"\r\n"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
"LANGUAGE 9, 1\r\n"
"#pragma code_page(1252)\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#endi\0"
END 

0 0