MFC函数集合:深入学习与实践指南

本文还有配套的精品资源,点击获取

简介:MFC(Microsoft Foundation Classes)是一个面向对象的C++类库,用于简化Windows应用程序的开发。本学习资料集合了一系列MFC函数的应用和实践,涵盖从MFC基础架构到高级特性,包括文档/视图架构、线程管理、控件条使用、消息映射、GDI绘图、数据库访问、网络编程及ActiveX控件的使用。学习这些内容可以帮助开发者更高效地在项目中运用MFC,并理解Windows应用程序开发的核心概念。

1. MFC基础架构与文档/视图架构

1.1 MFC编程模型简介

MFC(Microsoft Foundation Classes)为开发者提供了一套面向对象的C++类库,用于简化Windows平台下的应用程序开发。MFC将Windows的API抽象为类和对象,从而简化了事件驱动编程和图形用户界面(GUI)的实现。一个典型的MFC应用程序包含应用程序对象、文档模板、文档、视图以及框架窗口等核心组件。

1.2 文档/视图架构核心概念

文档/视图架构是MFC应用程序的核心概念之一,这种架构将数据处理(文档)与数据展示(视图)分离。 CDocument 类负责数据的管理和存储,而 CView 类则负责如何将数据呈现给用户。这种分离增强了程序的模块化和可维护性,同时也支持一个文档与多个视图的关联,使得一个数据源可以有多种表现形式。

1.3 文档/视图架构的优势和应用场景

文档/视图架构的最大优势在于其对多种视图的支持,能够同时提供如编辑视图、打印预览等多种用户界面。这在许多需要多视角呈现信息的应用场景中非常有用,比如文档编辑器、图像浏览器等。架构的分层设计也有利于团队分工协作,文档层可以由一个团队负责,而视图层可以由另一个团队独立开发。

通过掌握MFC基础架构与文档/视图架构,开发者可以快速搭建起应用程序的骨架,并进一步深入到具体功能模块的实现中。接下来的章节中,我们将深入探讨MFC中的关键类以及它们在应用程序中的作用和应用方式。

2. CWinApp和CWinThread核心类

2.1 CWinApp类的生命周期和消息处理

2.1.1 CWinApp类的初始化和启动流程

CWinApp 类是MFC应用程序中的一个核心类,负责整个应用程序的初始化和启动流程。当一个基于MFC的应用程序启动时,首先进行的是全局对象的创建,其中就包括 CWinApp 派生类的实例。这个实例在构造函数中会注册一个消息泵,并在初始化函数中执行应用程序的初始化代码。其过程如下:

全局对象创建 :当程序执行入口 WinMain 被调用时,首先创建 CWinApp 派生类的全局对象。这一过程通常在程序的全局变量区完成。

消息泵注册 :在 CWinApp 的构造函数中,会通过调用 AfxWinInit 函数注册一个消息泵。这个消息泵是所有Windows程序消息循环的基础。

初始化函数调用 :随后 WinMain 会调用 CWinApp 派生类的 InitInstance 函数,执行应用程序特有的初始化操作。

消息循环启动 : InitInstance 执行完毕后,进入主消息循环,开始处理窗口消息。

class CMyApp : public CWinApp

{

public:

virtual BOOL InitInstance();

};

BOOL CMyApp::InitInstance()

{

// 应用程序特有初始化代码

// ...

return TRUE; // 初始化成功则返回TRUE

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

CMyApp theApp; // 创建CWinApp派生类对象

// ...

if(!theApp.InitInstance())

return FALSE; // 如果InitInstance返回FALSE,则退出应用程序

theApp.Run(); // 进入主消息循环

return 0;

}

2.1.2 消息泵和消息循环的实现原理

在MFC中,消息泵(Message Pump)和消息循环(Message Loop)是应用程序响应用户交互的核心机制。消息泵是负责不断检索消息队列并分派到相应窗口的过程。而消息循环则是应用程序的核心循环,持续在执行直到用户选择关闭程序。

