MFC 快速入门


概述

  • MFC微软基础类库的作用在Windows平台做GUI开发使用
  • MFC框架设计思想

Windows消息机制

  • SDK 软件开发工具包(Software Development Kit)

SDK是软件开发人员为特定软件包、框架、硬件平台、操作系统等建立引用软件的开发工具的集合。

  • API 应用程序编程接口(Application Programming Interface)

WindowsAPI函数是通过C实现的,主要在windows.h头文件中进行了声明。

  • 窗口和句柄

窗口是Windows应用程序中非常重要的元素,一个Windows应用程序至少要有一个窗口,称为主窗口。
窗口时屏幕上的一块矩形区域,是Windows应用程序与用户进行交互的接口,利用窗口可接受用户输入及显示输出。

 
应用程序窗口

窗口可分为客户区和非客户区,客户区市窗口的一部分。

窗口可有一个父窗口,有父窗口的窗口称为子窗口。

Windows应用程序中,窗口时通过窗口句柄(HWND)来标识,对窗口的操作时首先要得到窗口句柄。

句柄(HANDLE)是Windows程序的一个重要概念,在Windows程序中,有各种资源如窗口、图标、光标、画刷等。系统在创建这些资源时会为其分配内存,并返回标识资源的标识号即句柄。

  • 消息和消息队列

Windows程序设计是一种完全不同于传统DOS的程序设计方法,是一种事件驱动方式的程序设计模式,主要是基于消息的。

每个Windows应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。

例如,当用户在窗口中画图时,按下鼠标左键,此时操作系统会感知此事件,于是将事件包装成一个消息,投递到应用程序的消息队列中,等待应用程序的处理。然后,应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。在这个处理过程中,操作系统会给应用程序发送消息,实际是操作系统调用程序中一个专门负责处理消息的函数,这个函数成为窗口过程。

 
消息队列
  • WinMain函数

当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain()函数,实际上是由插入到可执行文件中的启动代码调用的。

WinMain()是Windows程序的入口函数,与DOS程序的入口点函数main()的作用是相同的,但WinMain()函数结束或返回时,Windows程序结束。

Windows编程模型

完整的Win32程序#include<windows.h>实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序实现步骤:

  1. WinMain函数定义
  2. 创建窗口
  3. 消息循环
  4. 编写窗口过程函数

VS2017配置

包含目录的路径,这里以SDk版本10.0.15063.0为例,添加路径如下:
C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\shared C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\ucrt C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\um C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\winrt 库目录的路径,添加路径如下: C:\Program Files (x86)\Windows Kits\10\Lib\10.0.15063.0\ucrt\x86 C:\Program Files (x86)\Windows Kits\10\Lib\10.0.15063.0\um\x86 

windows.c

