MFC 视图窗口

发布时间:2023年12月24日

目录

视图窗口概述

视图窗口的使用

视图窗口创建流程

命令消息 WM_COMMAND 处理顺序

对象关系


视图窗口概述

作用:提供了一个用于显示数据的窗口

关于视图窗口

  • 视图类是用来展示用户,文档类是用来存储和管理数据
  • 视图窗口是覆盖掉框架窗口的客户区
  • 视图窗口是框架窗口的子窗口,它的创建应该是在框架窗口的WM_CREATE消息处理中
  • 每个窗口都有自己消息映射机制,处理属于自己的消息
  • 所有消息中,只有命令消息?WM_COMMAND 是可以被多个类处理的,系统消息,自定义消息只能由对应的窗口处理

框架窗口的消息映射机制:CMyFrameWnd---CFrameWnd---CWnd

视图窗口的消息映射机制:CMyView---CView---CWnd

视图窗口的使用

如何使用?

  • 定义一个自己的视图类(CMyView) ,派生自Cview,并重写父类成员纯虚函数OnDraw(可以用于绘图)
  • 其余框架类和应用程序类代码不变。
  • 在处理框架窗口的WM_CREATE消息时,定义CMyView类对象,并调用Create函数创建视图窗口。

在框架窗口的 WM_CREATE 消息处理函数中创建

int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
	CMyView* pView = new CMyView;
	pView->Create(NULL, "MFCView", WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(0, 0, 200, 200), this,
		AFX_IDW_PANE_FIRST);
	this->m_pViewActive = pView;
	return CFrameWnd::OnCreate(pcs);
}

WS_CHILD, WS_VISIBLEWS_BORDER 是窗口风格(Window Style)的标志,用于指定窗口的样式和行为。

  • WS_CHILD?表示该窗口是一个子窗口,它位于父窗口内部,并随父窗口的移动和调整大小而相应变化。
  • WS_VISIBLE?表示该窗口是可见的,即在创建后立即显示在屏幕上。
  • WS_BORDER?表示该窗口有一个边框,用于提供视觉上的分隔和装饰

?AFX_IDW_PANE_FIRST:添加之后,视图窗口就会完全覆盖掉框架窗口的客户区。如果客户由多个视图窗口的话,其他视图窗口的创建函数AFX_IDW_PANE_FIRST+1……即可。

但是多个视图窗口中只能由一个是激活窗口。

想要创建成功需要重写纯虚函数,这个纯虚函数是在父类 CVIEW 中的,父类有纯虚函数,所以是抽象类,子类继承父类也是抽象类。所以需要重写纯虚函数才能成功创建

void CMyView::OnDraw(CDC* pDC) {
	pDC->TextOut(100, 100, "CMyView::OnDraw");
}

在未处理WM_PAINT消息时,这个函数是由父类来调用的处理的

这个是调用父类的消息处理函数?

void CView::OnPaint()
{
	// standard paint routine
	CPaintDC dc(this);
	OnPrepareDC(&dc);
	OnDraw(&dc);
}

这个函数的功能和处理函数WM_PAINT功能是一样的

void CMyView::OnPaint() {
	PAINTSTRUCT ps = { 0 };
	HDC hdc = ::BeginPaint(this->m_hWnd, &ps);
	::TextOut(hdc, 200, 200, "CMyView::OnPaint", strlen("CMyView::OnPaint"));
	::EndPaint(this->m_hWnd, &ps);
}

如果重写了WM_PAINT消息,就不会再调用重写的虚函数了,优先交给WM_PAINT消息处理函数处理。

视图窗口创建流程

下断点分析

进入这个函数

熟悉的窗口结构体

创建之前的窗口处理函数,(1)注册窗口(2)更改cs未空的成员

埋个钩子,对WM_CREATE消息感兴趣,保存对象到全局变量程序线程信息,并且在钩子回调函数绑定句柄与对象

视图窗口的创建与框架窗口的创建是一样的

命令消息 WM_COMMAND 处理顺序

给 CMyApp,CMyFrameWnd,CMyView三个添加 WM_COMMAND 消息处理函数

#include <afxwin.h>
#include "resource.h"


class CMyView : public CView {
	DECLARE_MESSAGE_MAP()
public:
	void OnDraw(CDC* pDC);
	afx_msg void OnPaint();
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyView, CView)
	ON_COMMAND( ID_NEW, OnNew )
	ON_WM_PAINT()
END_MESSAGE_MAP()
void CMyView::OnNew() {
	AfxMessageBox("视图类处理了WM_COMMAND消息");
}
void CMyView::OnPaint() {
	PAINTSTRUCT ps = { 0 };
	HDC hdc = ::BeginPaint(this->m_hWnd, &ps);
	::TextOut(hdc, 200, 200, "CMyView::OnPaint", strlen("CMyView::OnPaint"));
	::EndPaint(this->m_hWnd, &ps);
}
void CMyView::OnDraw(CDC* pDC) {
	pDC->TextOut(100, 100, "CMyView::OnDraw");
}


class CMyFrameWnd : public CFrameWnd {
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnPaint();
	afx_msg int OnCreate(LPCREATESTRUCT pcs);
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
	ON_WM_PAINT()
	ON_COMMAND( ID_NEW, OnNew )
	ON_WM_CREATE()
END_MESSAGE_MAP()
void CMyFrameWnd::OnNew() {
	AfxMessageBox("框架类处理了WM_COMMAND消息");
}
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) {
	CMyView* pView = new CMyView;
	pView->Create(NULL, "MFCView", WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(0, 0, 200, 200), this,
		AFX_IDW_PANE_FIRST);
	this->m_pViewActive = pView;
	return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint() {
	PAINTSTRUCT ps = { 0 };
	HDC hdc = ::BeginPaint(this->m_hWnd, &ps);
	::TextOut(hdc, 100, 100, "我是框架窗口客户区", strlen("我是框架窗口客户区"));
	::EndPaint(this->m_hWnd, &ps);
}



class CMyWinApp : public CWinApp {
	DECLARE_MESSAGE_MAP()
public:
	virtual BOOL InitInstance();
	afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
	ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew() {
	AfxMessageBox("应用程序类处理了WM_COMMAND消息");
}
BOOL CMyWinApp::InitInstance() {
	CMyFrameWnd* pFrame = new CMyFrameWnd;
	pFrame->Create(NULL, "MFCView", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault,
		NULL, (CHAR*)IDR_MENU1);
	this->m_pMainWnd = pFrame;
	pFrame->ShowWindow(SW_SHOW);
	pFrame->UpdateWindow();
	return TRUE;
}
CMyWinApp theApp;

可以知道 WM_COMMADN 消息处理的顺序:视图类---框架类---应用程序类

值得一提的是,this->m_pViewActive = pView;? 激活当前视图窗口,否则需要先点击以下视图窗口,才能点击 文件--新建。

对象关系

CMyApp 应用程序类是全局的,有一个成员变量,保存了CMyFrameWnd对象地址

CMyFrameWnd对象有一个成员变量保存了 CMyView 对象的地址

也就说说拿到了CMyApp就可以拿到所有对象。

注意:this->m_pViewActive = pView; 还可以激活当前窗口

把这句代码注释掉对比以下:

没有点击视图窗口,点击? 文件--新建,是框架类处理的命令消息

点击视图窗口,点击? 文件--新建,是视图类处理的命令消息

添加上后,点击? 文件--新建,是视图类处理的命令消息

这句代码可以直接把这个窗口设置为激活状态。

文章来源:https://blog.csdn.net/qq_61553520/article/details/135176006
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。