创建一个基于对话框的MFC项目,给主对话框添加一个tab控件(设置关联变量 类型:CTabCtrl 名称:m_tab),添加两个子对话框(IDC_PAGE1和IDC_PAGE2),给子对话框添加一个list control控件(设置关联变量 类型:CListCtrl 名称:m_list),并将子对话框的边框属性设置为None,窗口样式设为child
在资源视图界面右击对话框给IDC_PAGE1和IDC_PAGE2添加对话框类,类名分别为CPage1,CPage2。
在C任务管理器Dlg类中添加CPage1和CPage2类型的变量page1和page2。
要通过这两成员来创建子窗口。不要忘记在pch.h中包含"CPage1.h","CPage2.h"头文件。
这个时候运行程序,结果如下
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消息的响应函数
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);
}
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))
if (m_list.GetSafeHwnd())
m_list.MoveWindow(0, 0, cx, cy);
枚举进程要在CPage2类中加上头文件#include
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
}
枚举进程的流程,获取系统快照-》获取快照中第一个进程-》循环获取下一个进程
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);
}
}
运行效果