MFC 基础

windows桌面应用分为两种类型: 基于文档视图类型 和 基于对话框类型。 通常具有复杂交互控件的程序即为基于对话框类型,相对而言比较复杂,而基于文档视图类的应用交互形式比较单一,相对简单。下面给出基于mfc框架的最基本的桌面程序示例:

cpp 复制代码
// 1. 创建控制台空项目
// 2. 项目属性--> 高级-->MFC的应用:[使用标准 Windows 库]  改成  [在共享 DLL 中使用 MFC]
// 3. 项目属性-->链接器-->系统-->子系统:[控制台 (/SUBSYSTEM:CONSOLE)] 改成 [窗口 (/SUBSYSTEM:WINDOWS)]


#include <afxwin.h>
class BaseWinApp:public CWinApp
{
public:
	BaseWinApp();
	virtual BOOL InitInstance() override;
};

class BaseMainFrame:public CFrameWnd
{
public:
	BaseMainFrame();
};

BaseMainFrame::BaseMainFrame()
{}


BaseWinApp::BaseWinApp()
{}

BOOL BaseWinApp::InitInstance()
{
    BaseMainFrame* pFrame = new BaseMainFrame();
    pFrame->Create(NULL, "BaseFrame");
    m_pMainWnd = pFrame;
    pFrame->ShowWindow(SW_SHOW);
    pFrame->UpdateWindow();
    return TRUE;
}

BaseWinApp theApp;//全局唯一

// 主线程启动顺序(最终进入一个事件循环):
// WinMain: appmodul.cpp
//                 AfxWinMain: winmain.cpp
//                              (CWinApp*)(&theApp)->InitApplication  应用资源初始化,是虚函数,可以在子类中重写,做一些特殊资源的初始化
//                              (CWinThread*)(&theApp)->InitInstance  用户重写的InitInstance
//                              (CWinThread*)(&theApp)->Run: appcore.cpp
//                                                  (CWinThread*)(&theApp)->CWinThread::Run(): thrdcore.cpp  进入事件循环,处理消息


// 当消息产生后会在消息循环中侦测到,并在DispatchMessage内部调用对应窗口的处理回调(如AfxWndProc: wincore.cpp)进行消息处理

// MFC 中创建线程的两种方法:
//		1. CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, ...); 调用该接口,传入线程函数,生成一个CWinThread线程管理对象
//		2. CWinThread* AFXAPI AfxBeginThread(CRuntimeClass* pThreadClass,...); 继承CWinThread实现新的Thread类,并声明Runtime信息, 传入新类的RuntimeClass,生成一个线程管理对象。(即CWinApp的做法)
    
//	通过这两种方法创建的新线程,与当前线程公用同一个消息队列,以便在两个线程之间完成通信

基于对话框的应用,可以先看win32 框架下的示例,对程序的运行框架有一个大致的理解:

cpp 复制代码
#include <windows.h>
#include <iostream>
#include "resource.h"//要给项目添加资源文件
    //本例需要在资源文件中添加一个Dialog控件(ID为IDD_DIALOG1)和一个Menu控件(ID为IDR_MENU1,MENU中要增加菜单栏和菜单项)

HINSTANCE g_hInstance = NULL;
HWND hddd = NULL;

INT_PTR CALLBACK DlgProc(HWND hwndlg,UINT msgID,WPARAM wParam, LPARAM lParam)
{
    switch (msgID)
    {
    case WM_SYSCOMMAND:
        if (wParam == SC_CLOSE)
        {
            HWND pHwnd = GetParent(hwndlg);
            DestroyWindow(hwndlg);
            EnableWindow(pHwnd, TRUE);
        }
        else//不知道如何处理的消息,则让框架处理
            return FALSE;
        break;
    case WM_DESTROY:
        MessageBox(NULL,L"Dialog Destroyed",L"Notify",MB_OK);
        break;
    case WM_COMMAND:
        if(wParam == IDOK)
            MessageBox(NULL, L"User Confirmed",L"Dialog Result",  MB_OK);
        else if(wParam == IDCANCEL)
            MessageBox(NULL, L"User Denied",  L"Dialog Result",MB_OK);
        break;
    default:
        return FALSE;
        break;
    }
    return TRUE;
}

void OnNoModel(HWND hWnd)
{
    HWND pHwnd = GetParent(hWnd);
    EnableWindow(pHwnd,FALSE);
    //HWND hDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_DIALOG1),hWnd,DlgProc);// 等效步骤①②③④⑤⑥
                        //创建对话窗对象,并和对话框控件(资源中创建,ID为IDD_DIALOG1)绑定
    HRSRC hRs = FindResource(g_hInstance,MAKEINTRESOURCE(IDD_DIALOG1),RT_DIALOG);//①
    HGLOBAL hGl = LoadResource(g_hInstance,hRs);//②
    LPDLGTEMPLATE pTemplate = (LPDLGTEMPLATE)LockResource(hGl);//③
    HWND hDlg = CreateDialogIndirect(g_hInstance,pTemplate,hWnd, DlgProc);//④
    UnlockResource(hGl);//⑤
    FreeResource(hGl);//⑥
    hddd = hDlg;
    ShowWindow(hDlg, SW_SHOW);//立即返回不阻塞
}