一个典型的MFC消息循环代码如下:

int CWinApp::Run()

{

MSG msg;

m_pMainWnd->ShowWindow(m_nCmdShow); // 显示应用程序窗口

m_pMainWnd->UpdateWindow(); // 更新窗口

while(::GetMessage(&msg, NULL, 0, 0)) // 消息泵:从消息队列获取消息

{

if(!AfxCallWndProc(m_pMainWnd, &msg)) // 分派消息到窗口处理函数

return FALSE;

if(msg.message == WM_QUIT) // 如果收到退出消息,则退出循环

break;

}

return (int) msg.wParam; // 返回退出码

}

CWinApp::Run 函数中, GetMessage 函数从系统消息队列中检索消息, DispatchMessage 函数将消息分派到相应的窗口过程函数。在这个过程中, AfxCallWndProc 负责调用窗口过程函数,并传递消息参数。

2.2 CWinThread类在多线程中的应用

2.2.1 CWinThread类的线程对象模型

在多线程编程中, CWinThread 类扮演了线程控制的角色。每一个由 CWinThread 派生的线程对象都可以拥有一个独立的消息队列。其结构如下:

线程入口函数 :每个线程都有自己的入口函数,通常是由 CWinThread::InitInstance 和 CWinThread::Run 共同构成。在 InitInstance 中进行初始化,在 Run 中执行线程的主要工作。

消息循环 :与主线程类似,每个线程对象可以有一个消息循环,用于处理该线程自己的消息队列。

线程终止 : CWinThread 提供了 ExitThread 等方法来安全地终止线程。

下面是一个线程的简略示例代码:

class CMyThread : public CWinThread

{

public:

virtual BOOL InitInstance();

virtual int Run();

static CMyThread* PASCAL ThreadFunc(LPVOID pParam);

};

BOOL CMyThread::InitInstance()

{

// 线程初始化代码

return TRUE;

}

int CMyThread::Run()

{

// 线程的运行代码

// ...

return 0;

}

// 线程创建与执行函数

void StartMyThread()

{

CMyThread* pThread = AFXINGLETON::GetThreadObject();

if(!pThread->CreateThread())

AfxMessageBox(_T("Thread creation failed."));

else

pThread->Run();

}

2.2.2 线程间的通信与同步机制

当多个线程需要访问共享资源时,就必须使用同步机制来防止数据竞争和确保线程安全。MFC提供了多种同步对象,如 CMutex 、 CSemaphore 、 CCriticalSection 和 CEvent 等。以下是使用 CCriticalSection 进行线程同步的一个示例:

CCriticalSection g_csResource; // 定义临界区对象

void Thread1Function()

{

g_csResource.Lock(); // 进入临界区

// 临界区代码,访问共享资源

g_csResource.Unlock(); // 离开临界区

}

void Thread2Function()

{

g_csResource.Lock(); // 进入临界区

// 临界区代码,访问共享资源

g_csResource.Unlock(); // 离开临界区

}

在这个例子中,只有获得锁的线程才能进入临界区,访问共享资源,而其他线程则会被阻塞直到锁被释放。这种方法可以避免多个线程同时访问同一个资源而产生的数据不一致问题。

MFC的同步机制是多线程编程中不可或缺的部分,合理使用这些同步对象,可以有效地保证程序的稳定性和效率。

3. CDocument和CView的文档/视图分离

文档/视图分离是MFC框架中的一个核心概念,它允许应用程序将数据和表示数据的视图分开处理,从而使得程序结构更加清晰,并且易于维护。本章将深入探讨CDocument和CView类在实现文档/视图分离模型中的作用及其内部机制。

3.1 文档/视图分离模型的实现原理

3.1.1 CDocument类的数据管理功能

CDocument类在MFC框架中扮演着数据仓库的角色。它是所有文档数据的管理者,负责存储、加载和保存数据,同时也管理文档的生命周期,包括创建新文档、打开现有文档以及关闭文档。