$ vim windows.c //底层实现窗口的头文件 #include <windows.h> /** * 程序入口函数 * WINAPI 宏 代表 __stdcall,表示参数传递顺序,从右到左依次入栈,在函数返回前清空栈。 * HINSTACE H表示句柄 * HINSTACE hInstance 应用程序实例句柄 * HINSTACE hPrevInstance 上一个应用程序句柄,在win32环境下参数一般为NULL,不起作用。 * LPSTR lpCmdLine 代表 char * argv[] * int nShowCmd 显示命令,即最大化、最小化、正常 */ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { //1.设计窗口 //2.注册窗口 //3.创建窗口 //4.显示更新 //5.通过循环获取消息 //6.处理消息即窗口过程 //设计窗口 WNDCLASS wc;//Windows类 wc.cbClsExtra = 0;//类的额外内存 wc.cbWndExtra = 0;//窗口额外内存 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//设置背景 wc.hCursor = LoadCursor(NULL, IDC_HAND);//设置光标,参数1为NULL为系统提供的光标 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//设置图标 wc.hInstance = hInstance;//应用程序实例句柄,传入实例句柄 wc.lpfnWndProc = WindowProc;//窗口过程,即回调函数 wc.lpszClassName = TEXT("WIN");//窗口类名 wc.lpszMenuName = NULL;//窗口菜单名称 wc.style = 0;//显示风格 0默认风格 //注册窗口 RegisterClass(&wc); //创建窗口 // lpClassName 窗口类名 // lpWindowName 窗口标题名称 // dwStyle 窗口风格 混合风格 // x X坐标 默认值 CW_USERDEFAULT // y Y坐标 默认值 CW_USERDEFAULT // nWidth // nHeight 默认值 CW_USERDEFAULT // hWndParent 父窗口,顶层方式弹出为NULL // hMenu 窗口菜单 // hInstance 实例句柄 // lpParam 附加值 HWND hwnd = CreateWindow( wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, CW_USEDEFAULT );//todo “CreateWindowExW”: 指针与实参 12 不匹配 //显示更新 ShowWindow( hwnd, SW_SHOWNORMAL//展示方式 普通方式 ); UpdateWindow(hwnd); //通过循环获取消息 /* 每个消息都是一个结构体 HWND hwnd; 主窗口句柄 UINT message; 消息名称 WPARAM wParam; 附件消息 通常为键盘消息 LPARAM lParam; 附加消息 通常为鼠标左右键消息 DWORD time; 消息产生时间 POINT pt; 附加消息 鼠标坐标点消息 */ MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { /* 捕获消息 GetMessage() _Out_ LPMSG lpMsg;//消息地hi _In_opt_ HWND hWnd;//捕获窗口 NULL为捕获所有窗口 _In_ UNIT wMsgFilterMin;//最小的过滤消息 0表示捕获所有消息 _In_ UINT wMsgFilterMax;//最大的过滤消息 0表示捕获所有消息 */ //if (GetMessage(&msg, NULL, 0, 0) == FALSE) { // break;//若关闭窗口则退出死循环 //} // 翻译消息 TranslateMessage(&msg);//例如针对键盘组合快捷键需翻译 // 分发消息 DispatchMessage(&msg); } return 0; } 

窗口处理过程