void OnCommand(HWND hWnd,WPARAM wParam )
{
    WORD ID = LOWORD(wParam);//控件ID
    WORD Code = HIWORD(wParam);//通知类型
    switch (ID)
    {
    case ID_FFF:// 资源文件中定义菜单栏下拉的菜单选项对应的资源ID,点击该菜单项将创建一个对话框出来
        OnNoModel(hWnd);
        break;
    default:
        break;
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRet = 0;
    switch (msgID)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_COMMAND:
        OnCommand(hWnd,wParam);
        break;
    default:
        lRet = DefWindowProc(hWnd, msgID, wParam, lParam);
        break;
    }
    return lRet;
}

int CALLBACK WinMain(HINSTANCE hIns,HINSTANCE hPreIns,LPSTR lpCmdLine,int nCmdShow)
{
    g_hInstance = hIns;
    WNDCLASS wc = {};
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.hCursor = NULL;
    wc.hIcon = NULL;
    wc.hInstance = hIns;
    wc.lpfnWndProc = WndProc;
    wc.lpszClassName =L"Main";
    //wc.lpszMenuName = NULL;// IDR_MENU1 在资源文件中添加一个菜单资源,资源ID为IDR_MENU1
    wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&wc);
    HWND hWnd = CreateWindowEx(0,L"Main",L"window",WS_OVERLAPPEDWINDOW,100,100,500,500,NULL,NULL,hIns,NULL);
    ShowWindow(hWnd,SW_SHOW);
    UpdateWindow(hWnd);
    MSG nMsg = {};
   // AllocConsole();//打日志用
   // FILE* f = NULL;
   // freopen_s(&f,"CONOUT$", "w", stdout);
    while (GetMessage(&nMsg, NULL, 0, 0))
    {
        TranslateMessage(&nMsg);
        DispatchMessage(&nMsg);//将消息交给窗口处理函数处理
    }
    //fclose(f);
    return 0;
}

对话框程序示例

cpp 复制代码
#include <afxwin.h>
#include <afxcmn.h>
#include "resource.h"

//本例需要在资源文件中添加一个Dialog控件(ID为IDD_DIALOG1) 

class MainDialog : public CDialog
{
	DECLARE_MESSAGE_MAP()
	enum { IDD = IDD_DIALOG1 };
public:
	MainDialog():CDialog(IDD){}
	void OnIdle(){}//可在此处理低优先级任务
protected:
	BOOL OnInitDialog() override
    {
        return CDialog::OnInitDialog();
    }
	void OnClosed(void)
    {
        ::DestroyWindow(this->m_hWnd);
    }
	void AFX_MSG_CALL OnSysCommand(UINT msgID, LPARAM lParam)
    {
	    DWORD cmdType = msgID & 0xFFF0;
	    switch (cmdType)
	    {
	    case SC_CLOSE://处理标题栏的关闭事件
	    	OnClosed();
		    break;
	    default:
		    CDialog::OnSysCommand(msgID, lParam);
		    break;
	    }
    }
	void DoDataExchange(CDataExchange* pDX) override
    {}
};
BEGIN_MESSAGE_MAP(MainDialog, CDialog)
	ON_WM_SYSCOMMAND()
END_MESSAGE_MAP()

class BaseWinApp :public CWinApp
{
public:
	BaseWinApp();
	virtual BOOL InitInstance() override;
	virtual BOOL OnIdle(LONG lCount) override;
};

BaseWinApp::BaseWinApp()
{
	InitApplication();
}

BOOL BaseWinApp::InitInstance()
{
	MainDialog* pFrame = new MainDialog();
	pFrame->Create(IDD_DIALOG1,NULL);
	m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	//LONG wProc = GetWindowLongPtr(pFrame->m_hWnd, GWLP_WNDPROC);//that should be AfxWndProc
	//WNDPROC fun = AfxWndProc;
	//BOOL bRet = fun == (WNDPROC)wProc;
	//delete pFrame;
	return TRUE;
}

BOOL BaseWinApp::OnIdle(LONG lCount)
{
	if (m_pMainWnd != NULL)
		((MainDialog*)m_pMainWnd)->OnIdle();
	return CWinThread::OnIdle(lCount);
}

BaseWinApp theApp;

单文档程序示例

cpp 复制代码
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"

//本例需要在资源文件中添加一个Menu控件(ID为IDR_MENU1) 和一个String Table(添加字符串资源:ID=AFX_IDS_UNTITLED, Value=61443,Caption=自定义)

class CMyDoc :public CDocument
{
	DECLARE_DYNCREATE(CMyDoc)
};
IMPLEMENT_DYNCREATE(CMyDoc,CDocument)