在CDocument类中,与数据管理相关的成员函数主要有以下几个:

OnNewDocument() :创建新文档时调用,用于初始化文档。 OnOpenDocument() :打开现有文档时调用,用于加载文档数据。 OnSaveDocument() :保存文档时调用,用于将数据写入文件。 Serialize() :序列化函数,用于读写文档数据到文件或内存。

下面是一个简单的Serialize()函数示例:

void CYourDocument::Serialize(CArchive& ar)

{

if (ar.IsStoring())

{

// 将数据写入归档对象(例如:文件)

ar << m_someData;

}

else

{

// 从归档对象中读取数据

ar >> m_someData;

}

}

在序列化过程中,开发者需要确保数据成员的读写顺序一致,以便正确加载和保存文档状态。 CArchive 对象通过其 IsStoring() 成员函数区分操作是存储还是加载。

3.1.2 CView类的视图显示与交互设计

CView类代表文档的视图,它是用户与应用程序数据交互的界面。一个文档可以有多个视图,它们共享同一个文档对象,但可以提供不同的视图角度或展示方式。CView类提供了丰富的接口用于绘图和事件处理,使得视图可以响应用户的操作,如键盘输入、鼠标点击等,并且能够将这些操作反馈给CDocument对象进行相应的数据处理。

CView类中与视图显示和交互相关的关键函数有:

OnDraw(CDC* pDC) :绘制视图内容,例如绘制文档数据的图形表示。 OnInitialUpdate() :视图首次显示时调用,通常用来执行初始化设置。 OnUpdate() :当CDocument中的数据发生改变时,会通知视图进行更新。

下面是一个OnDraw()函数的示例:

void CYourView::OnDraw(CDC* pDC)

{

CDocument* pDoc = GetDocument();

if (pDoc == nullptr)

return;

// 根据需要绘制的内容调用GDI函数

// 例如:绘制文档中的数据

pDC->Rectangle(10, 10, 100, 100);

}

在上面的代码中, Rectangle 函数使用GDI函数 CDC 对象 pDC 来绘制一个矩形。在实际应用中,开发者需要根据文档中的数据来定制绘图逻辑。

3.2 文档与视图的关联和数据更新

3.2.1 数据传递和视图刷新机制

文档与视图之间的关联是通过MFC框架动态建立的。当用户对视图进行操作时,视图会通知文档更新数据;当数据发生变化时,文档会通知所有关联的视图进行更新。

文档更新视图的机制通常涉及以下几个步骤:

当数据更新时,CDocument对象调用 UpdateAllViews() 函数。 UpdateAllViews() 通知所有视图调用其 OnUpdate() 函数。 在 OnUpdate() 函数中,视图决定如何更新显示内容。

3.2.2 多视图共享同一文档的策略

在MFC中,多个视图可以共享同一文档对象。这些视图可以是不同类型的视图,例如一个文档可以同时有一个列表视图和一个图形视图。共享同一个文档对象意味着所有视图都能访问到相同的数据集合。

要实现多视图共享文档,需要注意以下几点:

确保文档类设计为多视图友好。 在创建新视图时,将新视图与已存在的文档对象关联起来。 在文档对象的 OnNewView() 和 RemoveView() 函数中维护视图列表。

下面是一个维护视图列表的示例:

void CYourDocument::OnNewView()

{

CYourView* pView = new CYourView;

AddView(pView);

pView->Create(this);

}

void CYourDocument::RemoveView(CYourView* pView)

{

RemoveViewFromList(pView);

pView->DestroyWindow();

delete pView;

}

在这个示例中, OnNewView 函数创建并关联一个新视图到文档。 RemoveView 函数则负责从文档的视图列表中移除并销毁一个视图。

