美文网首页MFC
MFC 快速入门

MFC 快速入门

作者: JunChow520 | 来源:发表于2018-09-09 22:22 被阅读0次

    概述

    • 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();
    

    相关文章

      网友评论

        本文标题:MFC 快速入门

        本文链接:https://www.haomeiwen.com/subject/roqrgftx.html