MFC 快速入門

概述

  • MFC微軟基礎(chǔ)類庫(kù)的作用在Windows平臺(tái)做GUI開發(fā)使用
  • MFC框架設(shè)計(jì)思想

Windows消息機(jī)制

  • SDK 軟件開發(fā)工具包(Software Development Kit)

SDK是軟件開發(fā)人員為特定軟件包谓媒、框架赂摆、硬件平臺(tái)、操作系統(tǒng)等建立引用軟件的開發(fā)工具的集合知纷。

  • API 應(yīng)用程序編程接口(Application Programming Interface)

WindowsAPI函數(shù)是通過C實(shí)現(xiàn)的浩峡,主要在windows.h頭文件中進(jìn)行了聲明禁谦。

  • 窗口和句柄

窗口是Windows應(yīng)用程序中非常重要的元素划纽,一個(gè)Windows應(yīng)用程序至少要有一個(gè)窗口锁荔,稱為主窗口结洼。
窗口時(shí)屏幕上的一塊矩形區(qū)域黎做,是Windows應(yīng)用程序與用戶進(jìn)行交互的接口叉跛,利用窗口可接受用戶輸入及顯示輸出松忍。

應(yīng)用程序窗口

窗口可分為客戶區(qū)和非客戶區(qū),客戶區(qū)市窗口的一部分筷厘。

窗口可有一個(gè)父窗口鸣峭,有父窗口的窗口稱為子窗口。

Windows應(yīng)用程序中酥艳,窗口時(shí)通過窗口句柄(HWND)來標(biāo)識(shí)摊溶,對(duì)窗口的操作時(shí)首先要得到窗口句柄。

句柄(HANDLE)是Windows程序的一個(gè)重要概念充石,在Windows程序中莫换,有各種資源如窗口、圖標(biāo)骤铃、光標(biāo)拉岁、畫刷等。系統(tǒng)在創(chuàng)建這些資源時(shí)會(huì)為其分配內(nèi)存惰爬,并返回標(biāo)識(shí)資源的標(biāo)識(shí)號(hào)即句柄喊暖。

  • 消息和消息隊(duì)列

Windows程序設(shè)計(jì)是一種完全不同于傳統(tǒng)DOS的程序設(shè)計(jì)方法,是一種事件驅(qū)動(dòng)方式的程序設(shè)計(jì)模式撕瞧,主要是基于消息的陵叽。

每個(gè)Windows應(yīng)用程序開始執(zhí)行后,系統(tǒng)都會(huì)為該程序創(chuàng)建一個(gè)消息隊(duì)列丛版,這個(gè)消息隊(duì)列用來存放該程序創(chuàng)建的窗口的消息巩掺。

例如,當(dāng)用戶在窗口中畫圖時(shí)页畦,按下鼠標(biāo)左鍵胖替,此時(shí)操作系統(tǒng)會(huì)感知此事件,于是將事件包裝成一個(gè)消息寇漫,投遞到應(yīng)用程序的消息隊(duì)列中刊殉,等待應(yīng)用程序的處理。然后州胳,應(yīng)用程序通過一個(gè)消息循環(huán)不斷地從消息隊(duì)列中取出消息记焊,并進(jìn)行響應(yīng)。在這個(gè)處理過程中栓撞,操作系統(tǒng)會(huì)給應(yīng)用程序發(fā)送消息遍膜,實(shí)際是操作系統(tǒng)調(diào)用程序中一個(gè)專門負(fù)責(zé)處理消息的函數(shù)碗硬,這個(gè)函數(shù)成為窗口過程。

消息隊(duì)列
  • WinMain函數(shù)

當(dāng)Windows操作系統(tǒng)啟動(dòng)一個(gè)程序時(shí)瓢颅,它調(diào)用的就是該程序的WinMain()函數(shù)恩尾,實(shí)際上是由插入到可執(zhí)行文件中的啟動(dòng)代碼調(diào)用的。

WinMain()是Windows程序的入口函數(shù)挽懦,與DOS程序的入口點(diǎn)函數(shù)main()的作用是相同的翰意,但WinMain()函數(shù)結(jié)束或返回時(shí),Windows程序結(jié)束信柿。

Windows編程模型