在本章节中,我们探讨了MFC框架中文档/视图分离模型的实现原理和机制。从CDocument类如何管理数据,到CView类如何展示和处理用户交互。我们了解到,文档对象与视图对象之间的通信机制以及多视图共享文档的策略。MFC框架通过这种分离模型允许开发者构建更加灵活、可维护的大型应用程序。在下一章节中,我们将深入了解CFrameWnd类在MFC应用程序主窗口设计中的应用,并探讨主窗口的个性化定制策略。

4. CFrameWnd与应用程序主窗口定制

4.1 CFrameWnd类在主窗口设计中的应用

CFrameWnd类是MFC中用于设计应用程序主窗口的基础类。它封装了Win32窗口的创建和管理,使得开发者能够快速构建功能丰富、外观定制的主窗口。

4.1.1 创建和管理应用程序窗口

要创建一个基本的窗口,开发者需要从CFrameWnd派生出一个类,并在派生类中重写 OnCreate 函数,以处理窗口创建时的消息。以下是一个简单的示例代码:

class CMyAppWnd : public CFrameWnd

{

public:

CMyAppWnd()

{

Create(NULL, _T("My Application Window"));

ShowWindow(SW_SHOW);

}

virtual int OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

// 在这里可以添加创建子窗口和控件的代码

return 0;

}

};

在这段代码中, CMyAppWnd 构造函数中调用了 Create 函数来创建窗口。 OnCreate 函数是窗口创建过程中被调用的,如果返回值为0,则表示创建成功。在这个函数中,你可以添加创建菜单栏、工具栏和状态栏等子窗口的代码。

4.1.2 窗口菜单和工具栏的集成方法

为了集成菜单和工具栏,你可以使用MFC提供的 LoadFrame 函数来加载资源。以下是一个如何加载菜单和工具栏的示例:

BOOL CMyAppWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

// 加载菜单

HMENU hMenu = LoadMenu(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MY_MENU));

SetMenu(hMenu);

// 加载工具栏

HINSTANCE hInst = AfxGetInstanceHandle();

HICON hIcon = AfxGetApp()->LoadIcon(IDR_MY_ICON);

CToolBarCtrl tb;

tb.Create(this, TBStyle_FLAT, IDR_MY_TOOLBAR);

tb.AddBitmap(16, hInst, IDR_MY_TOOLBAR, 0, 0, RGB(255,0,0));

tb.SetBarStyle(tb.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

tb.EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&tb);

return 0;

}

这段代码展示了如何加载一个菜单资源和工具栏资源,并将其集成到应用程序主窗口中。 LoadMenu 函数加载菜单资源, LoadIcon 加载图标资源,而 CToolBarCtrl 创建工具栏控件。通过调用 DockControlBar 函数,可以将工具栏控件停靠到主窗口的边缘。

4.2 应用程序主窗口的个性化定制

MFC框架提供了丰富的功能,允许开发者定制窗口的外观和行为以满足应用程序特定的需求。通过重写 PreCreateWindow 函数,可以自定义窗口样式。

4.2.1 窗口样式的定制与扩展

PreCreateWindow 函数在窗口创建之前被调用,允许你修改窗口创建参数。以下是一个示例,展示了如何修改窗口样式:

BOOL CMyAppWnd::PreCreateWindow(CREATESTRUCT& cs)

{

if (!CFrameWnd::PreCreateWindow(cs))

return FALSE;

// 设置窗口样式为 WS_OVERLAPPED | WS_SYSMENU | WS_THICKFRAME

// 并移除窗口标题和边框

cs.style &= ~(WS_CAPTION | WS_THICKFRAME | WS_SYSMENU);

cs.dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);

return TRUE;

}

在这段代码中,我们移除了默认的窗口标题和边框,并设置了窗口样式。这允许开发者自定义窗口的外观,使其看起来与应用程序的风格更加匹配。

4.2.2 状态栏和其他窗口元素的设计

在许多应用程序中,状态栏是用来显示程序状态信息的一个重要窗口元素。MFC同样提供了简单的接口来集成状态栏。

