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