完整的Win32程序#include<windows.h>實(shí)現(xiàn)的功能是創(chuàng)建一個(gè)窗口冀偶,并在該窗口中響應(yīng)鍵盤及鼠標(biāo)消息,程序?qū)崿F(xiàn)步驟:

  1. WinMain函數(shù)定義
  2. 創(chuàng)建窗口
  3. 消息循環(huán)
  4. 編寫窗口過程函數(shù)

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
庫(kù)目錄的路徑,添加路徑如下:
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
//底層實(shí)現(xiàn)窗口的頭文件
#include <windows.h>
/**
* 程序入口函數(shù)
* WINAPI 宏 代表 __stdcall形病,表示參數(shù)傳遞順序客年,從右到左依次入棧,在函數(shù)返回前清空棧漠吻。
* HINSTACE H表示句柄
* HINSTACE hInstance 應(yīng)用程序?qū)嵗浔?* HINSTACE hPrevInstance 上一個(gè)應(yīng)用程序句柄量瓜,在win32環(huán)境下參數(shù)一般為NULL,不起作用侥猩。
* LPSTR lpCmdLine 代表 char * argv[]
* int nShowCmd 顯示命令榔至,即最大化、最小化欺劳、正常
*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    //1.設(shè)計(jì)窗口
    //2.注冊(cè)窗口
    //3.創(chuàng)建窗口
    //4.顯示更新
    //5.通過循環(huán)獲取消息
    //6.處理消息即窗口過程

    //設(shè)計(jì)窗口
    WNDCLASS wc;//Windows類
    wc.cbClsExtra = 0;//類的額外內(nèi)存
    wc.cbWndExtra = 0;//窗口額外內(nèi)存
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//設(shè)置背景
    wc.hCursor = LoadCursor(NULL, IDC_HAND);//設(shè)置光標(biāo),參數(shù)1為NULL為系統(tǒng)提供的光標(biāo)
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);//設(shè)置圖標(biāo)
    wc.hInstance = hInstance;//應(yīng)用程序?qū)嵗浔笕。瑐魅雽?shí)例句柄
    wc.lpfnWndProc = WindowProc;//窗口過程,即回調(diào)函數(shù)
    wc.lpszClassName = TEXT("WIN");//窗口類名
    wc.lpszMenuName = NULL;//窗口菜單名稱
    wc.style = 0;//顯示風(fēng)格 0默認(rèn)風(fēng)格
    
    //注冊(cè)窗口
    RegisterClass(&wc);

    //創(chuàng)建窗口
    // lpClassName 窗口類名
    // lpWindowName 窗口標(biāo)題名稱
    // dwStyle 窗口風(fēng)格 混合風(fēng)格
    // x X坐標(biāo) 默認(rèn)值 CW_USERDEFAULT
    // y Y坐標(biāo) 默認(rèn)值 CW_USERDEFAULT
    // nWidth
    // nHeight 默認(rèn)值 CW_USERDEFAULT
    // hWndParent 父窗口划提,頂層方式彈出為NULL
    // hMenu 窗口菜單 
    // hInstance 實(shí)例句柄
    // 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”: 指針與實(shí)參 12 不匹配

    //顯示更新
    ShowWindow(
        hwnd,
        SW_SHOWNORMAL//展示方式 普通方式
    );
    UpdateWindow(hwnd);

    //通過循環(huán)獲取消息
    /*
        每個(gè)消息都是一個(gè)結(jié)構(gòu)體
        HWND hwnd; 主窗口句柄
        UINT message; 消息名稱
        WPARAM wParam; 附件消息 通常為鍵盤消息
        LPARAM lParam; 附加消息 通常為鼠標(biāo)左右鍵消息
        DWORD time; 消息產(chǎn)生時(shí)間
        POINT pt; 附加消息 鼠標(biāo)坐標(biāo)點(diǎn)消息
    */
    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;//若關(guān)閉窗口則退出死循環(huán)
        //}
        // 翻譯消息
        TranslateMessage(&msg);//例如針對(duì)鍵盤組合快捷鍵需翻譯
        // 分發(fā)消息
        DispatchMessage(&msg);
    }

    return 0;
}

窗口處理過程