/** * 处理窗口过程 * HWND hWnd 消息所属的窗口句柄 * UINT uMsg 具体的消息名称 * WPARAM wParam 键盘附加消息 * LPARAM lParam 鼠标附加消息 */ LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { //根据不同消息做不同的处理 switch (uMsg) { //关闭窗口 发送另一个消息WM_DESTROY case WM_CLOSE: DestroyWindow(hWnd); //所有xxxWindow为结尾的方法都不会进入消息队列而会直接执行 break; //关闭窗口退出进程 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);//todo 从“char [1024]”到“LPCWSTR”的类型不兼容 MessageBox(hWnd, buf, TEXT("TITLE"), MB_OK); break; } //键盘按下 case WM_KEYDOWN: MessageBox(hWnd, TEXT("KEYDOWN"), TEXT("TITLE"), MB_OK); break; //绘图 case WM_PRINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 100, 100, TEXT("PRINT"), strlen("PRINT")); EndPaint(hWnd, &ps); break; } } //返回值使用默认处理方式 return DefWindowProc(hWnd, uMsg, wParam, lParam); } 

MFC

MFC(Microsoft Foundation Classes, 微软基础类库)是微软提供的类库(class libraries),以C++类的形式封装的WindowsAPI,包含一个应用程序框架,以减少应用程序开发人员的工作量。其中类包含大量Windows句柄封装类和Windows内建控件和组件的封装类。

MFC把Windows SDK API函数包装成几百个类,MFC给Windows操作系统提供面向对象的接口,支持可重用性、自包含性以及其他OPP原则。MFC通过编写类来封装窗口、对话框等其他对象,引入关键的虚函数(覆盖虚函数可改变派生类的功能)来完成,MFC设计者使类库带来的总开销降到了最低。

MFC快速入门

  • MFC源文件后缀为.cpp,因为MFC是C++编写的。
  • 编写MFC程序需包含#include<afxwin.h>头文件
$ vim MFCApp.h

// MFCApp.h: PROJECT_NAME 应用程序的主头文件
#pragma once

#ifndef __AFXWIN_H__
    #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif
// 主符号
#include "resource.h"       

// CMFCAppApp:
// 有关此类的实现,请参阅 MFCApp.cpp

//应用程序类CWinApp派生类(子类)
class CMFCAppApp : public CWinApp
{
public:
    CMFCAppApp();

// 重写
public:
    //基类的虚函数,派生类只是重写,MFC程序的入口地址。
    virtual BOOL InitInstance();

// 实现
    //声明消息映射,必须在类声明中。
    DECLARE_MESSAGE_MAP()
};

extern CMFCAppApp theApp;

MFC消息映射

消息映射是将消息和成员函数相互关联的表,例如框架窗口接收一个鼠标左击消息,MFC将搜索该窗口的消息映射,如果存在一个处理WM_LBUTTONDOWN消息的处理程序,就调用OnLButtonDown

//声明消息映射,必须在类声明中。
DECLARE_MESSAGE_MAP()
// 定义消息宏,必须在类实现中。 BEGIN_MESSAGE_MAP(CMFCAppApp, CWinApp) ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() 

Windows 字符集

  • 多字节中1个字符对应1个字节
  • 中文 1个字符对应多个字节
  • 宽字节 Unicode
  • 多字节转为宽字节 L"test"
  • TEXT() 具有自适应编码转码
  • TCHER()具有自适应编码转码
 
字符集

统计字符串长度

//统计多字节长度 int num = 0; char * p = "test"; num = strlen(p); //统计宽字节字符串 wchar_t *p = L"test"; int num = wcslen(p); 

char *CString之间的转换

// char *转CString char * p = "test"; CString str = CString(p); //CString转char * CString str = CString("test"); CStringA tmp; tmp = str; char * p = tmp.GetBuffer(); 
  • MFC中后缀为Ex的函数都是扩展函数
  • MFC中以Afx为前缀的都是全局函数

MFC基于对话框编程

对话框是一种特殊类型的窗口,大多数Windows程序都是通过对话框与用户进行交互。

 
控件设计
 
控件实现

模态对话框

  1. 创建对话框
    资源视图>Dialog>右键>插入Dialog>重命名为 IDD_EXEC
  2. 为对话框添加类
    IDD_EXEC>右击>添加类>类命名为CDlgExec 头文件命名为DlgExec
  3. 为按钮添加事件处理程序
// TODO: 在此添加控件通知处理程序代码 void CMfcDlg::OnBnClickedLogin() { //弹出模态对话框,具有堵塞功能。 CDlgExec dlg; dlg.DoModal(); } 

非模态对话框

  1. 创建对话框
    资源视图>Dialog>右键>插入Dialog>重命名为 IDD_Show
  2. 为对话框添加类
    IDD_EXEC>右击>添加类>类命名为CDlgShow 头文件命名为DlgShow
  3. 主对话框头文件添加私有属性
$ vim MfcDlg.h #include "DlgShow.h" // 类中添加私有属性 private: CDlgShow dlg; 
  1. 主对话框消息处理程序初始化中添加创建非模态框对话框
$ vim MfcDlg.cpp BOOL CMfcDlg::OnInitDialog() { //创建非模态对话框 dlg.Create(IDD_SHOW); } 
  1. 事件处理程序中添加显示
// 控件通知处理程序代码 void CMfcDlg::OnBnClickedLogin() { //弹出非模态对话框 //CDlgShow dlg; //dlg.Create(IDD_SHOW);//创建 dlg.ShowWindow(SW_SHOWNORMAL);//显示 } 

静态文本 CStaticText

  • 添加变量 以 STATIC为结尾的ID是不可以添加变量的需修改ID
  • 设置内容 SetWindowTextW()
  • 获取内容 GetWindowTextW()
void CMfcDlg::OnBnClickedSet() { text.SetWindowTextW(TEXT("Account")); btnSet.SetWindowTextW(TEXT("禁用")); btnSet.EnableWindow(FALSE);//禁用按钮 } void CMfcDlg::OnBnClickedGet() { CString str; text.GetWindowTextW(str); MessageBox(str); } 

静态图片BMP

  • 添加变量
  • 初始化显示图片
//显示图片 img.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//设置风格为16进制位图并居中显示 //获取图片路径获取bitmap句柄 #define HBMP(filepath, width, height)(HBITMAP)LoadImage(AfxGetInstanceHandle(), filepath, IMAGE_BITMAP, width, height, LR_LOADFROMFILE|LR_CREATEDIBSECTION) //宽高按空间大小设置 CRect rect; img.GetWindowRect(rect); //设置bitmap img.SetBitmap(HBMP(TEXT("./Image/plane.bmp"), rect.Width(), rect.Height())); 

编辑框 EditControl

  • 属性:mutiline 多行、want return换行
  • 获取设置值:GetWindowTextW()SetWindowText()W
  • 单行点击回车会退出,重写OnOK()注释其中代码。对话框
  • 退出当前对话框 CDialog::OnOk()CDialog::OnCancel()
// 源编辑框默认文本 editor_src.SetWindowTextW(TEXT("please input something")); //点击复制按钮 void CMfcDlg::OnBnClickedBtnCopy() { CString str; editor_src.GetWindowTextW(str); editor_dst.SetWindowTextW(str); } 

退出的方式

void CMfcDlg::OnBnClickedExit() { //退出当前对话框 CDialog::OnOK();//点击确定退出对话框 //CDialog::OnCancel();//点击取消推出对话框 //exit(0);//退出所有对话框 } 

添加变量时添加value,本身关联的变量就是值。

UpdateData(TRUE);//将控件中的内容同步到变量中 

void CMfcDlg::OnBnClickedBtnSetval() { editval = TEXT("setval"); UpdateData(FALSE);//将变量中的值同步到控件中 } void CMfcDlg::OnBnClickedBtnGetval() { UpdateData(TRUE);//将控件中的内容同步到变量中 MessageBox(editval); } 

下拉框CComBox

  • data属性中添加数据,逗号分隔。sort属性排序。
  • type属性为DropList则不可编辑
  • 添加元素AddString()
  • 删除元素DeleteString()
  • 插入元素InsertString()
  • 设置默认SetCurSel()
  • 获取当前索引GetCurSel()
  • 根据索引获取元素GetLBText(int Index, CString str)
  • 控件事件OnCbnSelChangeXXX()
//下拉框添加元素 role.AddString(TEXT("管理员")); role.AddString(TEXT("渠道商")); role.AddString(TEXT("代理商")); role.AddString(TEXT("员工")); role.AddString(TEXT("玩家")); //设置默认选项 role.SetCurSel(0); //插入选项 role.InsertString(4, TEXT("会员")); //删除选项 role.DeleteString(3); //获取索引所对应的值 CString str; role.GetLBText(1, str); //MessageBox(str); 
void CMfcDlg::OnCbnSelchangeComboRole() { //获取当前索引 int index = role.GetCurSel(); //获取值 CString str; role.GetLBText(index, str); MessageBox(str); } 

列表控件 CListCtrl

  • 控件属性view设置为报表模式Report
  • 添加表头InsertColumn()
  • 添加正文 从0开始 InsertItem(0,content)
  • 添加正文其他列表SetItemText(row, col, content)
  • 设置风格 整行选中LVS_EX_FULLROWSELECT 网格显示LVS_EX_GRIDLINES
 
列表控件 CListCtrl
/*列表控件*/ //设置属性 整行选中 网格显示 list.SetExtendedStyle(list.GetExtendedStyle()|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); //设置表头 CString strArr[] = {TEXT("账号"), TEXT("昵称"), TEXT("邮箱")}; for (int i = 0; i < 3; i++) { list.InsertColumn(i, strArr[i], LVCFMT_LEFT, 100);//参数 索引 内容 对齐 列宽 } list.InsertItem(0, TEXT("a12l31c09e")); list.SetItemText(0, 1, TEXT("Alice")); list.SetItemText(0, 2, TEXT("alice520@gmail.com")); //循环添加 int j; for (int i = 0; i < 10; i++) { j = 0; CString str; str.Format(TEXT("alice%d"), i); list.InsertItem(i, str); list.SetItemText(i, ++j, str); list.SetItemText(i, ++j, str); } 

树形控件Tree Control

  • 拖拽控件,命名ID为IDC_TREE
  • 设置私有private变量CTreeCtrl tree;
  • 设置属性:Has Buttons设置按钮、Has Lines设置线、Lines At Root设置根节点线
  • 准备图标:资源视图>Icon>右键>添加资源>Icon>导入,图标采用ico文件72像素。
  • 初始化中设置图标CMfcDlg::OnInitDialog()
//设置图标 //CImageList imglist;//图片集合,必须保存.h作为成员属性。 imglist.Create(30, 30, ILC_COLOR32, 6, 6); //添加图标 HICON icons[6]; icons[0] = AfxGetApp()->LoadIconW(IDI_ICON1); icons[1] = AfxGetApp()->LoadIconW(IDI_ICON2); icons[2] = AfxGetApp()->LoadIconW(IDI_ICON3); icons[3] = AfxGetApp()->LoadIconW(IDI_ICON4); icons[4] = AfxGetApp()->LoadIconW(IDI_ICON5); icons[5] = AfxGetApp()->LoadIconW(IDI_ICON6); for (int i = 0; i < 6; i++) { imglist.Add(icons[i]); } //设置图标 tree.SetImageList(&imglist, TVSIL_NORMAL); //设置根节点 HTREEITEM root = tree.InsertItem(TEXT("ROOT"), 0, 1, NULL); //设置父节点 HTREEITEM parent = tree.InsertItem(TEXT("PARENT"), 2, 3, root); //设置子节点 HTREEITEM child1 = tree.InsertItem(TEXT("CHILD1"), 4, 5, parent); HTREEITEM child2 = tree.InsertItem(TEXT("CHILD2"), 4, 5, parent); //设置默认选项 tree.SelectItem(child1); 
  • 设置事件OnTvnSelchanged
//树项目切换 void CMfcDlg::OnTvnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult) { LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); *pResult = 0; //获取当前选中项 HTREEITEM item = tree.GetSelectedItem(); CString text = tree.GetItemText(item); MessageBox(text); } 
 
树形控件

标签页Tab Control

 
标签页
  • 引用TabSheet.hTabSheet.cpp并添加到项目中

TabSheet.h

#if !defined(AFX_TABSHEET_H__42EE262D_D15F_46D5_8F26_28FD049E99F4__INCLUDED_)  
#define AFX_TABSHEET_H__42EE262D_D15F_46D5_8F26_28FD049E99F4__INCLUDED_  

#if _MSC_VER > 1000  
#pragma once  
#endif // _MSC_VER > 1000  
// TabSheet.h : header file  
//  

/////////////////////////////////////////////////////////////////////////////  
// CTabSheet window  
#define MAXPAGE 16  

class CTabSheet : public CTabCtrl
{
    // Construction  
public:
    CTabSheet();

    // Attributes  
public:

    // Operations  
public:

    // Overrides  
    // ClassWizard generated virtual function overrides  
    //{{AFX_VIRTUAL(CTabSheet)  
    //}}AFX_VIRTUAL  

    // Implementation  
public:
    int GetCurSel();
    int SetCurSel(int nItem);
    void Show();
    void Free();

    void SetRect();
    BOOL AddPage(LPCTSTR title, CDialog *pDialog, UINT ID);
    virtual ~CTabSheet();

    // Generated message map functions  
protected:
    LPCTSTR m_Title[MAXPAGE];
    UINT m_IDD[MAXPAGE];
    CDialog* m_pPages[MAXPAGE];
    int m_nNumOfPages;
    int m_nCurrentPage;
    //{{AFX_MSG(CTabSheet)  
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    //}}AFX_MSG  

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////  

//{{AFX_INSERT_LOCATION}}  
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.  

#endif // !defined(AFX_TABSHEET_H__42EE262D_D15F_46D5_8F26_28FD049E99F4__INCLUDED_)  

TabSheet.cpp


// TabSheet.cpp : implementation file // #include "stdafx.h" #include "TabSheet.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CTabSheet CTabSheet::CTabSheet() { m_nNumOfPages = 0; m_nCurrentPage = 0; } CTabSheet::~CTabSheet() { } BEGIN_MESSAGE_MAP(CTabSheet, CTabCtrl) //{{AFX_MSG_MAP(CTabSheet) ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTabSheet message handlers BOOL CTabSheet::AddPage(LPCTSTR title, CDialog *pDialog, UINT ID) { if (MAXPAGE == m_nNumOfPages) return FALSE; m_nNumOfPages++; m_pPages[m_nNumOfPages - 1] = pDialog; m_IDD[m_nNumOfPages - 1] = ID; m_Title[m_nNumOfPages - 1] = title; return TRUE; } void CTabSheet::SetRect() { CRect tabRect, itemRect; int nX, nY, nXc, nYc; GetClientRect(&tabRect); GetItemRect(0, &itemRect); nX = itemRect.left; nY = itemRect.bottom + 1; nXc = tabRect.right - itemRect.left - 2; nYc = tabRect.bottom - nY - 2; m_pPages[0]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_SHOWWINDOW); for (int nCount = 1; nCount < m_nNumOfPages; nCount++) m_pPages[nCount]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_HIDEWINDOW); } void CTabSheet::Show() { for (int i = 0; i < m_nNumOfPages; i++) { m_pPages[i]->Create(m_IDD[i], this); InsertItem(i, m_Title[i]); } m_pPages[0]->ShowWindow(SW_SHOW); for (int i = 1; i < m_nNumOfPages; i++) m_pPages[i]->ShowWindow(SW_HIDE); SetRect(); } void CTabSheet::OnLButtonDown(UINT nFlags, CPoint point) { CTabCtrl::OnLButtonDown(nFlags, point); if (m_nCurrentPage != GetCurFocus()) { m_pPages[m_nCurrentPage]->ShowWindow(SW_HIDE); m_nCurrentPage = GetCurFocus(); m_pPages[m_nCurrentPage]->ShowWindow(SW_SHOW); // m_pPages[m_nCurrentPage]->SetFocus(); } } int CTabSheet::SetCurSel(int nItem) { if (nItem < 0 || nItem >= m_nNumOfPages) return -1; int ret = m_nCurrentPage; if (m_nCurrentPage != nItem) { m_pPages[m_nCurrentPage]->ShowWindow(SW_HIDE); m_nCurrentPage = nItem; m_pPages[m_nCurrentPage]->ShowWindow(SW_SHOW); // m_pPages[m_nCurrentPage]->SetFocus(); CTabCtrl::SetCurSel(nItem); } return ret; } int CTabSheet::GetCurSel() { return CTabCtrl::GetCurSel(); } //释放page资源 void CTabSheet::Free() { CTabCtrl::DeleteAllItems(); for (int i = 0; i < m_nNumOfPages; i++) { m_pPages[i]->DestroyWindow(); m_IDD[i] = NULL; m_Title[i] = NULL; } m_nCurrentPage = 0; m_nNumOfPages = 0; //CTabCtrl::DestroyWindow(); //注意不要将this指针释放了 } 
  • 拖入控件TabControl
  • 添加变量,设置类型为TabSheet
  • 创建标签页,设置属性bordernone,设置stylechild
  • 标签页添加类
  • 主窗口添加标签
/*标签页*/ tab.AddPage(TEXT("系统设置"), &tabcfg, IDD_TAB_CFG); tab.AddPage(TEXT("系统管理"), &tabmgr, IDD_TAB_MGR); //显示 tab.Show(); 
 
 
 
 
 
 





免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM