MfC的具体mfc操作excel

MFC怎么使用_百度知道深入浅出话VC++(2)——MFC的本质 - 推酷
深入浅出话VC++(2)——MFC的本质
上一专题中,纯手动地完成了一个Windows应用程序,然而,在实际开发中,我们大多数都是使用已有的类库来开发Windows应用程序。MFC(Microsoft Foundation Class, 微软基础类库)是微软为了简化程序员的开发工作而将Windows API 封装到C++类中,利用这些类,程序员可以有效地完成Windows平台下应用程序的开发。本专题将详细剖析它。
二、利用向导创建一个MFC程序
用于帮助有效地开发Windows应用程序的类库除了MFC外,还有其他开源类库提供,比如说QT,只是QT不是微软开发的罢了,为了更好地剖析MFC,下面让我们用Visual Studio中的MFC模板和向导工具来创建一个基于MFC的单文档(SDI)应用程序。
启动Visual studio 2010,单击文件(FIle)菜单——&新建项目——&项目,在出现的项目窗口中选择Visual C++ 语言,然后选择MFC应用程序,并输入项目的名称为SDIMFC,具体如下图所示。
2. 输入项目名称后点击确定按钮,将出现MFC应用程序向导窗口,点击下一步,应用程序类型选择:单个文档,如下图所示:
3. 点击下一步,出现MFC向导的第三个对话框,复合文档支持保持默认选择,然后在出现的对话框中一直点击下一步来完成一个单文档MFC应用程序的创建。下面,按下Ctrl+F5来运行MFC应用程序,之后将看到我们创建的MFC应用程序界面,具体如下图所示:
在上面的程序中,我们并没有编写任何代码,运行它后就生成了一个带标题栏,系统菜单,具有最大化、最小化框和一个可调边框的应用程序,这一切的工作都是由MFC的向导工具帮我们完成,即该向导工具为我们生成了很多代码,下面就以这个简单的MFC程序来分析下MFC框架。
三、MFC框架详细解析
我们看下用MFC向导工具帮我们生成的哪些代码。你可以在VS中点击类视图选项卡(如果VS界面上没有看到类视图的,可以通过菜单栏视图—&类视图的方式显示出来),就可以看到如下图所示的类。
从上图可以发现,在MFC中,类的命名都是以字母“C”开头的,这种命名方式只是一种约定,让开发人员很快识别出该类是否属于MFC类库中的类。从图片可以看到,前面创建的单文档应用程序中有15个类,但这里我们只分析4个基本类,因为这4个基本类是每个Windows应用程序都会包含的,这4个类是:CMainFrame类、C+工程名(SDIMFC)+App类、C+工程名+Doc类(即CSDIMFCDoc类)和CSDIMFCView类(也是C+工程名+View的结构)。这4个类的基类都是MFC中类,基类的查看可以通过在VS类视图点击
图标。关于MFC中类图层次结构图可以参考MSDN:
,下图(摘自MSDN)很好地诠释了MFC中层次结构图类别。
3.1 MFC应用程序中的WinMain函数
前面对我们创建的MFC应用程序结构进行了一个简单的介绍,下面让我们深入剖析MFC应用程序的实现原理,在前一专题讲到,所有Window下窗口应用程序都要遵循这样一个过程:程序首先进入WinMain函数,然后设计窗口类、注册窗口类、创建窗口、显示和更新窗口、最后进入消息循环,将消息传递给窗口过程函数进行处理。然后在MFC应用程序中,我们使用VS的查找工具在MFC项目中查看WinMain函数却找不到,再查看CreateWindow函数也找不到,那么是不是MFC应用程序不需要WinMain函数,不需要创建窗口吗?这个疑问答案肯定是否定的,因为MFC应用程序一样是Windows应用程序,所以一定遵循上一专题介绍的过程,只是MFC提供的类帮我们对这些类进行了封装,这些函数都存在于MFC的源代码中,下面我们一起去找找程序的入口WinMain函数。
既然WinMain函数存在与MFC源码中,自然我们就要知道MFC源码在哪里了,在安装Visual studio的时候,我们已经安装了MFC的源代码,具体路径为:VS的安装路径\VC\atlmfc\src\mfc,如果你本机把VS安装到D:\Program Files(x86)的话,则MFC源代码路径在:D:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc。 下面利用Windows搜索工具查看WinMain函数的存在那个C++类中,在搜索之前,需要设置下Windows搜索工具,默认情况下,Windows搜索工具搜索内容在没有索引的位置,只搜索文件名的,这里需要设置为搜索文件名和内容,具体设置如下图所示(Win7下选择工具—&文件夹选项即可显示下图):
设置完成之后,在搜索框中输入WinMain,你将看到如下图所示的一个搜索结果:
WinMain函数的实现实际在appmodul.cpp文件里,用VS打开该cpp文件,你将看到WinMain函数的定义:
extern &C& int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
#pragma warning(suppress: 4985)
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
上面代码中是_tWinMain函数啊,并不是我要的WinMain函数的,难道是找错了吗?对于这个疑问,答案也是否定的,我们没有找错,这里_tWinMain是一个宏定义,按F12即可以看到它代表的是WinMain。宏定义源码如下(存在于tchar.h头文件中):
#define _tmain
#define _tWinMain
为了证明我们找到的WinMain正是我们需要找到的入口函数,我们可以在appmodul.cpp文件中_tWinMain函数中设置一个断点,然后按下F5按钮运行SDIMFC程序,我们发现,SDIMFC程序会在我们刚才设置的断点处停下来,具体如下图所示:
我们已经找到了WinMain函数在MFC中的实现了,但是并没有弄明白,我们创建的MFC程序是如何调用appmodul.cpp中的_tWinMain函数的,即程序中的MFC类如何与WinMain函数联系起来的呢?下面就让我们看看CSDIMFCApp类(至于为什么想到该类,因为其后缀为App,即应用程序,所以猜测程序在进入WinMain函数之前会先进入该类),在类视图中双击该类将在VS中看到该类的定义,从类定义可以知道,CSDIMFCApp类继承于CWinAppEx类,CWinAppEx类又继承于CWinApp,为了证明在WinMain函数之前先执行了CSDIMFCApp类中代码,我们在CSDIMFCApp类中的构造函数设置一个断点,然后按F5再运行下该程序,将发现程序首先停在CSDIMFCApp类的构造函数处,然后进入到_tWinMain函数(该断点是我们之前设置的断点)。这里又引起另外一个疑问了——为什么程序会首先调用CSDIMFCApp的构造函数呢?既然构造函数被调用了,肯定定义了该类的一个对象,然后,我们可以发现在CSDIMFCApp类中,定义了一个CSDIMFCApp类型的全局对象theApp,存在于SDIMFC.cpp文件中,具体定义代码如下:
// 唯一的一个 CSDIMFCApp 对象
CSDIMFCApp theA // 初始化对象,这种方式为调用类的无参数构造来初始化,所以会调用类的无参构造函数
然后我们在这个全局对象处设置一个断点,然后再按F5调试运行下该程序,你将发现程序执行的顺序为:theApp全局对象—&CSDIMFCApp构造函数(调用派生类的构造函数之前会调用其父类的构造函数)—&_tWinMain函数。在MFC程序中,theApp对象是用来唯一标识应用程序实例的,每个MFC程序有且仅有一个应用程序对象(这里为theApp对象)。
3.2 设计和注册窗口类
现在我们已经找到MFC中的WinMain函数了,根据前一专题的内容,接下来就是找到MFC应用程序中的窗口类和注册窗口类的代码,在上一专题中,窗口类和注册都是在WinMain函数中定义的,下面让我们看下MFC中WinMain函数都帮我们封装了什么,在MFC中的WinMain函数中只是简单对AfxWinMain函数进行调用,下面让我们看看AfxWinMain具体代码:
// AfxWinMain函数
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine, int nCmdShow)
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitF
// App global initializations (rare)
if (pApp != NULL && !pApp-&InitApplication())
goto InitF
// Perform specific initializations
if (!pThread-&InitInstance())
if (pThread-&m_pMainWnd != NULL)
TRACE(traceAppMsg, 0, &Warning: Destroying non-NULL m_pMainWnd\n&);
pThread-&m_pMainWnd-&DestroyWindow();
nReturnCode = pThread-&ExitInstance();
goto InitF
// PThread-&Run函数是完成消息循环任务的
nReturnCode = pThread-&Run();
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()-&m_nTempMapLock != 0)
TRACE(traceAppMsg, 0, &Warning: Temp map lock count non-zero (%ld).\n&,
AfxGetModuleThreadState()-&m_nTempMapLock);
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
AfxWinTerm();
return nReturnC
上面代码首先调用AfxGetThread函数获得一个指向CWinThread类型的指针,然后再调用了AfxGetApp函数获得一个指向CWinApp类型的指针,再继续调用AfxWinInit函数进行AFX(以AFX为前缀的函数为应用程序框架函数,Application Framework)内部初始化,接着pApp调用InitApplication函数,该函数主要完成MFC内部管理方面的工作,该函数为虚函数,在CWinApp中的实现为(函数实现代码查找按照前面介绍的方式进行查看):
// 主要完成MFC内部管理工作
BOOL CWinApp::InitApplication()
if (CDocManager::pStaticDocManager != NULL)
if (m_pDocManager == NULL)
m_pDocManager = CDocManager::pStaticDocM
CDocManager::pStaticDocManager = NULL;
if (m_pDocManager != NULL)
m_pDocManager-&AddDocTemplate(NULL);
CDocManager::bStaticInit = FALSE;
LoadSysPolicies();
return TRUE;
接着继续调用pThread的InitInstance函数,按F12可知,该函数声明为虚函数,根据类的多态性,这里AfxWinMain函数中调用的InitInstance函数为调用子类CSDIMFCApp的InitInstance函数,该函数的定义代码为:
/ CSDIMFCApp 初始化
BOOL CSDIMFCApp::InitInstance()
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
INITCOMMONCONTROLSEX InitC
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它设置为包括所有要在应用程序中使用的
// 公共控件类。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinAppEx::InitInstance();
// 初始化 OLE 库
if (!AfxOleInit())
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
AfxEnableControlContainer();
EnableTaskbarInteraction(FALSE);
// 使用 RichEdit 控件需要
AfxInitRichEdit2()
// AfxInitRichEdit2();
// 标准初始化
// 如果未使用这些功能并希望减小
// 最终可执行文件的大小,则应移除下列
// 不需要的特定初始化例程
// 更改用于存储设置的注册表项
// TODO: 应适当修改该字符串,
// 例如修改为公司或组织名
SetRegistryKey(_T(&应用程序向导生成的本地应用程序&));
LoadStdProfileSettings(4);
// 加载标准 INI 文件选项(包括 MRU)
InitContextMenuManager();
InitKeyboardManager();
InitTooltipManager();
CMFCToolTipInfo ttP
ttParams.m_bVislManagerTheme = TRUE;
theApp.GetTooltipManager()-&SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,
RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);
// 注册应用程序的文档模板。文档模板
// 将用作文档、框架窗口和视图之间的连接
CSingleDocTemplate* pDocT
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CSDIMFCDoc),
RUNTIME_CLASS(CMainFrame),
// 主 SDI 框架窗口
RUNTIME_CLASS(CSDIMFCView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
// 分析标准 shell 命令、DDE、打开文件操作的命令行
CCommandLineInfo cmdI
ParseCommandLine(cmdInfo);
// 调度在命令行中指定的命令。如果
// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 唯一的一个窗口已初始化,因此显示它并对其进行更新
m_pMainWnd-&ShowWindow(SW_SHOW);
m_pMainWnd-&UpdateWindow();
// 仅当具有后缀时才调用 DragAcceptFiles
在 SDI 应用程序中,这应在 ProcessShellCommand 之后发生
return TRUE;
在上面代码中,
77行代码和78行代码为窗口的显示和更新
,m_pMainWnd为我们创建的窗口,按F12转到其定义为指向CWnd类型的指针,Cwnd类是MFC为我们预定义的标准窗口类,现在我们已经找到MFC程序中的窗口类,接下来就是找到MFC中是如何注册窗口的,在MFC中,窗口类的注册是由AfxEndDeferRegisterClass函数完成的,其定义在Wincore.cpp文件中,AfxEndDeferRegisterClass函数内部又是通过AfxRegisterClass函数(该函数也定义在wincore.cpp文件中)来注册窗口类,由于篇幅的问题,这里就不贴其函数的定义源码,大家可以在本机中进行查看。
3.3 创建窗口
我们已经找到了MFC设计窗口和注册的封装,接下来就是MFC程序中是如何创建一个窗口的,该功能在MFC中是由CWnd类的CreateEx函数进行完成的,该函数的声明在afxwin.h文件中,具体代码如下:
virtual BOOL CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam = NULL);
实现代码位于wincore.cpp文件中,我们程序中创建的是CMainFrame窗口,CMainFrame类继承于CFrameWndEx,该类又继承于CFrameWnd,CFrameWnd类的Create函数内部会调用CreateEx函数,而CFrameWnd的Create函数又由CFrameWnd类的LoadFrame函数调用。CFrameWnd类的Create函数声明位于afxwin.h文件中,其实现代码位于winfrm.cpp文件中,实现代码如下:
BOOL CFrameWnd::Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd,
LPCTSTR lpszMenuName,
DWORD dwExStyle,
CCreateContext* pContext)
HMENU hMenu = NULL;
if (lpszMenuName != NULL)
// load in a menu that will get destroyed when window gets destroyed
HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, ATL_RT_MENU);
if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)
TRACE(traceAppMsg, 0, &Warning: failed to load menu for CFrameWnd.\n&);
PostNcDestroy();
// perhaps delete the C++ object
return FALSE;
m_strTitle = lpszWindowN
// save title for later
if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
pParentWnd-&GetSafeHwnd(), hMenu, (LPVOID)pContext))
TRACE(traceAppMsg, 0, &Warning: failed to create CFrameWnd.\n&);
if (hMenu != NULL)
DestroyMenu(hMenu);
return FALSE;
return TRUE;
3.4 显示窗口和更新窗口
在CSDIMFCApp类的InitInstance函数内容即有窗口显示和更新窗口的代码,具体代码如下:
// 唯一的一个窗口已初始化,因此显示它并对其进行更新
m_pMainWnd-&ShowWindow(SW_SHOW);
m_pMainWnd-&UpdateWindow();
3.5 消息循环
CWinThread类的Run函数就是完成消息循环这一任务的,该函数在AfxWinMain函数中进行了调用,其定义在thrdcore.cpp文件中,其定义代码如下所示:
// main running routine until thread exits
int CWinThread::Run()
ASSERT_VALID(this);
_AFX_THREAD_STATE* pState = AfxGetThreadState();
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// acquire and dispatch messages until a WM_QUIT message is received.
// phase1: check to see if we can do idle work
while (bIdle &&
!::PeekMessage(&(pState-&m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
// call OnIdle while in bIdle state
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume &no idle& state
// phase2: pump messages while available
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset &no idle& state after pumping &normal& message
//if (IsIdleMessage(&m_msgCur))
if (IsIdleMessage(&(pState-&m_msgCur)))
bIdle = TRUE;
lIdleCount = 0;
} while (::PeekMessage(&(pState-&m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
3.6 窗口过程函数
在AfxEndDeferRegisterClass函数中其中有一行这样的代码(下面代码红色标记处):
BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)
// mask off all classes that are already registered
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
fToRegister &= ~pModuleState-&m_fRegisteredC
if (fToRegister == 0)
return TRUE;
LONG fRegisteredClasses = 0;
// common initialization
memset(&wndcls, 0, sizeof(WNDCLASS));
// start with NULL defaults
// 设置窗口过程函数,这里指定时一个默认的窗口过程
wndcls.lpfnWndProc = DefWindowP
wndcls.hInstance = AfxGetInstanceHandle();
wndcls.hCursor = afxData.hcurA
但实际上,MFC中并不是把所有消息都交给DefWindowProc这一默认窗口过程进行处理的,而是采用了一种称为
消息映射机制
来处理各种消息,MFC消息映射机制指的是可以通过类向导为类添加消息处理函数,具体操作为,在类视图中右键某个类,然后选择类向导,在弹出的MFC类向导窗体中切换到消息选项卡来添加某个消息的处理函数,下图是CMainFrame执行类向导的截图:
该过程类似.NET中WinForm中通过某个控件的事件来添加事件处理函数。(WinForm中事件对应于MFC中的消息)。
至此,我们已经分析完了MFC程序的运行机制了,可以发现其经历过程和前一专题介绍是一致,只是MFC中我们不需要自己实现这些过程了,这些都由MFC框架帮我们封装好了,从而减少开发人员的任务量,将更多的时间放在实现程序的业务逻辑上面。下面让我们一起来梳理下MFC程序的运行过程:
首先利用全局应用程序对象theApp启动应用程序。
调用全局应用程序对象的构造函数,从而会调用基类CWinApp的构造函数,后者完成一些应用程序的初始化工作。
进入到WinMain函数,即_tWinMain函数,在该函数中调用了AfxWinMain函数,后者获取子类(程序中指的CSDIMFCApp类)的指针,利用该指针调用InitInstance虚函数,根据多态原理,实际调用的是子类CSDIMFCApp的InitInstance函数,子类CSDIMFCApp的InitInstance函数完成应用程序的一些初始化工作,包括窗口类的注册、创建、窗口显示和更新。
进入消息循环。虽然注册函数中设置了默认的窗口过程函数,但是,MFC应用程序实际上采用消息映射机制来处理各种消息的,当收到WM_QUIT消息时,将退出消息循环,程序结束。
四、文档/视图结构
&我们创建的MFC程序除了主框架窗口外,还有一个窗口是视类窗口,对应于CView类,框架窗口是视类窗口的一个父窗口,它们之间的关系如下图所示。主框架窗口是整个应用程序外框所包括的部分,而视类窗口只是主框架窗口中的空白的地方。
在我们之前创建的MFC程序中还有一个CSDIMFCDoc类,它派生与CDocument类,后者的基类又是CCmdTarget,而CCmdTarget又派生于CObject类,从而,可以知道CSDIMFCDoc类不是一个窗口类,实际上它是一个文档类。
MFC提供了一个文档/视图结构(Document/View),这里文档指的是CDocument类,而视图指的是CView类。微软在设计MFC时,考虑到数据本身应该与它的显示分离(这点在微软的很多技术中都有体现,例如Asp.net MVC ),于是就采用文档和视图结构来实现这一想法。数据的存储和加载由文档类来完成,数据的显示和修改由视图类来完成,从而把数据管理和显示方法分离开来
到此,本专题的内容就介绍结束了,本专题主要剖析了MFC框架的运行机制,从而发现MFC应用程序同样遵循Win32 SDK程序相应的过程,包括设计窗口类、注册窗口类、创建窗口、显示和更新窗口、消息循环和窗口处理过程函数,只不过这些操作都被MFC本身封装好了。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致& VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)
VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)
&&&&&&&上一节鸡啄米讲了的使用,本节主要讲解组合框控件Combo Box。组合框同样相当常见,例如,在Windows系统的控制面板上设置语言或位置时,有很多选项,用来进行选择的控件就是组合框控件。它为我们的日常操作提供了很多方便。&&&&&& 组合框控件简介&&&&&& 组合框其实就是把一个和一个列表框组合到了一起,分为三种:简易(Simple)组合框、下拉式(Dropdown)组合框和下拉列表式(Drop List)组合框。下面讲讲它们的区别。&&&&&&&简易组合框中的列表框是一直显示的,效果如下图:&&&&&&&下拉式组合框默认不显示列表框,只有在点击了编辑框右侧的下拉箭头才会弹出列表框,列表框弹出后如下图:&&&&&&&下拉列表式组合框的编辑框是不能编辑的,只能由用户在下拉列表框中选择了某项后,在编辑框中显示其文本。下拉列表式组合框如下图:&&&&&&&经过上面的介绍,大家应该知道,最常用的当属下拉式组合框和下拉列表式组合框了,它们在很多时候能使程序看起来更专业,更简洁,让用户在进行选择操作时更方便。&&&&&& 组合框被操作时会向父窗口发送通知消息,这些通知消息及其含义如下:&&&&&& CBN_CLOSEUP:组合框的列表框组件被关闭,简易组合框不会发送该通知消息&&&&&& CBN_DBLCLK:用户在某列表项上双击鼠标,只有简易组合框才会发送该通知消息&&&&&& CBN_DROPDOWN:组合框的列表框组件下拉,简易式组合框不会发送该通知消息&&&&&& CBN_EDITUPDATE:在编辑框准备显示改变了的正文时发送该消息,下拉列表式组合框不会发送该消息&&&&&& CBN_EDITCHANGE:编辑框的内容被用户改变了,与CBN_EDITUPDATE不同,该消息是在编辑框显示的正文被刷新后才发出的,下拉列表式组合框不会发送该消息&&&&&&&CBN_ERRSPACE:组合框无法申请足够的内存来容纳列表项&&&&&& CBN_SELENDCANCEL:表明用户的选择应该取消,当用户在列表框中选择了一项,然后又在组合框控件外单击鼠标时就会导致该消息的发送&&&&&& CBN_SELENDOK:用户选择了一项,然后按了回车键或单击了下滚箭头,该消息表明用户确认了自己所作的选择&&&&&& CBN_KILLFOCUS:组合框失去了输入焦点&&&&&& CBN_SELCHANGE:用户通过单击或移动箭头键改变了列表的选择&&&&&& CBN_SETFOCUS:组合框获得了输入焦点&&&&&& 组合框控件的创建&&&&&&将组合框控件的所有操作都封装到了CComboBox类中。&&&&&&&我们在对话框中加入组合框时,可以往对话框模板中拖入Combo Box控件,而后添加CComboBox类型的控件变量使用,但如果我们想在程序中动态创建的话,就要使用CComboBox类的成员函数Create了。Create函数的原型如下:virtual BOOL Create(&& DWORD dwStyle,&& const RECT& rect,&& CWnd* pParentWnd,&& UINT nID );&&&&&& 大家可以看出,CComboBox类的Create成员函数同前面几个控件类的Create成员函数非常类似,dwStyle指定组合框控件的风格,rect为列表框弹出后组合框的位置和尺寸,pParentWnd是指向父窗口的指针,不能为NULL,nID指定组合框控件的ID。最后还是重点讲讲dwStyle参数。组合框控件的风格包括以下几种,并给出了相应说明:&&&&&& CBS_AUTOHSCROLL:使编辑框组件具有水平滚动的风格&&&&&& CBS_DISABLENOSCROLL:使列表框在不需要滚动时显示一个禁止的垂直滚动条&&&&&& CBS_DROPDOWN:指定一个下拉式组合框&&&&&& CBS_DROPDOWNLIST:指定一个下拉列表式组合框&&&&&& CBS_HASSTRINGS:指定一个含有字符串的自绘式组合框&&&&&& CBS_LOWERCASE:将编辑框和列表框中的所有文本都自动转换为小写字符&&&&&& CBS_NOINTEGRALHEIGHT:组合框的尺寸由应用程序而不是Windows 指定,通常,由Windows指定尺寸会使列表项的某些部分隐藏起来&&&&&& CBS_OEMCONVERT:使编辑框组件中的正文可以在ANSI 字符集和OEM字符集之间相互转换。这在编辑框中包含文件名时是很有用的&&&&&& CBS_OWNERDRAWFIXED:指定自绘式组合框,即由父窗口负责绘制列表框的内容,并且列表项有相同的高度&&&&&& CBS_OWNERDRAWVARIABLE:指定自绘式组合框,并且列表项有不同的高度&&&&&& CBS_SIIMPLE:指定一个简易组合框&&&&&& CBS_SORT:自动对列表框组件中的项进行排序&&&&&& CBS_UPPERCASE:将编辑框和列表框中的所有文本都自动转换为大写字符&&&&&&&dwStyle参数可以是以上风格的组合。跟其他控件一样,创建时一般也还要指定WS_CHILD、WS_VISIBLE、WS_TABSTOP和WS_VSCROLL等风格。&&&&&&&在对话框模板中直接添加组合框控件时,其属性页中的属性包含了以上风格,例如属性Uppercase设为True就相当于指定了CBS_UPPERCASE风格。&&&&&& CComboBox类的主要成员函数&&&&& 因为组合框是由编辑框和列表框组合而成的,所以组合框的操作和编辑框与列表框的操作有很多相似之处,同样的,CComboBox类的成员函数也和CEdit类与CListBox类的成员函数有很多相似之处,不但功能相似,甚至函数名和参数也很相似。鸡啄米下面大概讲解下CComboBox类的主要成员函数,更详细的内容可以参见MSDN。&&&&&&&int GetCount( )&&&&&&&获取组合框控件的列表框中列表项的数量。&&&&&&&int GetCurSel( )&&&&&&&获取组合框控件的列表框中选中项的索引,如果没有选中任何项,该函数返回CB_ERR。&&&&&&&int SetCurSel(int nSelect);&&&&&&&在组合框控件的列表框中选择某项。nSelect参数指定了要选择的列表项的索引,如果为-1则列表框中当前选择项被取消选中,编辑框也被清空。&&&&&&&DWORD GetEditSel( )&&&&&&&获取组合框控件的编辑框中当前选择范围的起始和终止字符的位置。该函数返回一个32位数,低16位存放起始位置,高16位存放选择范围后第一个非选择字符的位置。如果该函数用于下拉列表式组合框时,会返回CB_ERR。&&&&&&&BOOL SetEditSel(int nStartChar,int nEndChar);&&&&&& 用于在组合框控件的编辑框中选择字符。nStartChar参数指定起始位置,nEndChar参数指定终止位置。&&&&&& DWORD_PTR GetItemData(int nIndex)&&&&&& 获取组合框中指定项所关联的32位数据。nIndex参数指定组合框控件的列表框某项的索引(从0开始)。&&&&&& int SetItemData(int nIndex,DWORD_PTR dwItemData);&&&&&& 为某个指定的组合框列表项设置一个关联的32位数。nIndex参数指定要进行设置的列表项索引。dwItemData参数指定要关联的新值。&&&&&& void GetLBText(int nIndex,CString& rString)&&&&&& 从组合框控件的列表框中获取某项的字符串。nIndex参数指定要获取字符串的列表项的索引,CString参数用于接收取到的字符串。&&&&&& int GetLBTextLen(int nIndex)&&&&&&&获取组合框控件的列表框中某项的字符串长度。nIndex参数指定要获取字符串长度的列表项的索引。&&&&&&&& int GetTopIndex( )&&&&&& 获取组合框控件的列表框中第一个可见项的索引。&&&&&& int SetTopIndex(int nIndex);&&&&&& 将组合框控件的列表框中某个指定项设置为可见的。nIndex参数指定了该列表项的索引。该函数成功则返回0,有错误发生则返回CB_ERR。&&&&&& BOOL LimitText(int nMaxChars);&&&&&& 用于限制用户在组合框控件的编辑框中能够输入的最大字节长度。nMaxChars参数指定了用户能够输入文字的最大字节长度,如果为0则长度被限制为65535个字节。&&&&&& int AddString(LPCTSTR lpszString);&&&&&& 为组合框控件中的列表框添加新的列表项。lpszString参数是指向要添加的字符串的指针。该函数的返回值如果大于等于0,那么它就是新列表项的索引,而如果有错误发生则会返回CB_ERR,如果没有足够的内存存放新字符串则返回CB_ERRSPACE。&&&&&& int DeleteString(UINT nIndex);&&&&&& 删除组合框中某指定位置的列表项。nIndex参数指定了要删除的列表项的索引。该函数的返回值如果大于等于0,那么它就是组合框中剩余列表项的数量。如果nIndex指定的索引超出了列表项的数量则返回CB_ERR。&&&&&& int FindString(int nStartAfter,LPCTSTR lpszString)&&&&&&&在组合框控件的列表框中查找但不选中第一个包含指定前缀的列表项。nStartAfter参数指定了第一个要查找的列表项之前的那个列表项的索引。lpszString指向包含要查找的前缀的字符串。该函数的返回值如果大于等于0,那么它是匹配列表项的索引,如果查找失败则返回CB_ERR。&&&&&& int InsertString(int nIndex,LPCTSTR lpszString);&&&&&& 向组合框控件的列表框中插入一个列表项。nIndex参数指定了要插入列表项的位置,lpszString参数则指定了要插入的字符串。该函数返回字符串被插入的位置,如果有错误发生则会返回CB_ERR,如果没有足够的内存存放新字符串则返回CB_ERRSPACE。&&&&&& int SelectString(int nStartAfter,LPCTSTR lpszString);&&&&&& 在组合框控件的列表框中查找一个字符串,如果查找到则选中它,并将其显示到编辑框中。参数同FindString。如果字符串被查找到则返回此列表项的索引,如果查找失败则返回CB_ERR,并且当前选择项不改变。&&&&&& 此外,CComboBox类还继承了CWnd类的成员函数GetWindowText、SetWindowText等。&&&&&& CComboBox类应用实例&&&&&&&&&&& 最后鸡啄米给大家写一个简单的实例,说明CComboBox的几个成员函数及通知消息等的使用方法。此实例实现的功能:在组合框中包含一个网站列表,切换组合框控件的列表框中选择的列表项时,将新选中的列表项的文本显示到编辑框中。下面是具体实现步骤:&&&&&& 1. 创建一个基于对话框的MFC工程,名称设置为&Example25&。&&&&&& 2. 在自动生成的对话框模板IDD_EXAMPLE25_DIALOG中,删除&TODO: Place dialog controls here.&静态文本控件、&OK&按钮和&Cancel&按钮。添加一个Combo Box控件,ID设置为IDC_WEB_COMBO,Type属性设为Drop List,为下拉列表式组合框,编辑框不允许用户输入,Sort属性设为False,以取消排序显示。再添加一个静态文本控件和一个编辑框,静态文本控件的Caption属性设为&您选择的网站:&,编辑框的ID设为IDC_SEL_WEB_EDIT,Read Only属性设为True。此时的对话框模板如下图:&&&&&& 3. 为组合框IDC_WEB_COMBOm_comboWeb。&&&&&& 4. 在对话框初始化时,我们将站点名加入到组合框中,并默认选择第一项,那么需要修改CExample25Dlg::OnInitDialog()函数为:
BOOL&CExample25Dlg::OnInitDialog() &&
&&&&CDialogEx::OnInitDialog(); &&
&&&&ASSERT((IDM_ABOUTBOX&&&0xFFF0)&==&IDM_ABOUTBOX); &&
&&&&ASSERT(IDM_ABOUTBOX&&&0xF000); &&
&&&&CMenu*&pSysMenu&=&GetSystemMenu(FALSE); &&
&&&&if&(pSysMenu&!=&NULL) &&
&&&&&&&&BOOL&bNameV &&
&&&&&&&&CString&strAboutM &&
&&&&&&&&bNameValid&=&strAboutMenu.LoadString(IDS_ABOUTBOX); &&
&&&&&&&&ASSERT(bNameValid); &&
&&&&&&&&if&(!strAboutMenu.IsEmpty()) &&
&&&&&&&&{ &&
&&&&&&&&&&&&pSysMenu-&AppendMenu(MF_SEPARATOR); &&
&&&&&&&&&&&&pSysMenu-&AppendMenu(MF_STRING,&IDM_ABOUTBOX,&strAboutMenu); &&
&&&&&&&&} &&
&&&&SetIcon(m_hIcon,&TRUE);&&&&&&&&&&&
&&&&SetIcon(m_hIcon,&FALSE);&&&&&&&&&&
&&&&m_comboWeb.AddString(_T(&鸡啄米&)); &&
&&&&m_comboWeb.AddString(_T(&百度&)); &&
&&&&m_comboWeb.InsertString(1,&_T(&新浪&)); &&
&&&&m_comboWeb.SetCurSel(0); &&
&&&&SetDlgItemText(IDC_SEL_WEB_EDIT,&_T(&鸡啄米&)); &&
&&&&return&TRUE;&&&&
}&&&&&&&& 5. 我们希望在组合框中选中的列表项改变时,将最新的选择项实时显示到编辑框中,那么这就要用到CBN_SELCHANGE通知消息。为列表框IDC_WEB_COMBO的通知消息CBN_SELCHANGE添加CExample25Dlg::OnCbnSelchangeWebCombo(),并修改如下:
void&CExample25Dlg::OnCbnSelchangeWebCombo() &&
&&&&CString&strW &&
&&&&int&nS &&
&&&&nSel&=&m_comboWeb.GetCurSel(); &&
&&&&m_comboWeb.GetLBText(nSel,&strWeb); &&
&&&&SetDlgItemText(IDC_SEL_WEB_EDIT,&strWeb); &&
}&&&&&&&& 6. 运行程序,弹出结果对话框,在对话框的组合框中改变选择项时,编辑框中的显示会相应改变。效果图如下:&&&&&&&组合框的内容就是这些了。相对于CComboBox类数量不少的成员函数来说,本节的实例只是用到了很少的几个,大家可以根据上面所讲试试其他的成员函数。有问题欢迎继续到鸡啄米来交流讨论。
除非特别注明,文章均为原创
转载请标明本文地址:
作者:鸡啄米
&&( 23:21:17)&&( 21:47:59)&&( 0:24:18)&&( 0:15:31)&&( 22:29:38)&&( 21:26:10)&&( 22:25:46)&&( 20:30:21)&&( 21:30:18)&&( 22:3:6)
学到东西了,。谢谢博主分享。
好专业的文章
原来博主也是搞技术的!鸡啄米 于
11:30:28 回复是啊,同行啊
不错,真的是技术出身的……
手上有现成的可以多客户端的聊天源码吗?呵呵,有点急用呢鸡啄米 于
11:29:51 回复不好意思,我这里也没有
不知不觉都25接了
有点 看不 太懂
浅显易懂,非常适合初学者鸡啄米 于
22:38:00 回复希望能帮到更多的学习编程者
ON_CBN_SELCHANGE:When processing this message, the text in the edit control of the combo box can only be retrieved via GetLBText or another similar function. GetWindowText cannot be used. 鸡啄米 于
20:35:48 回复msdn上是这样说的,但是用GetWindowText我还没遇到过问题。不过以防万一,还是根据msdn的说法进行了修改。很感谢这位朋友的提醒,通过大家的建议和提醒我也学到了不少。再次感谢!秦风 于
11:41:33 回复GetWindowText:我也使用过这个函数,报错。没有的成员函数,汗啊!
你好,添加组合框成员为什么不直接用属性中的Data添加?这样更直观些,而且这样也自动添加了Index鸡啄米 于
22:40:33 回复我这里是为了演示成员函数的使用方法。如果数据是静态的,是固定的几个数据,可以在data属性里添加
怎样在data属性中添加多个数据?鸡啄米 于
22:07:15 回复多个数据之间用;分隔开
师傅,怎么将combo box 里的字符串显示到标签页的对话框的edit box里啊,您的例程里的combo box和edit box同在一个对话框内,用您的代码可以,可是这不在同一个对话框内,咋办啊?搞了两天,都没明白,求指导啊?鸡啄米 于
23:16:58 回复可以在对话框类中提供接口函数设置过去,也可以通过全局变量,当然前者耦合性低些,具体情况具体分析cl 于
09:43:31 回复谢谢师傅,我调试了一下,CString strW
// 获取组合框控件的列表框中选中项的索引
nSel = m_comboWeb.GetCurSel();
// 根据选中项索引获取该项字符串
m_comboWeb.GetLBText(nSel, strWeb);
// 将组合框中选中的字符串显示到IDC_SEL_WEB_EDIT编辑框中
发现以上的代码都没问题,字符串可以传到strWeb中,就是SetDlgItemText(IDC_SEL_WEB_EDIT, strWeb); 这句话有问题。我与师傅不同的是,combo框在父窗口中,tab标签设在在父窗口中,edit框在tab页的子对话框中。我这个OnCbnSelchangeWebCombo()函数是在父窗口中写的,可就是不能把strWeb传给edit显示,我也试过在tab的那个子对话框中生成OnCbnSelchangeWebCombo(),可它显示m_comboWeb是未定义的标示符,我也包含了父对话框的头文件的啊。我也试过给edit定义字符串变量的方法,网上找的传递函数的法,都也没试出来。哎,晕啊,徒弟真是学艺不精,丢师傅的人啊
师傅,全局变量extern 和接口函数我也试了,可能是我资质太差吧,反正是各种错误,各种郁闷啊wegen 于
16:41:53 回复 我先说一下问题的所在:假如创建了一个子对话框kidDLG,添加了一个ID为IDC_EDIT1的编辑框,然后你在原对话框的消息处理函数OnCbnSelchangeWebCombo()里写了SetDlgItemText(IDC_EDIT, strWeb);;发现strWeb的字符串内容没有传进子对话框的编辑框,我觉得这是因为在一个对话框里不能直接引用其他对话框的ID,对话框是一个模型,可以有很多对象,直接引用的话是找不到具体要引用哪一个。
所以我的做法是在原本对话框的头文件添加子对话框类的对象例如kid_wegen,然后将SetDlgItemText(IDC_EDIT, strWeb)改成kid_wegen.SetDlgItemText(IDC_EDIT, strWeb)就可以了。
请问博主,怎么为组合框IDC_WEB_COMBO添加CComboBox类型的控件变量m_comboWeb。nianhuadefo 于
11:28:02 回复肯定是没看前面的文章
请问在combo box属性Data添加的数据怎么去引用它呢求解 于
21:56:48 回复我也遇到同样的问题,比如二选一“男;女;”运行后在下拉框里没看见可以选择的。豆丁lft 于
16:15:33 回复那个分号必须是英文输入法下输入
否则data的数据按回车之后什么都没有了
博主!您好!ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX & 0xF000);
这两句的作用是什么?IDM_ABOUTBOX、IDS_ABOUTBOX又分别指的是什么,是包含在哪个头文件中的宏定义?
师傅你好,我的问题来了:1: m_Combo1.AddString(_T(&美国&));
m_Combo1.AddString(_T(&中国&));
m_Combo1.InsertString(1, _T(&德国&));运行只显示第一个,下拉框没有另外二个是怎么回事啊?2:比如只有少量的时候可以直接在“数据”属性栏里输入“男;女;”,但是运行的时候为什么没有出来效果呢?(就是没有出现男和女可供选择)。菜鸟,多多指点!
编译报错:SetCurSel is not a menber of ATL::CStringT&BaseType,StringTraits&
最近有个功能把我困惑住了:1. 有一个button,点击后,需要动态生成一个CComboBox。应该如何为动态生成的CComboBox添加事件呢?
CComboBox heCComboBoxEX很容易搞混,之前设置变量的时候没注意就弄错了CComboBoxEX 类虽然也有AddString函数 但是并不支持 ,程序一运行就会报错还有就是组合框空间不能设定太小 ,否则出不了下拉列表
完全随机文章

我要回帖

更多关于 mfcclub操作视频 的文章

 

随机推荐