/**
 * 處理窗口過程
 * HWND hWnd 消息所屬的窗口句柄
 * UINT uMsg 具體的消息名稱
 * WPARAM wParam 鍵盤附加消息
 * LPARAM lParam 鼠標(biāo)附加消息
*/
LRESULT CALLBACK WindowProc(
    HWND hWnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    //根據(jù)不同消息做不同的處理
    switch (uMsg) {
        //關(guān)閉窗口 發(fā)送另一個(gè)消息WM_DESTROY
        case WM_CLOSE:
            DestroyWindow(hWnd); //所有xxxWindow為結(jié)尾的方法都不會(huì)進(jìn)入消息隊(duì)列而會(huì)直接執(zhí)行
            break;
        //關(guān)閉窗口退出進(jìn)程
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        //鼠標(biāo)左鍵按下
        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;
        }
    }
    //返回值使用默認(rèn)處理方式
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

MFC

MFC(Microsoft Foundation Classes枫弟, 微軟基礎(chǔ)類庫(kù))是微軟提供的類庫(kù)(class libraries),以C++類的形式封裝的WindowsAPI鹏往,包含一個(gè)應(yīng)用程序框架淡诗,以減少應(yīng)用程序開發(fā)人員的工作量。其中類包含大量Windows句柄封裝類和Windows內(nèi)建控件和組件的封裝類伊履。

MFC把Windows SDK API函數(shù)包裝成幾百個(gè)類韩容,MFC給Windows操作系統(tǒng)提供面向?qū)ο蟮慕涌冢С挚芍赜眯蕴破佟⒆园砸约捌渌鸒PP原則群凶。MFC通過編寫類來封裝窗口、對(duì)話框等其他對(duì)象哄辣,引入關(guān)鍵的虛函數(shù)(覆蓋虛函數(shù)可改變派生類的功能)來完成请梢,MFC設(shè)計(jì)者使類庫(kù)帶來的總開銷降到了最低赠尾。

MFC快速入門

  • MFC源文件后綴為.cpp,因?yàn)镸FC是C++編寫的毅弧。
  • 編寫MFC程序需包含#include<afxwin.h>頭文件
$ vim MFCApp.h

// MFCApp.h: PROJECT_NAME 應(yīng)用程序的主頭文件
#pragma once

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

// CMFCAppApp:
// 有關(guān)此類的實(shí)現(xiàn)气嫁,請(qǐng)參閱 MFCApp.cpp

//應(yīng)用程序類CWinApp派生類(子類)
class CMFCAppApp : public CWinApp
{
public:
    CMFCAppApp();

// 重寫
public:
    //基類的虛函數(shù),派生類只是重寫够坐,MFC程序的入口地址寸宵。
    virtual BOOL InitInstance();

// 實(shí)現(xiàn)
    //聲明消息映射,必須在類聲明中咆霜。
    DECLARE_MESSAGE_MAP()
};

extern CMFCAppApp theApp;

MFC消息映射

消息映射是將消息和成員函數(shù)相互關(guān)聯(lián)的表邓馒,例如框架窗口接收一個(gè)鼠標(biāo)左擊消息嘶朱,MFC將搜索該窗口的消息映射蛾坯,如果存在一個(gè)處理WM_LBUTTONDOWN消息的處理程序,就調(diào)用OnLButtonDown疏遏。

//聲明消息映射脉课,必須在類聲明中。
DECLARE_MESSAGE_MAP()
// 定義消息宏财异,必須在類實(shí)現(xiàn)中倘零。
BEGIN_MESSAGE_MAP(CMFCAppApp, CWinApp)
    ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()

Windows 字符集

  • 多字節(jié)中1個(gè)字符對(duì)應(yīng)1個(gè)字節(jié)
  • 中文 1個(gè)字符對(duì)應(yīng)多個(gè)字節(jié)
  • 寬字節(jié) Unicode
  • 多字節(jié)轉(zhuǎn)為寬字節(jié) L"test"
  • TEXT() 具有自適應(yīng)編碼轉(zhuǎn)碼
  • TCHER()具有自適應(yīng)編碼轉(zhuǎn)碼
字符集

統(tǒng)計(jì)字符串長(zhǎng)度

//統(tǒng)計(jì)多字節(jié)長(zhǎng)度
int num = 0;
char * p = "test";
num = strlen(p);