BOOL CMyAppWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

// 创建和显示状态栏

CreateStatusBar();

SetStatusText(_T("Ready"));

// 在此代码中可以添加其他窗口元素的创建

return 0;

}

在这段代码中,通过调用 CreateStatusBar 函数创建了一个状态栏,并通过 SetStatusText 设置状态栏上显示的文本。

接下来,让我们进一步探讨如何使用CFrameWnd类来定制应用程序的主窗口,以及如何在MFC应用程序中实现个性化的界面设计。通过结合使用 PreCreateWindow 函数和资源编辑器,开发者可以创建具有独特外观和用户体验的主窗口。

5. CControlBar系列控件条使用

5.1 CControlBar派生类的应用

5.1.1 工具栏(CToolBar)和状态栏(CStatusBar)的定制

工具栏(CToolBar)和状态栏(CStatusBar)是MFC应用程序中常见的用户界面元素,用于提供快捷功能的访问和显示程序状态信息。CControlBar类是这些派生类的基类,提供了许多共通的功能,如位置、大小和层叠顺序的管理。

定制CToolBar通常包括以下步骤: 1. 创建CToolBar对象并添加到框架窗口中。 2. 添加按钮和分隔符来构建工具栏的布局。 3. 为每个按钮设置位图资源,并关联命令消息。 4. 实现按钮的响应函数来处理用户的点击事件。

状态栏的定制则包括: 1. 创建CStatusBar对象并附加到框架窗口。 2. 定义状态栏各个部分的布局和宽度。 3. 实现更新状态栏信息的成员函数。

示例代码片段展示如何在MFC应用中创建和初始化一个工具栏:

void CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

// 创建并加载工具栏资源

if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return -1; // 失败则不能继续

}

// 创建并加载状态栏资源

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(IDS_STATUS_BAR,川_STBAR(indicators)|STBAR_TIMEOUT|

STBAR الكبرى))

{

TRACE0("Failed to create status bar\n");

return -1; // 失败则不能继续

}

// 更新状态栏为默认状态

m_wndStatusBar.SetPaneInfo(0,IDI_RETURN,RBPS_LEFT край);

m_wndStatusBar.SetPaneInfo(1,IDI_SIMBOL,RBPS_LEFT край);

m_wndStatusBar.SetPaneInfo(2,IDI_SIMBOL_2,RBPS_LEFT край);

m_wndStatusBar.SetPaneInfo(3,IDI_SIMBOL_3,RBPS_LEFT край);

m_wndStatusBar.SetPaneInfo(4,IDI_TIME,RBPS_RIGHT край);

// ...

}

在上述代码中, CreateEx 方法用于创建工具栏,并设置了工具栏的一些基本属性。 LoadToolBar 用于加载预定义的工具栏资源。状态栏的创建和初始化也类似,先创建状态栏,然后通过 SetIndicators 方法设置状态栏的指示器。

5.1.2 对话条(CDialogBar)的使用与实现

对话条(CDialogBar)是一个可以像工具栏一样停靠的特殊对话框。它通常用于创建复杂的工具栏界面,允许通过对话框的方式组织控件,并且具有更灵活的布局和事件处理能力。

对话条的创建和使用步骤通常包括: 1. 创建继承自CDialogBar的类。 2. 在类中添加并布局控件。 3. 在框架窗口中创建并初始化对话条。 4. 管理对话条的显示和隐藏。

以下是一个对话条类的示例定义:

class COptionsDialogBar : public CDialogBar

{

public:

COptionsDialogBar()

{

// 对话条ID

SetPaneInfo(0, IDB_OPTIONS, PANE_LEFT, 100);

}

// 重写对话条的DoDataExchange,用于支持DDX/DDV

virtual void DoDataExchange(CDataExchange* pDX) override;

protected:

DECLARE_MESSAGE_MAP()

public:

afx_msg void OnBnClickedButtonSave();

afx_msg void OnBnClickedButtonCancel();

// 控件变量

CButton m_btnSave;

CButton m_btnCancel;

// ...

};

