MFC窗口

合集下载

MFC创建简单窗口

MFC创建简单窗口

1.创建MFC对话框工程
2.布置界面
3.创建类。

4.设计类的方法和属性。

5.更改控件ID
6.添加按钮处理函数。

7.编写按钮处理函数。

练习:
实现一个日期计算器程序,基于MFC对话框。

要求;
1.设计一个C++类CDater, 该类实现两个功能:
功能一:计算指定日期是一年中的第几天。

如2011 年1 月31日是2011年的第31天。

功能二:计算某年的某天是几月几日。

如2011年的第32天是2011年2月1日。

2.在对话框中设计两个按钮和若干个编辑框,以及若干静态文本框,要求调用CDater类的函数。

按钮一:把用户输入的年月日转化为第多少天。

按钮二:把用户输入的第多少天转化为几月几日。

mfc 代码关闭当前多文档的子窗口

mfc 代码关闭当前多文档的子窗口

MFC(Microsoft Foundation Class)是微软公司开发的用于Windows评台的C++类库,用于简化Windows应用程序的开发。

在MFC中,关闭当前多文档的子窗口可以通过以下步骤实现:1. 获取当前活动的文档视图需要获取到当前处于活动状态的文档视图,可以通过以下代码实现:```cppCWnd* pActiveWnd = AfxGetM本人nWnd(); CMDIChildWnd* pChild = (CMDIChildWnd*)pActiveWnd; CView* pView = pChild->GetActiveView();```2. 关闭子窗口有了当前活动的文档视图之后,可以通过以下代码关闭子窗口:```cpppChild->MDIDestroy();```在这段代码中,`MDIDestroy` 函数用于关闭当前子窗口。

3. 整合关闭子窗口的代码将以上两个步骤整合在一起,完整的代码如下所示:```cppCWnd* pActiveWnd = AfxGetM本人nWnd(); CMDIChildWnd* pChild = (CMDIChildWnd*)pActiveWnd; CView* pView = pChild->GetActiveView();pChild->MDIDestroy();```这样,就可以在MFC中关闭当前多文档的子窗口了。

以上代码基于MFC类库,在多文档程序框架下实现了关闭当前子窗口的功能。

在实际开发中,可以根据具体的需求和程序结构进行适当的修改和扩展。

总结起来,关闭当前多文档的子窗口在MFC中实现并不复杂,通过获取当前活动的文档视图并调用相应的函数即可完成这一操作。

希望本文对MFC开发者能有所帮助。

初步思考:续写部分将围绕MFC中关闭子窗口的方法展开,涉及到MFC开发中更广泛的内容,包括MFC文档视图架构、消息处理机制等。

MFC浮动窗口使用方法和注意事项

MFC浮动窗口使用方法和注意事项