//統(tǒng)計(jì)寬字節(jié)字符串
wchar_t *p  = L"test";
int num = wcslen(p);

char *CString之間的轉(zhuǎn)換

// char *轉(zhuǎn)CString
char * p = "test";
CString str = CString(p);

//CString轉(zhuǎn)char *
CString str = CString("test");
CStringA tmp;
tmp = str;
char * p = tmp.GetBuffer();
  • MFC中后綴為Ex的函數(shù)都是擴(kuò)展函數(shù)
  • MFC中以Afx為前綴的都是全局函數(shù)

MFC基于對(duì)話框編程

對(duì)話框是一種特殊類型的窗口,大多數(shù)Windows程序都是通過對(duì)話框與用戶進(jìn)行交互戳寸。

控件設(shè)計(jì)
控件實(shí)現(xiàn)

模態(tài)對(duì)話框

  1. 創(chuàng)建對(duì)話框
    資源視圖>Dialog>右鍵>插入Dialog>重命名為 IDD_EXEC
  2. 為對(duì)話框添加類
    IDD_EXEC>右擊>添加類>類命名為CDlgExec 頭文件命名為DlgExec
  3. 為按鈕添加事件處理程序
// TODO: 在此添加控件通知處理程序代碼
void CMfcDlg::OnBnClickedLogin()
{
    //彈出模態(tài)對(duì)話框呈驶,具有堵塞功能。
    CDlgExec dlg;
    dlg.DoModal();
}

非模態(tài)對(duì)話框

  1. 創(chuàng)建對(duì)話框
    資源視圖>Dialog>右鍵>插入Dialog>重命名為 IDD_Show
  2. 為對(duì)話框添加類
    IDD_EXEC>右擊>添加類>類命名為CDlgShow 頭文件命名為DlgShow
  3. 主對(duì)話框頭文件添加私有屬性
$ vim MfcDlg.h
#include "DlgShow.h"
// 類中添加私有屬性
private:
    CDlgShow dlg;
  1. 主對(duì)話框消息處理程序初始化中添加創(chuàng)建非模態(tài)框?qū)υ捒?/li>
$ vim MfcDlg.cpp
BOOL CMfcDlg::OnInitDialog()
{
    //創(chuàng)建非模態(tài)對(duì)話框
    dlg.Create(IDD_SHOW);
}
  1. 事件處理程序中添加顯示
// 控件通知處理程序代碼
void CMfcDlg::OnBnClickedLogin()
{
    //彈出非模態(tài)對(duì)話框
    //CDlgShow dlg;
    //dlg.Create(IDD_SHOW);//創(chuàng)建
    dlg.ShowWindow(SW_SHOWNORMAL);//顯示
}

靜態(tài)文本 CStaticText

  • 添加變量 以 STATIC為結(jié)尾的ID是不可以添加變量的需修改ID
  • 設(shè)置內(nèi)容 SetWindowTextW()
  • 獲取內(nèi)容 GetWindowTextW()
void CMfcDlg::OnBnClickedSet()
{
    text.SetWindowTextW(TEXT("Account"));

    btnSet.SetWindowTextW(TEXT("禁用"));
    btnSet.EnableWindow(FALSE);//禁用按鈕
}


void CMfcDlg::OnBnClickedGet()
{
    CString str;
    text.GetWindowTextW(str);
    MessageBox(str);
}

靜態(tài)圖片BMP

  • 添加變量
  • 初始化顯示圖片
//顯示圖片
img.ModifyStyle(0xf, SS_BITMAP | SS_CENTERIMAGE);//設(shè)置風(fēng)格為16進(jìn)制位圖并居中顯示
//獲取圖片路徑獲取bitmap句柄
#define HBMP(filepath, width, height)(HBITMAP)LoadImage(AfxGetInstanceHandle(), filepath, IMAGE_BITMAP, width, height, LR_LOADFROMFILE|LR_CREATEDIBSECTION)
//寬高按空間大小設(shè)置
CRect rect;
img.GetWindowRect(rect);
//設(shè)置bitmap
img.SetBitmap(HBMP(TEXT("./Image/plane.bmp"), rect.Width(), rect.Height()));