BEGIN_MESSAGE_MAP(COptionsDialogBar, CDialogBar)

ON_BN_CLICKED(IDC_BUTTON_SAVE, &COptionsDialogBar::OnBnClickedButtonSave)

ON_BN_CLICKED(IDC_BUTTON_CANCEL, &COptionsDialogBar::OnBnClickedButtonCancel)

END_MESSAGE_MAP()

在框架窗口中初始化对话条:

void CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

// ...

// 创建并加载对话条资源

if (!m_wndOptionsBar.CreateEx(this, WS_EX_CONTROLPARENT, WS_CHILD | WS_VISIBLE | CBRS_TOP)

|| !m_wndOptionsBar.LoadBar(IDD_OPTIONS_BAR))

{

TRACE0("Failed to create options dialog bar\n");

return -1;

}

// ...

m_wndOptionsBar.ShowWindow(SW_SHOW);

// ...

}

在这段代码中,我们首先定义了一个对话条类 COptionsDialogBar ,它包含了两个按钮控件,并为这些控件定义了消息映射。然后,在主窗口的 OnCreate 函数中创建了这个对话条对象,并加载了相应的资源。最后,通过调用 ShowWindow 来控制对话条的显示。

5.2 控件条的管理与布局

5.2.1 控件条的创建与附加

在MFC中,控件条通常指工具栏、状态栏和对话条等可以停靠在应用程序主窗口边缘的控件。创建控件条时,我们通常需要定义一个继承自CControlBar的类,并在该类中进行控件的布局和初始化。创建完成后,需要将这些控件条附加到主框架窗口。

控件条的创建包括以下步骤: 1. 定义一个继承自CControlBar的类。 2. 在该类的构造函数中调用基类的构造函数,并传入WS_CHILD、WS_VISIBLE等标志位。 3. 重写OnCreateControlBar成员函数,执行控件条创建和布局的具体工作。 4. 在框架窗口类中创建控件条实例,并通过调用 DockControlBar 方法将其附加到主窗口。

控件条附加到框架窗口的代码示例如下:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

if (CFrameWnd::OnCreateClient(lpcs, pContext))

{

// 创建工具栏并附加到框架窗口

if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return FALSE; // 失败则不能继续

}

// 将工具栏附加到框架窗口

DockControlBar(&m_wndToolBar);

// 创建状态栏并附加到框架窗口

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(IDS_STATUS_BAR,川_STBAR(indicators)|STBAR_TIMEOUT|

STBAR الكبرى))

{

TRACE0("Failed to create status bar\n");

return FALSE; // 失败则不能继续

}

// 将状态栏附加到框架窗口

DockControlBar(&m_wndStatusBar);

// ...

}

return TRUE;

}

在此代码中, CreateEx 方法用于创建工具栏,并设置了工具栏的一些基本属性。 LoadToolBar 方法用于加载预定义的工具栏资源。 DockControlBar 方法用于将工具栏附加到框架窗口的指定位置。

5.2.2 动态调整控件条位置和大小的策略

在某些场景下,用户可能需要动态地调整控件条的位置和大小,以适应不同的使用环境和个性化设置。MFC提供了一套机制来支持这种动态调整功能。

动态调整控件条的策略通常包括以下几个步骤: 1. 在框架窗口中捕捉鼠标事件,如鼠标左键按下(WM_LBUTTONDOWN)和鼠标移动(WM_MOUSEMOVE)。 2. 判断用户是否点击了控件条的调整手柄或者边框。 3. 在鼠标移动事件中,根据鼠标位置计算新的控件条位置和大小。 4. 调用控件条的 MoveWindow 或者 SetWindowPos 方法来调整其位置和大小。 5. 确保在调整时控件条不会和其他控件或者窗口边界冲突。