MFC浮动窗⼝使⽤⽅法和注意事项使⽤VS2008+SP1创建悬浮窗⼝的步骤:1. 创建悬浮窗⼝类每⼀个悬浮窗⼝都是⼀个CDockablePane的派⽣类的对象, 因此要为每⼀个悬浮窗⼝创建⼀个新类1.1 添加类通过菜单Project->Add Class...或者在类视图中⼯程名字处右键选择Add->Class...添加类选择MFC Class, 点Add按钮进⼊下⼀步Class name处写⼊新类的名字, 这⾥⽤CDock, 选择Base class为CDockablePane按Finish按钮, 添加类完成.1.2 添加消息处理函数⼀般⾄少要处理两个消息, ⼀个是WM_CREATE, ⼀个是WM_SIZE, 具体步骤为:(1) 头⽂件中添加函数声明(函数名及参数不可写错)protected:afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnSize(UINT nType, int cx, int cy);(2) cpp⽂件中添加消息映射BEGIN_MESSAGE_MAP(CDock, CDockablePane)ON_WM_CREATE()ON_WM_SIZE()END_MESSAGE_MAP()这⾥BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏都是⾃动⽣成的, 只需要添加中间两⾏代码即可(3) 添加函数实现部分int CDock::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CDockablePane::OnCreate(lpCreateStruct) == -1)return -1;// 在这⼉创建控件return 0;}void CDock::OnSize(UINT nType, int cx, int cy){CDockablePane::OnSize(nType, cx, cy);// 这⼉添加代码}1.3 添加控件现在创建的CDock类中由于没有任何控件, 因此如果现在创建该类的对象并显⽰, 该区域中由于全是垃圾数据, 故可能该窗⼝显⽰时为花屏. 如果程序运⾏期间出现类似花屏的问题, ⼤概会有⼏种可能性: 1. 没有创建控件 2. 已创建控件, 但控件位置不对或未覆盖整个的dockablePane 3. 控件虽然占据整个区域, 但不能⾃动刷新这⾥以添加⼀个listBox为例:(1) 在类的头⽂件中添加控件对象, 代码为:protected:CListBox _listBox;(2) 在OnCreate()中添加创建控件窗⼝的代码:这⾥必须要注意, 需要先调⽤基类的函数OnCreate()int CDock1::OnCreate(LPCREATESTRUCT lpCreateStruct){if (CDockablePane::OnCreate(lpCreateStruct) == -1)return -1;// 在这⼉创建控件// nID为该控件的ID, 可以⾃⾏设置, 如果对ID不感兴趣, 也可以选择传递0让系统做处理if (!_listBox.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, nID)){TRACE0("创建listbox失败");return -1;}return 0;}(3) 在OnSize中设置各个控件的位置这⾥要注意的是, 需要将控件布满整个窗⼝. 这⾥只有⼀个listBox, 故可以直接⽤listBox覆盖窗⼝.同理, 必须要先调⽤基类函数CDockablePane::OnSize(nType, cx, cy)void CDock::OnSize(UINT nType, int cx, int cy){CDockablePane::OnSize(nType, cx, cy);// 这⼉添加代码if (GetSafeHwnd() == NULL){return;}if (_listBox.GetSafeHwnd() != NULL){CRect rectClient;GetClientRect(rectClient);_listBox.SetWindowPos(NULL, rectClient.left, rectClient.top, rectClient.Width(), rectClient.Height(), SWP_NOACTIVATE | SWP_NOZORDER);}}2. 在程序中添加悬浮窗⼝对象上⾯⼀步只是给⼯程添加了⼀个悬浮窗⼝类, 但并没⽣成该类的实例. 这⾥创建该实例(在CMainFrame类中)2.1 在主框架类声明中添加对象, 代码为:protected:CDock m_wndDock;2.2 创建dockablePane的窗⼝, 在主框架的OnCreate()函数中(注: 这⾥我建议在OnCreate函数中⾃动⽣成代码EnableAutoHidePanes(CBRS_ALIGN_ANY)的后⾯添加)int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){...EnableAutoHidePanes(CBRS_ALIGN_ANY);// 利⽤这⾥的CBRS_RIGHT来设置最初的窗⼝停靠的位置, 可以的取值是// CBRS_NOALIGN, CBRS_LEFT, CBRS_TOP, CBRS_RIGHT, CBRS_BOTTOMDWORD style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_RIGHT |CBRS_FLOAT_MULTI;if (!wndDock1.Create(// 该dock窗⼝的标题(如果可以有的话...)_T("Dock1"),// 该dock窗⼝的parent, 设置为thisthis,// 窗⼝的⼤⼩, 注意是"悬浮"的情况下的⼤⼩, 处于dock状态时⼤⼩与该值⽆关CRect(0, 0, 200, 200),// 该dock窗⼝是否有标题, 如果为FALSE, 则第⼀个字符串参数显⽰不出来TRUE,// 该dock窗⼝的ID值. 注意: 如果希望dock窗⼝的状态可以保存在注册表中(这样下次启动程序时仍保持该状态), 则该值必须的唯⼀的nID,//style)){return FALSE;}...}2.3去掉CDockablePane的Close按钮?⽅法⼀:在继承CDockablePane的类中重写CanBeClosed()⽅法:virtual BOOL CanBeClosed() const; ... BOOL COutputWnd::CanBeClosed() const { return FALSE;}⽅法⼆:if (!m_wndView.Create(strFileView, this, CRect(0, 0, 250, 200), TRUE, ID_VIEW_VIEW,WS_CHILD | WS_VISIBLE | CBRS_LEFT | CBRS_HIDE_INPLACE | WS_CAPTION, AFX_CBRS_REGULAR_TABS, AFX_CBRS_RESIZE))在Create的时候后⾯加上这样的参数设置AFX_CBRS_REGULAR_TABS, AFX_CBRS_RESIZE 就不会有那个关闭按钮了2.4显⽰隐藏CDockablePanem_wndFileView.ShowPane(TRUE,FALSE,TRUE);//显⽰m_wndFileView.ShowPane(FALSE,FALSE,TRUE);//隐藏2.5 给悬浮窗⼝添加icon, 暂时省略.3. 设置窗⼝悬浮⽅式, 令窗⼝悬浮3.1 设置窗⼝悬浮位置这部分代码也应该在MainFrame类的OnCreate函数中, ⽽且紧跟创建悬浮窗⼝的后⾯.设置悬浮位置只需要调⽤CDockablePane::EnableDocking即可m_wndDock.EnableDocking(CBRS_ALIGN_ANY);其中, 参数可以是CBRS_ALIGN_TOP, CBRS_ALIGN_RIGHT, CBRS_ALIGN_BOTTOM, CBRS_ALIGN_ANY3.2 令窗⼝悬浮欲使⼀个CDockablePane对象悬浮, 只需要调⽤框架类的DockPane函数即可:DockPane(&m_wndDock);但是若有另外⼀个悬浮窗⼝的对象需要和m_wndDock在⼀起显⽰, 构成⼀个组(就像VS的资源视⼒和类视图), 那么第⼆个悬浮窗⼝需要使⽤CDockablePane类的AttchToTabWnd函数, 代码如下:DockPane(&m_wndDock);CDockablePane *pTabbedBar = NULL;m_wndDock2.AttachToTabWnd(&m_wndDock, DM_SHOW, FALSE, &pTabbedBar);CDockablePane 使⽤这个是转载的int m_nshowCurrent;m_nshowCurrent=theApp.GetProfileInt(_T("Workspace//Pane-377"),_T("IsFloating"),0); //在构造函数中⾸先派⽣两个⼦类,源码就不⽤写出来了,占篇幅,在MainFrm⾥申明如:CCurrentDockablePane m_wndCurrentDockablePane;CHistoryDockablePane m_wndHistoryDockablePane;CDockablePane* m_pTabbedBar;然后在OnCreate()⾥⾯:CString strHistoryDockablePane;CString strCurrentView;strCurrentView.LoadString(IDS_Current_VIEW);strHistoryDockablePane.LoadString(IDS_History_VIEW);if (!m_wndHistoryDockablePane.Create(strHistoryDockablePane, this, CRect(0, 0, 200, 200),TRUE, ID_VIEW_HistoryDockablePane, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI)){TRACE0("Failed to create Class View window/n");return FALSE; // failed to create}if (!m_wndCurrentDockablePane.Create(strCurrentView, this, CRect(0, 0, 200, 200),TRUE, ID_VIEW_CurrentView, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT|CBRS_FLOAT_MULTI)){TRACE0("Failed to create File View window/n");return FALSE; // failed to create}再给她们添加图标:HICON hHistoryDockablePaneIcon = (HICON) ::LoadImage(::AfxGetResourceHandle(),MAKEINTRESOURCE(bHiColorIcons ? IDI_history : IDI_history), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON), 0);m_wndHistoryDockablePane.SetIcon(hHistoryDockablePaneIcon, FALSE);HICON hCurrentViewIcon = (HICON) ::LoadImage(::AfxGetResourceHandle(),MAKEINTRESOURCE(bHiColorIcons ? IDI_Currrently : IDI_Currrently), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON),::GetSystemMetrics(SM_CYSMICON), 0);m_wndCurrentDockablePane.SetIcon(hCurrentViewIcon, FALSE);m_wndHistoryDockablePane.EnableDocking(CBRS_ALIGN_ANY);m_wndCurrentDockablePane.EnableDocking(CBRS_ALIGN_ANY);DockPane(&m_wndHistoryDockablePane);DockPane(&m_wndCurrentDockablePane);m_pTabbedBar = NULL;m_wndCurrentDockablePane.AttachToTabWnd(&m_wndHistoryDockablePane, DM_SHOW, FALSE, &m_pTabbedBar);相关显⽰代码就这样的了.后来⽼⼤说关闭需要修改⼯具栏⾥的显⽰状态,即去掉对勾.在⼯具栏⾥控制他们的显⽰和隐藏简单啊,就是⽤m_wndCurrentDockablePane.ShowPane(TRUE,FALSE,TRUE);可是关闭再去修改⼯具栏想了半天,以为要重载CDockablePane的Close()消息,⼜尝试了他的很多消息,都不对.跟踪进去才知道是调⽤MainFrm来关闭的.⾥⾯有pMainfrm.onCloseDockingPane(this);好了,我就重载这个⽅法.BOOL CMainFrame::OnCloseDockingPane( CDockablePane* pWnd ){CWnd * pfWnd = pWnd->GetFocus();if (*pfWnd == m_wndCurrentDockablePane){m_nshowCurrent = 0;}else if(*pfWnd == m_wndHistoryDockablePane){m_nshowHistory = 0;}return TRUE;}这样⼯具栏⾥⾯的信息就更新了.呵呵,⾼兴的太早了,才做了⼀半,当两个⾯板拆开,即处于浮动状态时关闭根本就不调⽤这⾥.⼜郁闷了半天,还是⽼⼤⽜逼,说那种情况是OnCloseMiniFrame,于是有如下重载:BOOL CMainFrame::OnCloseMiniFrame( CPaneFrameWnd* pWnd ){CWnd *ptWnd = pWnd->GetWindow( GW_CHILD );if (*ptWnd ==m_wndCurrentDockablePane){m_nshowCurrent = 0;}else if (*ptWnd == m_wndHistoryDockablePane){m_nshowHistory = 0;}return TRUE;}//写注册表,在析构函数中theApp.WriteProfileInt(_T("Workspace//Pane-377"),_T("IsFloating"),m_nshowCurrent);。