編輯框 EditControl

  • 屬性:mutiline 多行疫鹊、want return換行
  • 獲取設(shè)置值:GetWindowTextW()SetWindowText()W
  • 單行點(diǎn)擊回車會(huì)退出袖瞻,重寫OnOK()注釋其中代碼。對(duì)話框
  • 退出當(dāng)前對(duì)話框 CDialog::OnOk()CDialog::OnCancel()
// 源編輯框默認(rèn)文本
editor_src.SetWindowTextW(TEXT("please input something"));
//點(diǎn)擊復(fù)制按鈕
void CMfcDlg::OnBnClickedBtnCopy()
{
   CString str;
   editor_src.GetWindowTextW(str);

   editor_dst.SetWindowTextW(str);
}

退出的方式

void CMfcDlg::OnBnClickedExit()
{
    //退出當(dāng)前對(duì)話框
    CDialog::OnOK();//點(diǎn)擊確定退出對(duì)話框
    //CDialog::OnCancel();//點(diǎn)擊取消推出對(duì)話框
    //exit(0);//退出所有對(duì)話框
}

添加變量時(shí)添加value拆吆,本身關(guān)聯(lián)的變量就是值聋迎。

UpdateData(TRUE);//將控件中的內(nèi)容同步到變量中

void CMfcDlg::OnBnClickedBtnSetval()
{
    editval = TEXT("setval");
    UpdateData(FALSE);//將變量中的值同步到控件中
}


void CMfcDlg::OnBnClickedBtnGetval()
{
    UpdateData(TRUE);//將控件中的內(nèi)容同步到變量中
    MessageBox(editval);
}

下拉框CComBox

  • data屬性中添加數(shù)據(jù),逗號(hào)分隔枣耀。sort屬性排序霉晕。
  • type屬性為DropList則不可編輯
  • 添加元素AddString()
  • 刪除元素DeleteString()
  • 插入元素InsertString()
  • 設(shè)置默認(rèn)SetCurSel()
  • 獲取當(dāng)前索引GetCurSel()
  • 根據(jù)索引獲取元素GetLBText(int Index, CString str)
  • 控件事件OnCbnSelChangeXXX()
//下拉框添加元素
role.AddString(TEXT("管理員"));
role.AddString(TEXT("渠道商"));
role.AddString(TEXT("代理商"));
role.AddString(TEXT("員工"));
role.AddString(TEXT("玩家"));
//設(shè)置默認(rèn)選項(xiàng)
role.SetCurSel(0);
//插入選項(xiàng)
role.InsertString(4, TEXT("會(huì)員"));
//刪除選項(xiàng)
role.DeleteString(3);
//獲取索引所對(duì)應(yīng)的值
CString str;
role.GetLBText(1, str);
//MessageBox(str);
void CMfcDlg::OnCbnSelchangeComboRole()
{
    //獲取當(dāng)前索引
    int index = role.GetCurSel();
    //獲取值
    CString str;
    role.GetLBText(index, str);
    MessageBox(str);
}

列表控件 CListCtrl

  • 控件屬性view設(shè)置為報(bào)表模式Report
  • 添加表頭InsertColumn()
  • 添加正文 從0開始 InsertItem(0,content)
  • 添加正文其他列表SetItemText(row, col, content)
  • 設(shè)置風(fēng)格 整行選中LVS_EX_FULLROWSELECT 網(wǎng)格顯示LVS_EX_GRIDLINES