示例代码展示如何响应鼠标事件来移动控件条:

void CMainFrame::OnLButtonDown(UINT nFlags, CPoint point)

{

CFrameWnd::OnLButtonDown(nFlags, point);

if (m_wndToolBar.IsWindowEnabled() && m_wndToolBar.IsWindowVisible())

{

// 获取工具栏的句柄

CWnd* pWndToolbar = &m_wndToolBar;

// 捕捉鼠标事件

SetCapture();

m_rectStart = m_wndToolBar.GetWindowRect();

m_ptStart = point;

m_bSizing = false;

}

}

void CMainFrame::OnMouseMove(UINT nFlags, CPoint point)

{

CFrameWnd::OnMouseMove(nFlags, point);

if (m_bSizing)

{

// 计算新位置和大小

int x = m_rectStart.left + (point.x - m_ptStart.x);

int y = m_rectStart.top + (point.y - m_ptStart.y);

int width = m_rectStart.Width();

int height = m_rectStart.Height();

// 移动工具栏

m_wndToolBar.MoveWindow(x, y, width, height);

}

}

在这个示例中,我们重写了 OnLButtonDown 和 OnMouseMove 事件处理函数。当用户按下鼠标左键时,记录工具栏的位置,并开始捕捉鼠标移动事件。当鼠标移动时,根据鼠标的移动量重新计算工具栏的位置,并调用 MoveWindow 来更新位置。

为了确保控件条的大小和位置调整不会与其他窗口元素冲突,通常需要实现一些边界检查逻辑,确保调整后的位置和大小仍然符合用户界面布局的需求。

6. MFC中的高级编程技术

6.1 消息映射宏的高级应用

在MFC(Microsoft Foundation Classes)框架中,消息映射是一种将Windows消息与类成员函数关联起来的机制。消息映射宏是实现消息映射的关键,它们允许开发者将特定消息映射到处理函数。高级应用包括理解消息映射的内部实现机制以及如何定制消息处理流程和扩展消息类型。

6.1.1 消息映射的实现机制

消息映射在MFC中通过一系列预定义的宏实现,比如 ON_COMMAND , ON_MESSAGE 等。开发者可以通过这些宏来指定消息处理函数。以 ON_COMMAND 宏为例,当应用程序接收到一个命令消息时,比如菜单项点击,框架会查找与该命令相关联的 ON_COMMAND 宏,并调用相应的成员函数。

BEGIN_MESSAGE_MAP(CYourDialog, CDialogEx)

ON_BN_CLICKED(IDC_MY_BUTTON, &CYourDialog::OnBnClickedMyButton)

END_MESSAGE_MAP()

上面的例子展示了如何将按钮点击事件( BN_CLICKED 消息)映射到成员函数 OnBnClickedMyButton 。

6.1.2 定制消息处理流程和扩展消息类型

定制消息处理流程意味着在消息处理函数中加入额外的逻辑,比如数据校验、状态更新等。开发者可以通过继承和重写消息处理函数来实现。扩展消息类型通常涉及定义新的消息并使用 ON_MESSAGE 宏,以便在消息映射中处理自定义消息。

// 在消息映射中添加自定义消息处理

BEGIN_MESSAGE_MAP(CYourDialog, CDialogEx)

ON_MESSAGE(WM_MY_CUSTOM_MESSAGE, &CYourDialog::OnMyCustomMessage)

END_MESSAGE_MAP()

// 自定义消息处理函数

LRESULT CYourDialog::OnMyCustomMessage(WPARAM wParam, LPARAM lParam)

{

// 自定义逻辑处理

return 0;

}

6.2 GDI绘图与控件封装的技巧

图形设备接口(GDI)是Windows用来处理图形和文本输出的一个核心组件。在MFC中, CDC 类及其派生类为GDI绘图提供了封装。

6.2.1 CDC类在图形绘制中的应用