MFC中自定义窗口类名技巧

MFC中自定义窗口类名技巧

转载MFC中封装很多常用的控件,把类名也给封装了,没有提供明显的接口出来,用win api 写窗口程序,第一步就是注册窗口类此时类名和标题名是一起注册的,所以能把标题很好地让用户来设定,类名也应该是很简单的,可惜的是MFC没有这样做,原因也许是window name可以不停的改,而类名不能。

窗口的类名是有Create来确定的,要在Create前,给窗口选择一个已经注册的窗口类名,作为参数窗口Create就ok了,CWnd的Create最终还是到了CreateEx中来,看看CreateEx 就会清楚许多BOOL CWnd::CreateEx(DWord dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam /* = NULL */){ return CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, lpParam);}BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam){ ASSERT(lpszClassName == NULL || AfxIsValidString(lpszClassName)|| AfxIsValidAtom(lpszClassName)); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // allow modification of several common create parameters CREA TESTRUCT cs; cs.dwExStyle = dwExStyle; cs.lpszClass = lpszClassName; cs.lpszName = lpszWindowName; cs.style = dwStyle; cs.x = x; cs.y = y; cs.cx = nWidth; cs.cy = nHeight; cs.hwndParent = hWndParent; cs.hMenu = nIDorHMenu; cs.hInstance = AfxGetInstanceHandle(); cs.lpCreateParams = lpParam; if (!PReCreateWindow(cs)) { PostNcDestroy(); returnFALSE; } AfxHookWindowCreate(this); HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);#ifdef _DEBUG if (hWnd == NULL) { TRACE(traceAppMsg, 0, "Warning: Window creation failed: GetLastError returns 0x%8.8Xn", GetLastError()); }#endif if (!AfxUnhookWindowCreate()) PostNcDestroy(); // cleanup if CreateWindowEx fails too soon if (hWnd == NULL) return FALSE; ASSERT(hWnd == m_hWnd); // should have been set in send msg hook return TRUE;}可以看到最后到了::AfxCtxCreateWindowEx,可以很容易地知道这里调用了CreateWindowEx 来创建一个窗口在前面有一个PreCreateWindow(cs),而cs经过PreCreateWindow处理后,交给::AfxCtxCreateWindowEx处理::AfxCtxCreateWindowEx在中转给CreateWindowEx,cs.lpszClass就是类名,可以清楚了AfxCtxCreateWindowEx的用心良苦我们可以重载的PreCreateWindow,来修改类名,如下的代码:// TODO: 在此添加专用代码和/或调用基类//VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AF X_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); WNDCLASS wndcls; memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL // defaults wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; //you can specify your own window procedure wndcls.lpfnWndProc = ::DefWindowProc; wndcls.hInstance = AfxGetInstanceHandle(); wndcls.hIcon = NULL; // or load a different icon wndcls.hCursor =NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; // Specify your own class name for using FindWindow later wndcls.lpszClassName = _T("MyNewClass"); // Register the new class and exit if it fails if(!AfxRegisterClass(&wndcls)) { TRACE("Class Registration Failedn"); return FALSE; } cs.lpszClass = wndcls.lpszClassName; return TRUE; //return CWnd::PreCreateWindow(cs);其实就是为了把一个已经注册的类名字符串传给CreateWindowEx,从上面代码中的注释中来看,我还用了一种让系统来生成className的方法AfxRegisterWndClass。

mfc 窗口重绘回调函数

mfc 窗口重绘回调函数

在MFC中,窗口的重绘通常是通过重载窗口类的OnPaint函数来实现的。

OnPaint函数是一个回调函数,当窗口需要重绘时,MFC会自动调用该函数。

以下是一个示例,展示了如何在MFC中使用OnPaint函数来处理窗口的重绘:
cpp
class CMyWindow : public CWnd
{
public:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyWindow, CWnd)
ON_WM_PAINT()
END_MESSAGE_MAP()
void CMyWindow::OnPaint()
{
CPaintDC dc(this); // 创建设备上下文
// 在这里进行绘制操作
// 例如,使用dc对象的绘图函数来绘制图形、文本等
// 最后,调用父类的OnPaint函数
CWnd::OnPaint();
}
在上述示例中,CMyWindow是一个自定义的窗口类,继承自CWnd。

通过重载OnPaint 函数,并在函数内部进行绘制操作,可以实现窗口的重绘。

需要注意的是,为了使窗口类能够接收到WM_PAINT消息并调用OnPaint函数,需要在消息映射中添加ON_WM_PAINT()宏。

以上是MFC中处理窗口重绘的一种常见方式,你可以根据自己的需求和具体情况来进行调整和扩展。

MFC学习笔记-窗口创建

MFC学习笔记-窗口创建

MFChierarchy chart(类库列表)MFC与Win321 win32:函数,使用API一步一步搭建应用程序。

(常使用FileView操作)2 MFC编程:实现仍然调用API函数,但是是用类封装API函数,使用向导自动生成应用程序框架。

(常使用ClassView操作)2.1需要掌握的技能2.1.1断点调试2.1.2堆栈调用的查看MFC课程内容1 MFC:MFC的六大机制,文档式架构,常用的MFC类,(10--12)。

2 COM(组件对象模型):COM的原理和应用(6)。

3 ADO/Socket:MFC访问数据库以及一些简单的网络编程。

MFC应用程序编程1 MFC的历史:92(VC1)98(VC6)……………………….2 MFC库基础:2.1 MFC库,微软基础类库。

封装了Windows应用程序编程的各种API以及相关机制的C++类库3 类库的相关头文件件★afx-application framework(应用程序框架x)3.1<stdafx.h>-不是类库头文件,是项目的头文件,称为VC下编译的预编译头文件,用来提高编译速度的。

(*.pch)(头文件是不参加编译的但是他参与生成*.pch)3.2<afxwin.h>-几乎包含了各种常用的MFC有文件3.3 <afxext.h>-提供扩展窗口类的支持(创建工具栏,状态栏等………)MFC应用程序的类型1 支持MFC的控制台应用程序(控制台的第四个选项)1.1 多了一个CWinApp(应用程序类,封装类应用程序启动过沉重所涉及到得相关信息)的全局对象(必须有,而且只能有一个)1.2主函数中多了一个AfxWinInit函数,初始化MFC库中的相关信息2 MFC库程序2.1 MFC支持的静态库2.2 MFC支持的动态库2.2.1 MFC规则库(shared MFC DLL)-可以被各种应用程序调用(非MFC程序,没有MFC类也可以调用)★还是有一个CWinApp派生的CMFC_DLLApp类对象2.2.2 MFC扩展库(using shared MFC DLL)-只能被MFC库所编写的应用程序所调用(对原有的MFC类扩展)★DllMain主函数只能被MFC程序调用3 MFC应用程序-----(注意看父类,子类名字可能不一样)3.1单文档视图应用程序★CWinApp 应用程序类★CAboutDlg(对话框-生成关于窗口-和框架没有任何关系)★CMainFrame(父类是:CFrameWnd)(应用程序主框架窗口类-生成应用程序的主框架-负责各个对象的协调工作)★CDocument(它是父类)(文档类-看不到的很重要-管理数据)★CView(它是父类)(视图类-显示数据并和用户进行交互)★CSingleDocApp(父类是CWinApp)-(使用前面的3个类来创建对象)3.2多文档视图架构★CWinApp 应用程序类★CAboutDlg(对话框-生成关于窗口-和框架没有任何关系)★CView(它是父类)(视图类-显示数据并和用户进行交互)★CDocument(它是父类)(文档类-看不到的很重要-管理数据)★CMDIChildWnd(子框架窗口类,父类)★CMDIFrameWnd(主框架窗口类,父类)我们看到的子窗体其实是★CView和★CMDIChildWnd叠加的3.3基于对话框的应用程序★CWinApp 应用程序类★CDialog(对话框窗口类)★★m_pMainWnd保存主窗口地址DoModal 显示对话框MFC相关类的说明1继承自CObject1.1 CObject类:绝大多数MFC类的父类,提供了MFC库的一些机制1 new/delete操作符,定义了与构造函数相关的内存分配函数2 assert和dump调试,堆调试的支持★3 运行时类信息-属于哪个类,还有类的层次结构★4 动态创建★5 序列化1.2 CWinThread: 线程类。

mfc窗口创建过程

mfc窗口创建过程

mfc窗口创建过程
MFC窗口的创建过程包括以下几个步骤:
1. 定义窗口类:首先需要定义一个派生自CWnd类的窗口类,该类是窗口的实例。

可以在应用程序的头文件中声明该类,并在源文件中实现其成员函数。

2. 注册窗口类:在应用程序的初始化阶段,需要调用AfxRegisterClass函数来注册窗口类,该函数会将窗口类的信息添加到注册表中。

3. 创建窗口:在初始化阶段,还需要创建窗口实例。

可以通过调用Create函数来创建一个新的窗口。

在调用Create函数之前,需要设置一些窗口的属性,如标题、大小、样式等。

4. 响应消息:窗口创建后,会进入一个消息循环。

在消息循环中,窗口会不断接收和处理消息。

可以通过覆盖窗口类的OnXXX函数来响应不同的消息,如OnPaint函数来处理窗口绘制消息。

5. 显示窗口:当窗口创建并响应消息后,需要调用ShowWindow 函数来显示窗口。

可以通过传入SW_SHOW参数来显示窗口。

以上就是MFC窗口的创建过程,通过这些步骤可以创建和管理窗口的实例,并实现窗口的功能。

如何使用visualstudio2019创建简单的MFC窗口(使用C++)

如何使用visualstudio2019创建简单的MFC窗口(使用C++)

如何使⽤visualstudio2019创建简单的MFC窗⼝(使⽤C++)本⽂介绍了如何使⽤visual studio2019创建简单的MFC窗⼝(使⽤C++)```cpp使⽤visual studio 2019 创建过程请参考Bili的上⼀篇⽂章⬇⬇→!使⽤visual studio 2019 创建简单的MFC窗⼝「使⽤底层的C语⾔」#include<windows.h> //底层实现窗⼝的头⽂件//6.处理窗⼝过程//CALLBACK 代表_stdcall 参数的传递顺序:从右到左依次⼊栈,并且函数返回前清空堆栈LRESULT CALLBACK WindowProc(HWND hand, //消息所属窗⼝句柄UINT uMsg, //具体消息名称 WM_XXXX消息名WPARAM wParam, //键盘附加消息LPARAM lParam) { //⿏标附加消息switch (uMsg){case WM_CLOSE://所有以XXXXWindow为结尾的⽅法,都不会进⼊到消息队列中,⽽是直接执⾏DestroyWindow(hand);//发送另⼀个消息WM_DESTROYbreak;case WM_DESTROY:PostQuitMessage(0);break;case WM_LBUTTONDOWN://⿏标左键按下{int xPos = LOWORD(lParam);int yPos = HIWORD(lParam);char buf[1024];wsprintf(buf, TEXT("x = %d,y = %d"),xPos,yPos);MessageBox(hand, buf, TEXT("按下⿏标左键"), MB_OK);break;}case WM_KEYDOWN: //键盘{MessageBox(hand, TEXT("键盘"), TEXT("按下键盘"), MB_OK);break;}case WM_PAINT: //画图{PAINTSTRUCT ps; //画图结构体HDC hdc = BeginPaint(hand, &ps);TextOut(hdc, 100, 100,TEXT("hello"), strlen("hello"));EndPaint(hand, &ps);break;}default:break;}//返回值⽤默认处理⽅式return DefWindowProc(hand, uMsg, wParam, lParam);}/*程序⼊⼝函数_In_ HINSTANCE hInstance,//应⽤程序实例句柄_In_opt_ HINSTANCE hPrevInstance,//上⼀个应⽤程序句柄,在WIN32环境下⼀般为NULL,不起作⽤了_In_ LPSTR lpCmdLine,//char * argv[]_In_ int nShowCmd//显⽰命令最⼤化、最⼩化、正常WINAPI 代表_stdcall 参数的传递顺序:从右到左依次⼊栈,并且函数返回前清空堆栈*/int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) {/*1.设计窗⼝2.注册窗⼝3.创建窗⼝4.显⽰和更新5.通过循环取消息6.处理消息(窗⼝过程)*///1.设计窗⼝WNDCLASS wc;wc.cbClsExtra = 0; //类的额外的内存wc.cbWndExtra = 0; //窗⼝额外的内存wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //设置背景wc.hCursor = LoadCursor(NULL, IDC_HAND); //设置光标,如果第⼀个参数为null,代表使⽤系统提供的光标wc.hIcon = LoadIcon(NULL, IDI_ERROR); //图标,如果第⼀个参数为null,代表使⽤系统提供的图标wc.hInstance = hInstance; //应⽤程序的实例句柄,传⼊winmain的形参即可wc.lpfnWndProc = WindowProc; //回调函数窗⼝过程wc.lpszClassName = TEXT("WIN"); //指定窗⼝名称wc.lpszMenuName = NULL; //菜单名称wc.style = 0; //显⽰风格,0代表默认//2.注册窗⼝RegisterClass(&wc);//3.创建窗⼝/*lpszClassName,//类名lpWindowName, //标题名dwStyle, //风格 WC_OVERLAPPEDWINDOWx, //坐标 CW_USERDEFAULTy, //坐标nWidth, //宽nHeight, //⾼hWndParent, //⽗窗⼝ nullhMenu, //菜单 nullhInstance, //实例句柄lpParam //附加值⿏标附加值*/HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //4.显⽰和更新ShowWindow(hwnd, SW_SHOWNORMAL);UpdateWindow(hwnd);/*HWND hwnd; //主窗⼝句柄UINT message; //具体消息名称WPARAM wParam; //附加消息键盘消息LPARAM lParam; //附加消息⿏标消息DWORD time; //消息产⽣时间POINT pt;*/ //附加消息⿏标消息 x,y//5.通过循环取消息MSG msg;/*_Out_ LPMSG lpMsg, //消息_In_opt_ HWND hWnd, //捕获窗⼝填null表⽰捕获所有窗⼝_In_ UINT wMsgFilterMin, //最⼤和最⼩的过滤消息⼀般填0_In_ UINT wMsgFilterMax);*/while (GetMessage(&msg, NULL, 0, 0)){/*if (GetMessage(&msg, NULL, 0, 0) == FALSE) {break;}*///翻译消息TranslateMessage(&msg);//不是false//分发消息DispatchMessage(&msg);}return 0;}划重点:项⽬->属性->常规->⾼级->将MFC的使⽤设置为在“共享dll中使⽤mfc”头⽂件mfc.h#include <afxwin.h>//mfc头⽂件class MyApp:public CWinApp{public:virtual BOOL InitInstance();};class MyFrame :public CFrameWnd {//窗⼝框架类public:MyFrame();//声明宏提⽰消息映射机制DECLARE_MESSAGE_MAP();afx_msg void OnLButtonDown(UINT,CPoint);afx_msg void OnChar(UINT,UINT,UINT);afx_msg void OnPaint();};源⽂件mfc.cpp#include “mfc.h”MyApp app;BOOL MyApp::InitInstance() {//创建窗⼝MyFrame* frame = new MyFrame;//显⽰和更新frame->ShowWindow(SW_SHOWNORMAL);frame->UpdateWindow();m_pMainWnd = frame;//保存指向应⽤程序的主窗⼝的指针return TRUE;//返回正常初始化}//分界宏BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)ON_WM_LBUTTONDOWN()//⿏标左键按下ON_WM_CHAR()ON_WM_PAINT()END_MESSAGE_MAP()MyFrame::MyFrame(){Create(NULL,TEXT(“windows”));}void MyFrame::OnLButtonDown(UINT, CPoint point){//TCHAR buf[1024];//wsprintf(buf, TEXT(“x = %d,y = %d”), point.x, point.y);//MessageBox(buf);CString str;str.Format(TEXT(“x = %d,y = %d”),point.x,point.y);MessageBox(str);}void MyFrame::OnChar(UINT key, UINT, UINT){CString str;str.Format(TEXT(“按下了%c键”),key);MessageBox(str);}void MyFrame::OnPaint(){CPaintDC dc(this);dc.TextOutW(100,100,TEXT(“为了部落”));dc.Ellipse(10,10,100,100);}到此这篇关于如何使⽤visual studio2019创建简单的MFC窗⼝(使⽤C++)的⽂章就介绍到这了,更多相关vs2019创建MFC窗⼝内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

MFC窗口的创建过程详细解析作者:关于MFC的窗口创建过程一直感觉比较神秘,那么我们来看下MFC中的窗口创建到底是一个什么过程(窗口创建前的窗口类准备就直接忽略了,与标准Win32窗口类准备大同小异)。

MFC中窗口创建主要涉及三个重要的函数,分别是CWnd::CreateEx(或者CWnd::Create)、AfxHookWindowCreate、AfxCbtFilterHook函数,首先是大概介绍下MFC 的窗口创建过程,当CWnd::CreateEx被调用时,CWnd::CreateEx在调用API函数::CreateWindowEx创建窗口前会通过调用AfxHookWindowCreate安装一个名为_AfxCbtFilterHook的线程钩子,并将需要创建的窗口的CWnd指针保存到线程状态结构中,在API函数::CreateWindowEx真正创建窗口前AfxCbtFilterHook会被调用,AfxCbtFilterHook 会执行子类化操作,把要创建的窗口的窗口过程子类化为线程状态结构中的窗口过程(AfxGetModuleState()->m_pfnAfxWndProc),即MFC的标准窗口过程,这样MFC的窗口(CWnd及其派生类)都可以通过消息映射机制接收和响应包括从创建开始的各种各样的消息。

(关于AfxCbtFilterHook可以参考MSDN中关于SetWindowsHookEx的解释。

)1. CWnd::CreateExBOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,int x, int y, int nWidth, int nHeight,HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam){// allow modification of several common create parameters准备一个结构给PreCreateWindow函数使用,这样就允许应用程序在创建窗口前修改窗口创建参数,比如给cs.lpszClass重新指定一个窗口类给CreateWindow函数。

CREATESTRUCT cs;cs.dwExStyle = dwExStyle;cs.lpszClass = lpszClassName;cs.lpszName = lpszWindowName;cs.style = dwStyle;cs.x = x;cs.y = y;cs.cx = nWidth;cs.cy = nHeight;cs.hwndParent = hWndParent;cs.hMenu = nIDorHMenu;cs.hInstance = AfxGetInstanceHandle();cs.lpCreateParams = lpParam;//允许应用程序修改窗口创建的参数。

if (!PreCreateWindow(cs)){PostNcDestroy();return FALSE;}Hook窗口的创建过程:主要是给当前现成安装一个名为_AfxCbtFilterHook的线程钩子,并讲需要创建的窗口的CWnd指针保存到线程状态结构(_AFX_THREAD_STATE)中。

AfxHookWindowCreate(this);开始创建窗口,在该函数正真开始创建窗口之前,AfxCbtFilterHook会被调用,AfxCbtFilterHook会执行子类化操作,把要创建的窗口的窗口过程子类化为线程状态结构中的窗口过程(AfxGetModuleState()->m_pfnAfxWndProc),这样MFC的窗口(CWnd及其派生类)都可以接收和响应包括从创建开始的各种各样的消息HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);#ifdef _DEBUGif (hWnd == NULL){TRACE1("Warning: Window creation failed: GetLastError returns 0x%8.8X\n",GetLastError());}#endif解除创建窗口的Hookif (!AfxUnhookWindowCreate())PostNcDestroy(); // cleanup if CreateWindowEx fails too soonif (hWnd == NULL)return FALSE;ASSERT(hWnd == m_hWnd); // should have been set in send msg hookreturn TRUE;}2.AfxHookWindowCreateAfxHookWindowCreate主要是Hook窗口的创建过程:主要是给当前现成安装一个名为_AfxCbtFilterHook的线程钩子,并讲需要创建的窗口的CWnd指针保存到线程状态结构void AFXAPI AfxHookWindowCreate(CWnd* pWnd)//获取线程状态_AFX_THREAD_STA TE* pThreadState = _afxThreadState.GetData();//如果线程状态里的m_pWndInit成员与pWnd相等表明给窗口正在创建中,直接返回if (pThreadState->m_pWndInit == pWnd)return;if (pThreadState->m_hHookOldCbtFilter == NULL){给本线程安装一个名为AfxCbtFilterHook的钩子,AfxCbtFilterHook会在::CreateWindowEx 真正开始创建窗口前被调用,更多信息请参考MSDN关于SetWindowsHookEx的解释。

pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());if (pThreadState->m_hHookOldCbtFilter == NULL)AfxThrowMemoryException();}ASSERT(pThreadState->m_hHookOldCbtFilter != NULL);ASSERT(pWnd != NULL);ASSERT(pWnd->m_hWnd == NULL); // only do onceASSERT(pThreadState->m_pWndInit == NULL); // hook not already in progress把需要Hook创建的窗口指针保存到线程状态中,AfxCbtFilterHook被调用时会用到。

pThreadState->m_pWndInit = pWnd;}3. AfxCbtFilterHookAfxCbtFilterHook会执行子类化操作,把要创建的窗口的窗口过程子类化为线程状态结构中的窗口过程(AfxGetModuleState()->m_pfnAfxWndProc),即MFC的标准窗口过程,这样MFC 的窗口(CWnd及其派生类)都可以接收和响应包括从创建开始的各种各样的消息LRESULT CALLBACK_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam){_AFX_THREAD_STA TE* pThreadState = _afxThreadState.GetData();if (code != HCBT_CREATEWND){// wait for HCBT_CREATEWND just pass others on...return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code, wParam, lParam);}ASSERT(lParam != NULL);LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs;ASSERT(lpcs != NULL);//获取要创建的窗口CWnd* pWndInit = pThreadState->m_pWndInit;BOOL bContextIsDLL = afxContextIsDLL;if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !bContextIsDLL)){// Note: special check to avoid subclassing the IME windowif (_afxDBCS){// check for cheap CS_IME style first...if (GetClassLong((HWND)wParam, GCL_STYLE) & CS_IME)goto lCallNextHook;//获取窗口类// get class name of the window that is being createdLPCTSTR pszClassName;TCHAR szClassName[_countof("ime")+1];if (HIWORD(lpcs->lpszClass)){pszClassName = lpcs->lpszClass;}else{szClassName[0] = '\0';GlobalGetAtomName((ATOM)lpcs->lpszClass, szClassName, _countof(szClassName));pszClassName = szClassName;}// a little more expensive to test this way, but necessary...if (lstrcmpi(pszClassName, _T("ime")) == 0)goto lCallNextHook;}ASSERT(wParam != NULL); // should be non-NULL HWND//获取即将创建的窗口句柄HWND hWnd = (HWND)wParam;WNDPROC oldWndProc;if (pWndInit != NULL){#ifdef _AFXDLLAFX_MANAGE_STATE(pWndInit->m_pModuleState);#endif//确保窗口句柄未与窗口(CWnd)关联// the window should not be in the permanent map at this time ASSERT(CWnd::FromHandlePermanent(hWnd) == NULL);//使窗口句柄与窗口(CWnd)关联,// connect the HWND to pWndInit...pWndInit->Attach(hWnd);//CWnd子类可以重载这个函数以在子类化进行前做一些处理// allow other subclassing to occur firstpWndInit->PreSubclassWindow();//获取窗口的原始窗口过程,该窗口过程保存在CWnd:: m_pfnSuper里,用CWnd::GetSuperWndProcAddr()函数可以获取,该函数为虚函数,可以重载把原来的窗口过程替换。

相关文档
最新文档