界面和关联变量设置
创建一个基于对话框的MFC项目,给主对话框添加一个tab控件(设置关联变量 类型:CTabCtrl 名称:m_tab),添加两个子对话框(IDC_PAGE1和IDC_PAGE2),给子对话框添加一个list control控件(设置关联变量 类型:CListCtrl 名称:m_list),并将子对话框的边框属性设置为None,窗口样式设为child
在资源视图界面右击对话框给IDC_PAGE1和IDC_PAGE2添加对话框类,类名分别为CPage1,CPage2。
CTabCtrl类
主窗口界面
在C任务管理器Dlg类中添加CPage1和CPage2类型的变量page1和page2。
要通过这两成员来创建子窗口。不要忘记在pch.h中包含"CPage1.h","CPage2.h"头文件。
这个时候运行程序,结果如下
tab添加选项卡
C任务管理器Dlg类的OnInitDialog()方法中添加如下代码
m_tab.InsertItem(0, L"窗口名");
m_tab.InsertItem(1, L"进程");
这个时候运行程序tab控件上就有选项卡了
添加子窗口
CRect rect;m_tab.GetClientRect(&rect);//Create函数通过资源ID和所属的父窗口对象创建一个无模式对话框//创建的对话框如果要显示需要通过ShowWindow(SW_SHOW)显示page1.Create(IDD_PAGE1, &m_tab);page2.Create(IDD_PAGE2, &m_tab);rect.top += 22;rect.left += 1;rect.right -= 3;rect.bottom -= 2;page1.MoveWindow(&rect);page2.MoveWindow(&rect);page1.ShowWindow(SW_SHOW);page2.ShowWindow(SW_HIDE);
获取tab控件的窗口大小并把子对话框显示在tab控件合适的位置。
运行效果如下
这个时候tab的选项卡还不能切换显示对应的对话框。需要通过类向导添加TCN_SELCHANGE消息的响应函数
TCN_SELCHANGE消息
void C任务管理器Dlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{// TODO: 在此添加控件通知处理程序代码int sel = m_tab.GetCurSel();switch (sel){case 0:page1.ShowWindow(SW_SHOW);page2.ShowWindow(SW_HIDE);break;case 1:page2.ShowWindow(SW_SHOW);page1.ShowWindow(SW_HIDE);break;}*pResult = 0;
}
注意
这里有两个命令TCN_SELCHANGE和TCN_SELCHANGING,选项卡改变是先执行TCN_SELCHANGING,后执行TCN_SELCHANGE,在执行TCN_SELCHANGING的时候,选项卡还未最终完成切换,在这个时候m_tab.GetCurSel()得到的是原来那个选项卡。所以在进行选项卡切换的时候响应的是TCN_SELCHANGE消息
可以在TCN_SELCHANGING的响应函数中加入这段代码简单的验证一下
int sel = m_tab.GetCurSel();
CString str;
str.Format(L"%d", sel);
MessageBox(str);
运行程序发现实现了选项卡切换的功能,但是如果拉大主窗口,tab控件和子对话框的大小不会变。这个时候要响应WM_SIZE消息使主窗口在变化的时候对话框和tab控件也进行相应的变化。在子对话框中的list control控件也要如此
控件和子对话框适应主窗口的大小变化
//GetSafeHwnd()用来判断...是否存在CRect rect;if (m_tab.GetSafeHwnd()){m_tab.MoveWindow(0, 0, cx, cy);m_tab.GetClientRect(&rect);}rect.top += 22;rect.left += 1;rect.right -= 3;rect.bottom -= 2;if (page1.GetSafeHwnd() && page2.GetSafeHwnd()){page1.MoveWindow(&rect);page2.MoveWindow(&rect);}
子对话框界面
CPage1
通过类向导添加OnInitDialog()
BOOL CPage1::OnInitDialog()
{CDialogEx::OnInitDialog();m_list.ModifyStyle(0,LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_VSCROLL | WS_BORDER);m_list.InsertColumn(0, L"序号", LVCFMT_LEFT, 50);m_list.InsertColumn(1, L"窗口标题", LVCFMT_LEFT,200);m_list.InsertColumn(2, L"窗口句柄", LVCFMT_LEFT, 200);m_list.InsertColumn(3, L"窗口类", LVCFMT_LEFT, 200);int i = 0;CWnd*pwnd=AfxGetMainWnd()->GetWindow(GW_HWNDFIRST);while (pwnd){CString str;str.Format(L"%d", i + 1);m_list.InsertItem(i,str);pwnd->GetWindowTextW(str);//获取窗口标题m_list.SetItemText(i, 1, str);str.Format(L"%x", pwnd->m_hWnd);//获取窗口句柄m_list.SetItemText(i, 2, str);TCHAR name[256];GetClassName(pwnd->m_hWnd, name, 256);//获取窗口类名m_list.SetItemText(i, 3, name);pwnd = pwnd->GetWindow(GW_HWNDNEXT);i++;}return TRUE; // return TRUE unless you set the focus to a control
}
在OnInitDialog()中实现枚举所有的窗口并显示,枚举窗口的流程是
获取主窗口(AfxGetMainWnd())-》获取和主窗口平级的第一个窗口(GetWindow(GW_HWNDFIRST))-》循环获取下一个窗口(GetWindow(GW_HWNDNEXT))
添加WM_SIZE消息响应
if (m_list.GetSafeHwnd())m_list.MoveWindow(0, 0, cx, cy);
CPage2
通过类向导添加OnInitDialog()
枚举进程要在CPage2类中加上头文件#include <tlhelp32.h>
BOOL CPage2::OnInitDialog()
{CDialogEx::OnInitDialog();m_list.ModifyStyle(0,LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_VSCROLL | WS_BORDER);m_list.InsertColumn(0, L"进程名", LVCFMT_LEFT, 300);m_list.InsertColumn(1, L"进程ID", LVCFMT_LEFT, 100);//枚举进程//获取当前进程的快照HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);PROCESSENTRY32 pe = { 0 };pe.dwSize = sizeof(pe);//获取快照中的第一个进程bool b=Process32First(hSnapshot, &pe);int i = 0;while (b){m_list.InsertItem(i, pe.szExeFile);DWORD id=pe.th32ProcessID;CString str;str.Format(L"%d", id);m_list.SetItemText(i, 1, str);//获取快照中的下一个进程b = Process32Next(hSnapshot, &pe);i++;}return TRUE; // return TRUE unless you set the focus to a control}
枚举进程的流程,获取系统快照-》获取快照中第一个进程-》循环获取下一个进程
添加WM_SIZE消息响应
void CPage2::OnSize(UINT nType, int cx, int cy)
{CDialogEx::OnSize(nType, cx, cy);if (m_list.GetSafeHwnd()){m_list.MoveWindow(0, 0, cx, cy);}
}
运行效果