class CMyView :public CView
{
	DECLARE_DYNCREATE(CMyView)
public:
	virtual void OnDraw(CDC* pDC);
};
void CMyView::OnDraw(CDC* pDC)
{
	pDC->TextOut(100,100,"this is a view wnd");
}
IMPLEMENT_DYNCREATE(CMyView, CView)

class CMyFrameWnd : public CFrameWnd
{
	DECLARE_DYNCREATE(CMyFrameWnd)
};
IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)

class CMyWinApp : public CWinApp
{
public:
	virtual BOOL InitInstance();
};

BOOL CMyWinApp::InitInstance()
{
    /************  方式一 Begin************************************/
	//CSingleDocTemplate* pTemplate = new CSingleDocTemplate(IDR_MENU1,
    //    RUNTIME_CLASS(CMyDoc),
	//	RUNTIME_CLASS(CMyFrameWnd), 
    //    RUNTIME_CLASS(CMyView));
	//AddDocTemplate(pTemplate);
	//OnFileNew();
    /************  方式一 End************************************/	
	
	/**********************方式二 Begin: **************************/ 
	CMyFrameWnd* pFrame = new CMyFrameWnd;
	CMyDoc* pDoc = new CMyDoc;
	CCreateContext cct;
	cct.m_pCurrentDoc = pDoc;
	cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
	pFrame->LoadFrame(IDR_MENU1,WS_OVERLAPPEDWINDOW,NULL,&cct);
	m_pMainWnd = pFrame;
	/**********************方式二 End **************************/

	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	return TRUE;
}

CMyWinApp theApp;

多文档程序示例

cpp 复制代码
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
//本例需要在资源文件中添加两个Menu控件(ID为IDR_MENU1和IDR_MENU2) 和一个String Table(添加字符串资源:ID=AFX_IDS_UNTITLED, Value=61443,Caption=自定义)


class CMyDoc :public CDocument
{
	DECLARE_DYNCREATE(CMyDoc)
};
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)

class CMyView :public CView
{
	DECLARE_DYNCREATE(CMyView)
public:
	virtual void OnDraw(CDC* pDC);
};
void CMyView::OnDraw(CDC* pDC)
{
	pDC->TextOut(100, 100, "I am a view wnd");
}
IMPLEMENT_DYNCREATE(CMyView, CView)

class CMyChild :public CMDIChildWnd
{
	DECLARE_DYNCREATE(CMyChild)
};
IMPLEMENT_DYNCREATE(CMyChild, CMDIChildWnd)

class CMyFrameWnd : public CMDIFrameWnd
{
public:
	CMyFrameWnd() :CMDIFrameWnd() {}
	BOOL PreCreateWindow(CREATESTRUCT& cs) override
	{
		m_strTitle = "MasterWnd";//修改主窗口标题
		return CMDIFrameWnd::PreCreateWindow(cs);
	}
public:
	DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CMDIFrameWnd)
END_MESSAGE_MAP()


class CMyWinApp : public CWinApp
{
public:
	virtual BOOL InitInstance();
};

BOOL CMyWinApp::InitInstance()
{
	CMyFrameWnd* pFrame = new CMyFrameWnd();
	pFrame->LoadFrame(IDR_MENU1);//MENU1为主框架窗口的菜单(MENU1至少需要两个菜单栏)
	m_pMainWnd = pFrame;

	CMultiDocTemplate* pTemplate = new CMultiDocTemplate(IDR_MENU2,//MENU2为子框架窗口的菜单
		RUNTIME_CLASS(CMyDoc),
		RUNTIME_CLASS(CMyChild),
		RUNTIME_CLASS(CMyView));
	AddDocTemplate(pTemplate);
	OnFileNew();//创建三个子窗口
	OnFileNew();
	OnFileNew();

	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

	return TRUE;
}

CMyWinApp theApp;
相关推荐
阿饼2402 小时前
算法——图论——交通枢纽
c++·算法·动态规划·图论
its_a_win2 小时前
洛谷 P1182 数列分段 Section II 二分详细讲解
c++·算法
爱编程的小赵3 小时前
第十五届蓝桥杯C/C++B组拔河问题详解
c语言·c++·蓝桥杯
ksbglllllll4 小时前
ccf3401矩阵重塑(其一)
c++·算法·矩阵
阿饼2405 小时前
算法——图论——最短路径(多边权)
c++·算法·动态规划·图论
Source.Liu6 小时前
【CXX】6.9 CxxVector<T> — std::vector<T>
c++·rust·cxx
威桑6 小时前
Qt 中 isHidden 和 isVisible 的区别与使用
开发语言·c++·qt
愚润求学7 小时前
C++刷题(二):栈 + 队列
开发语言·c++·算法·leetcode
..过云雨8 小时前
09.【C++】list链表(STL中的列表容器,C++封装的带头双向链表,可实现指定类型的增删查改,迭代器操作等功能)
开发语言·c++
阿巴~阿巴~8 小时前
C/C++蓝桥杯算法真题打卡(Day6)
c语言·c++·蓝桥杯·动态规划