列表控件 CListCtrl
/*列表控件*/
//設(shè)置屬性 整行選中 網(wǎng)格顯示
list.SetExtendedStyle(list.GetExtendedStyle()|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
//設(shè)置表頭
CString strArr[] = {TEXT("賬號(hào)"), TEXT("昵稱"), TEXT("郵箱")};
for (int i = 0; i < 3; i++) {
    list.InsertColumn(i, strArr[i], LVCFMT_LEFT, 100);//參數(shù) 索引 內(nèi)容 對(duì)齊 列寬
}
list.InsertItem(0, TEXT("a12l31c09e"));
list.SetItemText(0, 1, TEXT("Alice"));
list.SetItemText(0, 2, TEXT("alice520@gmail.com"));
//循環(huán)添加
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
  • 設(shè)置私有private變量CTreeCtrl tree;
  • 設(shè)置屬性:Has Buttons設(shè)置按鈕捞奕、Has Lines設(shè)置線牺堰、Lines At Root設(shè)置根節(jié)點(diǎn)線
  • 準(zhǔn)備圖標(biāo):資源視圖>Icon>右鍵>添加資源>Icon>導(dǎo)入,圖標(biāo)采用ico文件72像素颅围。
  • 初始化中設(shè)置圖標(biāo)CMfcDlg::OnInitDialog()
//設(shè)置圖標(biāo)
//CImageList imglist;//圖片集合伟葫,必須保存.h作為成員屬性。
imglist.Create(30, 30, ILC_COLOR32, 6, 6);
//添加圖標(biāo)
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]);
}
//設(shè)置圖標(biāo)
tree.SetImageList(&imglist, TVSIL_NORMAL);
//設(shè)置根節(jié)點(diǎn)
HTREEITEM root = tree.InsertItem(TEXT("ROOT"), 0, 1, NULL);
//設(shè)置父節(jié)點(diǎn)
HTREEITEM parent = tree.InsertItem(TEXT("PARENT"), 2, 3, root);
//設(shè)置子節(jié)點(diǎn)
HTREEITEM child1 = tree.InsertItem(TEXT("CHILD1"), 4, 5, parent);
HTREEITEM child2 = tree.InsertItem(TEXT("CHILD2"), 4, 5, parent);
//設(shè)置默認(rèn)選項(xiàng)
tree.SelectItem(child1);
  • 設(shè)置事件OnTvnSelchanged
//樹項(xiàng)目切換
void CMfcDlg::OnTvnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    *pResult = 0;

    //獲取當(dāng)前選中項(xiàng)
    HTREEITEM item = tree.GetSelectedItem();
    CString text = tree.GetItemText(item);
    MessageBox(text);
}
樹形控件

標(biāo)簽頁(yè)Tab Control

標(biāo)簽頁(yè)
  • 引用TabSheet.hTabSheet.cpp并添加到項(xiàng)目中

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
  • 添加變量谷浅,設(shè)置類型為TabSheet
  • 創(chuàng)建標(biāo)簽頁(yè)扒俯,設(shè)置屬性bordernone奶卓,設(shè)置stylechild
  • 標(biāo)簽頁(yè)添加類
  • 主窗口添加標(biāo)簽
/*標(biāo)簽頁(yè)*/
tab.AddPage(TEXT("系統(tǒng)設(shè)置"), &tabcfg, IDD_TAB_CFG);
tab.AddPage(TEXT("系統(tǒng)管理"), &tabmgr, IDD_TAB_MGR);
//顯示
tab.Show();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市撼玄,隨后出現(xiàn)的幾起案子夺姑,更是在濱河造成了極大的恐慌,老刑警劉巖掌猛,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盏浙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡荔茬,警方通過查閱死者的電腦和手機(jī)废膘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來慕蔚,“玉大人丐黄,你說我怎么就攤上這事】嘴” “怎么了灌闺?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)坏瞄。 經(jīng)常有香客問我桂对,道長(zhǎng),這世上最難降的妖魔是什么鸠匀? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任蕉斜,我火速辦了婚禮,結(jié)果婚禮上缀棍,老公的妹妹穿的比我還像新娘宅此。我一直安慰自己,他們只是感情好睦柴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布诽凌。 她就那樣靜靜地躺著,像睡著了一般坦敌。 火紅的嫁衣襯著肌膚如雪侣诵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天狱窘,我揣著相機(jī)與錄音杜顺,去河邊找鬼。 笑死蘸炸,一個(gè)胖子當(dāng)著我的面吹牛躬络,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搭儒,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼穷当,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼提茁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起馁菜,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤茴扁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后汪疮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峭火,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年智嚷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了卖丸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出社露,到底是詐尸還是另有隱情,我是刑警寧澤粹湃,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站泉坐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏裳仆。R本人自食惡果不足惜腕让,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望歧斟。 院中可真熱鬧纯丸,春花似錦、人聲如沸静袖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)队橙。三九已至坠陈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捐康,已是汗流浹背仇矾。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留解总,地道東北人贮匕。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像花枫,于是被迫代替她去往敵國(guó)和親刻盐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掏膏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容