CDC 类封装了GDI对象,并提供了用于绘制图形和文本的方法。例如,使用 CDC 对象的 Rectangle 方法可以在指定的位置绘制矩形:

void CMyView::OnDraw(CDC* pDC)

{

CRect rect(10, 10, 200, 100);

pDC->Rectangle(rect);

}

6.2.2 CBrush、CPen、CFont等GDI对象的高级使用

CBrush 、 CPen 、 CFont 等类分别用于创建画刷、画笔和字体GDI对象。在绘图前,必须创建并选入设备上下文(DC)的对象,以使用这些资源。

// 创建一个红色画刷并选入DC

CBrush brush(RGB(255, 0, 0));

CBrush* pOldBrush = pDC->SelectObject(&brush);

// 在DC上绘制

pDC->Rectangle(rect);

// 恢复旧画刷

pDC->SelectObject(pOldBrush);

6.3 数据库与网络编程在MFC中的集成

MFC提供了一套丰富的类和接口来支持数据库和网络编程。

6.3.1 ODBC数据库访问的实现

使用MFC的ODBC类进行数据库访问,如 CDatabase 、 CRecordset ,可以简化数据库操作。连接数据库、执行查询、处理结果集等都可以通过这些类来完成。

// 打开数据库连接

CDatabase db;

if (db.Open(_T("ODBC;DSN=MyDatabase;UID=user;PWD=password")))

{

// 执行数据库操作

db.ExecuteSQL(_T("UPDATE table SET column = value WHERE condition"));

// 关闭连接

db.Close();

}

6.3.2 Winsock网络编程的封装和应用

MFC对Winsock API进行了封装,提供了 CAsyncSocket 类和 CSocket 类,简化了网络编程。这两个类分别用于异步和同步网络通信。

// 使用CAsyncSocket进行异步通信

class CMySocket : public CAsyncSocket

{

public:

void OnReceive(int nErrorCode);

};

void CMySocket::OnReceive(int nErrorCode)

{

// 处理接收到的数据

}

CMySocket socket;

if (socket.Create(port, SOCK_STREAM, FD_READ))

{

socket.Listen();

}

6.4 ActiveX控件的创建与应用

ActiveX控件是一种可以被应用程序或其他控件嵌入的组件,MFC提供了创建和使用ActiveX控件的机制。

6.4.1 ActiveX控件的创建过程和集成方法

创建ActiveX控件的过程通常包括定义控件的属性、方法和事件,然后使用MFC类库中的 COleControl 类进行实现。

// MyControl.h

class CMyControl : public COleControl

{

// 控件属性、方法和事件的定义

};

在其他MFC应用程序中,可以像使用标准控件一样使用ActiveX控件。

6.4.2 利用ActiveX控件扩展应用程序功能

利用ActiveX控件可以增强应用程序的功能,比如通过集成第三方控件来提供特定的功能,如图表绘制、数据分析等。

// 在对话框中添加ActiveX控件

class CMyDialog : public CDialogEx

{

// 定义ActiveX控件的变量

COleControl m控件;

};

通过上述各节的详细讨论,我们可以看到MFC框架在高级编程技术方面的强大功能和灵活性。无论是消息处理的深入定制、GDI绘图技术的运用,还是数据库与网络编程的集成,亦或是ActiveX控件的创建与应用,MFC为开发者提供了一个全面的解决方案。

本文还有配套的精品资源,点击获取

简介:MFC(Microsoft Foundation Classes)是一个面向对象的C++类库,用于简化Windows应用程序的开发。本学习资料集合了一系列MFC函数的应用和实践,涵盖从MFC基础架构到高级特性,包括文档/视图架构、线程管理、控件条使用、消息映射、GDI绘图、数据库访问、网络编程及ActiveX控件的使用。学习这些内容可以帮助开发者更高效地在项目中运用MFC,并理解Windows应用程序开发的核心概念。

本文还有配套的精品资源,点击获取

鬭字笔顺
【高手在民间】定襄铁匠故事