C语言实现的MDI程序带Tab切换
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "comctl32.lib")
// 常量定义
#define IDC_TAB 1001
#define IDC_BUTTON 1002
#define IDM_NEW_WINDOW 40001
#define IDM_CLOSE_WINDOW 40002
#define IDM_CLOSE_ALL 40003
#define IDM_EXIT 40004
#define MAX_CHILD_WINDOWS 50
#define MAX_TITLE_LENGTH 256
// 全局变量
HINSTANCE hInst = NULL;
HWND hwndTab = NULL;
HWND hwndMDIClient = NULL;
HWND childWindows[MAX_CHILD_WINDOWS];
int childWindowCount = 0;
int childCounter = 0;
HFONT hButtonFont = NULL;
// 函数声明
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK MDIChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void CreateMDIChild(HWND hwndParent);
void UpdateTabControl(void);
void OnTabSelectionChanged(void);
int GetTabIndexFromChild(HWND hwndChild);
HWND GetChildFromTabIndex(int index);
void AddChildWindow(HWND hwndChild);
void RemoveChildWindow(HWND hwndChild);
void OnButtonClick(HWND hwndChild);
void UpdateButtonPosition(HWND hwndChild);
// 应用程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
// 初始化公共控件
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
// 注册主窗口类
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
wc.lpszClassName = TEXT("MDIMainWindow");
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, TEXT("主窗口注册失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
// 注册MDI子窗口类
WNDCLASSEX wcChild = {0};
wcChild.cbSize = sizeof(WNDCLASSEX);
wcChild.style = CS_HREDRAW | CS_VREDRAW;
wcChild.lpfnWndProc = MDIChildProc;
wcChild.hInstance = hInstance;
wcChild.hCursor = LoadCursor(NULL, IDC_ARROW);
wcChild.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcChild.lpszClassName = TEXT("MDIChildWindow");
wcChild.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcChild.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcChild)) {
MessageBox(NULL, TEXT("子窗口注册失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
hInst = hInstance;
// 创建主窗口
HWND hwnd = CreateWindowEx(
0,
TEXT("MDIMainWindow"),
TEXT("C语言 MDI程序 - Tab控制子窗口 (带按钮)"),
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL
);
if (!hwnd) {
MessageBox(NULL, TEXT("主窗口创建失败!"), TEXT("错误"), MB_ICONERROR);
return 0;
}
// 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateMDISysAccel(hwndMDIClient, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
// 主窗口过程
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
// 创建菜单
HMENU hMenu = CreateMenu();
HMENU hFileMenu = CreatePopupMenu();
AppendMenu(hFileMenu, MF_STRING, IDM_NEW_WINDOW, TEXT("新建窗口(&N)"));
AppendMenu(hFileMenu, MF_STRING, IDM_CLOSE_WINDOW, TEXT("关闭当前窗口(&C)"));
AppendMenu(hFileMenu, MF_STRING, IDM_CLOSE_ALL, TEXT("关闭所有窗口(&A)"));
AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hFileMenu, MF_STRING, IDM_EXIT, TEXT("退出(&X)"));
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, TEXT("文件(&F)"));
HMENU hWindowMenu = CreatePopupMenu();
AppendMenu(hWindowMenu, MF_STRING, 50001, TEXT("层叠窗口(&C)"));
AppendMenu(hWindowMenu, MF_STRING, 50002, TEXT("平铺窗口(&T)"));
AppendMenu(hWindowMenu, MF_STRING, 50003, TEXT("排列图标(&A)"));
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hWindowMenu, TEXT("窗口(&W)"));
SetMenu(hwnd, hMenu);
// 创建Tab控件
hwndTab = CreateWindowEx(
0, WC_TABCONTROL, TEXT(""),
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_FOCUSNEVER | TCS_TOOLTIPS,
0, 0, 0, 0,
hwnd, (HMENU)IDC_TAB, hInst, NULL
);
// 设置Tab控件字体
HFONT hFont = CreateFont(
16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("微软雅黑")
);
if (hFont) {
SendMessage(hwndTab, WM_SETFONT, (WPARAM)hFont, TRUE);
}
// 创建MDI客户端窗口
CLIENTCREATESTRUCT ccs = {0};
ccs.hWindowMenu = hWindowMenu;
ccs.idFirstChild = 50000;
hwndMDIClient = CreateWindowEx(
WS_EX_CLIENTEDGE,
TEXT("MDICLIENT"), NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
0, 0, 0, 0,
hwnd, NULL, hInst, (LPVOID)&ccs
);
// 创建按钮字体
hButtonFont = CreateFont(
18, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("微软雅黑")
);
// 创建初始子窗口
for (int i = 0; i < 3; i++) {
CreateMDIChild(hwnd);
}
return 0;
}
case WM_SIZE: {
int width = LOWORD(lParam);
int height = HIWORD(lParam);
// 调整Tab控件大小
if (hwndTab) {
MoveWindow(hwndTab, 0, 0, width, 30, TRUE);
}
// 调整MDI客户端窗口大小
if (hwndMDIClient) {
MoveWindow(hwndMDIClient, 0, 30, width, height - 30, TRUE);
}
return 0;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDM_NEW_WINDOW:
CreateMDIChild(hwnd);
break;
case IDM_CLOSE_WINDOW: {
HWND hwndActiveChild = (HWND)SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (hwndActiveChild) {
SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)hwndActiveChild, 0);
}
break;
}
case IDM_CLOSE_ALL:
while (childWindowCount > 0) {
HWND hwndChild = childWindows[childWindowCount - 1];
SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0);
}
break;
case IDM_EXIT:
DestroyWindow(hwnd);
break;
// 窗口排列命令
case 50001: // 层叠窗口
SendMessage(hwndMDIClient, WM_MDICASCADE, 0, 0);
break;
case 50002: // 平铺窗口
SendMessage(hwndMDIClient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
break;
case 50003: // 排列图标
SendMessage(hwndMDIClient, WM_MDIICONARRANGE, 0, 0);
break;
}
return 0;
}
case WM_NOTIFY: {
LPNMHDR lpnmh = (LPNMHDR)lParam;
if (lpnmh->idFrom == IDC_TAB) {
if (lpnmh->code == TCN_SELCHANGE) {
OnTabSelectionChanged();
}
}
return 0;
}
case WM_DESTROY:
if (hButtonFont) {
DeleteObject(hButtonFont);
}
PostQuitMessage(0);
return 0;
}
return DefFrameProc(hwnd, hwndMDIClient, msg, wParam, lParam);
}
// MDI子窗口过程
LRESULT CALLBACK MDIChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static TCHAR szTitle[MAX_TITLE_LENGTH];
static HWND hwndButton = NULL;
switch (msg) {
case WM_CREATE: {
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
lstrcpyn(szTitle, (LPCTSTR)lpcs->lpszName, MAX_TITLE_LENGTH);
// 添加到子窗口数组
AddChildWindow(hwnd);
UpdateTabControl();
return 0;
}
case WM_MDIACTIVATE: {
if (lParam == (LPARAM)hwnd) {
// 窗口被激活,更新Tab选择
int index = GetTabIndexFromChild(hwnd);
if (index != -1 && hwndTab) {
TabCtrl_SetCurSel(hwndTab, index);
}
}
return 0;
}
case WM_SIZE: {
UpdateButtonPosition(hwnd);
return 0;
}
case WM_COMMAND: {
if (LOWORD(wParam) == IDC_BUTTON) {
OnButtonClick(hwnd);
}
return 0;
}
case WM_DESTROY: {
// 从子窗口数组中移除
RemoveChildWindow(hwnd);
// 更新Tab控件
UpdateTabControl();
return 0;
}
}
return DefMDIChildProc(hwnd, msg, wParam, lParam);
}
// 创建MDI子窗口
void CreateMDIChild(HWND hwndParent) {
if (childWindowCount >= MAX_CHILD_WINDOWS) {
MessageBox(NULL, TEXT("已达到最大子窗口数量限制!"), TEXT("警告"), MB_ICONWARNING);
return;
}
childCounter++;
TCHAR szTitle[100];
wsprintf(szTitle, TEXT("子窗口 %d"), childCounter);
MDICREATESTRUCT mcs = {0};
mcs.szTitle = szTitle;
mcs.szClass = TEXT("MDIChildWindow");
mcs.hOwner = hInst;
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
SendMessage(hwndMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs);
}
// 更新Tab控件
void UpdateTabControl(void) {
if (!hwndTab) return;
// 清除所有Tab项
TabCtrl_DeleteAllItems(hwndTab);
// 添加所有子窗口到Tab控件
TCITEM tie = {0};
tie.mask = TCIF_TEXT;
for (int i = 0; i < childWindowCount; i++) {
TCHAR szTitle[MAX_TITLE_LENGTH];
GetWindowText(childWindows[i], szTitle, MAX_TITLE_LENGTH);
tie.pszText = szTitle;
TabCtrl_InsertItem(hwndTab, i, &tie);
}
// 如果有活动的子窗口,设置对应的Tab项为选中状态
HWND hwndActiveChild = (HWND)SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (hwndActiveChild) {
int index = GetTabIndexFromChild(hwndActiveChild);
if (index != -1) {
TabCtrl_SetCurSel(hwndTab, index);
}
}
}
// Tab选择改变时的处理
void OnTabSelectionChanged(void) {
if (!hwndTab) return;
int selected = TabCtrl_GetCurSel(hwndTab);
if (selected != -1) {
HWND hwndChild = GetChildFromTabIndex(selected);
if (hwndChild) {
// 激活选中的子窗口
SendMessage(hwndMDIClient, WM_MDIACTIVATE, (WPARAM)hwndChild, 0);
}
}
}
// 通过子窗口句柄获取Tab索引
int GetTabIndexFromChild(HWND hwndChild) {
for (int i = 0; i < childWindowCount; i++) {
if (childWindows[i] == hwndChild) {
return i;
}
}
return -1;
}
// 通过Tab索引获取子窗口句柄
HWND GetChildFromTabIndex(int index) {
if (index >= 0 && index < childWindowCount) {
return childWindows[index];
}
return NULL;
}
// 添加子窗口到数组
void AddChildWindow(HWND hwndChild) {
if (childWindowCount < MAX_CHILD_WINDOWS) {
childWindows[childWindowCount++] = hwndChild;
}
}
// 从数组中移除子窗口
void RemoveChildWindow(HWND hwndChild) {
int index = -1;
// 查找窗口在数组中的位置
for (int i = 0; i < childWindowCount; i++) {
if (childWindows[i] == hwndChild) {
index = i;
break;
}
}
if (index != -1) {
// 将后面的元素向前移动
for (int i = index; i < childWindowCount - 1; i++) {
childWindows[i] = childWindows[i + 1];
}
childWindowCount--;
}
}
// 按钮点击事件处理函数
void OnButtonClick(HWND hwndChild) {
TCHAR szTitle[MAX_TITLE_LENGTH];
TCHAR szMessage[512];
int childIndex = GetTabIndexFromChild(hwndChild) + 1;
// 获取窗口标题
GetWindowText(hwndChild, szTitle, MAX_TITLE_LENGTH);
// 创建消息
wsprintf(szMessage,
TEXT("您点击了子窗口的按钮!\n\n")
TEXT("窗口标题: %s\n")
TEXT("窗口编号: %d\n")
TEXT("总窗口数: %d\n")
TEXT("窗口句柄: 0x%p"),
szTitle, childIndex, childWindowCount, hwndChild
);
// 显示消息框
MessageBox(hwndChild, szMessage, TEXT("按钮点击事件"), MB_OK | MB_ICONINFORMATION);
}
// 更新按钮位置(在子窗口大小改变时调用)
void UpdateButtonPosition(HWND hwndChild) {
RECT rcClient;
GetClientRect(hwndChild, &rcClient);
// 获取或创建静态文本控件
HWND hwndStatic = GetDlgItem(hwndChild, 1000);
if (!hwndStatic) {
TCHAR szTitle[MAX_TITLE_LENGTH];
GetWindowText(hwndChild, szTitle, MAX_TITLE_LENGTH);
// 创建静态文本
hwndStatic = CreateWindow(
TEXT("STATIC"), szTitle,
WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
10, 10, rcClient.right - 20, 100,
hwndChild, (HMENU)1000, hInst, NULL
);
// 设置字体
HFONT hFont = CreateFont(
24, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("微软雅黑")
);
if (hFont) {
SendMessage(hwndStatic, WM_SETFONT, (WPARAM)hFont, TRUE);
}
} else {
MoveWindow(hwndStatic, 10, 10, rcClient.right - 20, 100, TRUE);
}
// 获取或创建按钮
HWND hwndButton = GetDlgItem(hwndChild, IDC_BUTTON);
if (!hwndButton) {
// 创建按钮
hwndButton = CreateWindow(
TEXT("BUTTON"), TEXT("点击我!"),
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP,
0, 0, 0, 0,
hwndChild, (HMENU)IDC_BUTTON, hInst, NULL
);
// 设置按钮字体
if (hButtonFont) {
SendMessage(hwndButton, WM_SETFONT, (WPARAM)hButtonFont, TRUE);
}
}
// 计算按钮位置(在静态文本下方)
int buttonWidth = 200;
int buttonHeight = 50;
int buttonX = (rcClient.right - buttonWidth) / 2;
int buttonY = 120; // 在静态文本下方
MoveWindow(hwndButton, buttonX, buttonY, buttonWidth, buttonHeight, TRUE);
}
c++
MDI程序带Tab切换
cpp
#include <windows.h>
#include <commctrl.h>
#include <vector>
#include <string>
#pragma comment(lib, "comctl32.lib")
// 常量定义
#define IDC_TAB 1001
#define IDM_NEW_WINDOW 40001
#define IDM_CLOSE_WINDOW 40002
#define IDM_CLOSE_ALL 40003
#define IDM_EXIT 40004
// 全局变量
HINSTANCE hInst;
HWND hwndTab = NULL;
HWND hwndMDIClient = NULL;
std::vector<HWND> childWindows;
int childCounter = 0;
// 函数声明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MDIChildProc(HWND, UINT, WPARAM, LPARAM);
void CreateMDIChild(HWND hwndParent);
void UpdateTabControl();
void OnTabSelectionChanged();
int GetTabIndexFromChild(HWND hwndChild);
HWND GetChildFromTabIndex(int index);
// 应用程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
// 初始化公共控件
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&icex);
// 注册主窗口类
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
wc.lpszClassName = L"MDIMainWindow";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc)) {
MessageBox(NULL, L"主窗口注册失败!", L"错误", MB_ICONERROR);
return 0;
}
// 注册MDI子窗口类
WNDCLASSEX wcChild = {};
wcChild.cbSize = sizeof(WNDCLASSEX);
wcChild.style = CS_HREDRAW | CS_VREDRAW;
wcChild.lpfnWndProc = MDIChildProc;
wcChild.hInstance = hInstance;
wcChild.hCursor = LoadCursor(NULL, IDC_ARROW);
wcChild.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcChild.lpszClassName = L"MDIChildWindow";
wcChild.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcChild.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcChild)) {
MessageBox(NULL, L"子窗口注册失败!", L"错误", MB_ICONERROR);
return 0;
}
hInst = hInstance;
// 创建主窗口
HWND hwnd = CreateWindowEx(
0,
L"MDIMainWindow",
L"MDI程序 - Tab控制子窗口",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL
);
if (!hwnd) {
MessageBox(NULL, L"主窗口创建失败!", L"错误", MB_ICONERROR);
return 0;
}
// 显示窗口
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateMDISysAccel(hwndMDIClient, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
// 主窗口过程
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
// 创建菜单
HMENU hMenu = CreateMenu();
HMENU hFileMenu = CreatePopupMenu();
AppendMenu(hFileMenu, MF_STRING, IDM_NEW_WINDOW, L"新建窗口(&N)");
AppendMenu(hFileMenu, MF_STRING, IDM_CLOSE_WINDOW, L"关闭当前窗口(&C)");
AppendMenu(hFileMenu, MF_STRING, IDM_CLOSE_ALL, L"关闭所有窗口(&A)");
AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hFileMenu, MF_STRING, IDM_EXIT, L"退出(&X)");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"文件(&F)");
SetMenu(hwnd, hMenu);
// 创建Tab控件
hwndTab = CreateWindowEx(
0, WC_TABCONTROL, L"",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | TCS_FOCUSNEVER | TCS_FIXEDWIDTH | TCS_TOOLTIPS,
0, 0, 0, 0,
hwnd, (HMENU)IDC_TAB, hInst, NULL
);
// 设置Tab控件字体
HFONT hFont = CreateFont(
16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"微软雅黑"
);
if (hFont) {
SendMessage(hwndTab, WM_SETFONT, (WPARAM)hFont, TRUE);
}
// 创建MDI客户端窗口
CLIENTCREATESTRUCT ccs = {};
ccs.hWindowMenu = NULL;
ccs.idFirstChild = 50000;
hwndMDIClient = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"MDICLIENT", NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
0, 0, 0, 0,
hwnd, NULL, hInst, (LPVOID)&ccs
);
// 创建几个初始子窗口
for (int i = 0; i < 3; i++) {
CreateMDIChild(hwnd);
}
return 0;
}
case WM_SIZE: {
int width = LOWORD(lParam);
int height = HIWORD(lParam);
// 调整Tab控件大小
MoveWindow(hwndTab, 0, 0, width, 30, TRUE);
// 调整MDI客户端窗口大小
MoveWindow(hwndMDIClient, 0, 30, width, height - 30, TRUE);
return 0;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDM_NEW_WINDOW:
CreateMDIChild(hwnd);
break;
case IDM_CLOSE_WINDOW: {
HWND hwndActiveChild = (HWND)SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (hwndActiveChild) {
SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)hwndActiveChild, 0);
}
break;
}
case IDM_CLOSE_ALL:
while (!childWindows.empty()) {
HWND hwndChild = childWindows.back();
SendMessage(hwndMDIClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0);
}
break;
case IDM_EXIT:
DestroyWindow(hwnd);
break;
}
return 0;
}
case WM_NOTIFY: {
LPNMHDR lpnmh = (LPNMHDR)lParam;
if (lpnmh->idFrom == IDC_TAB) {
if (lpnmh->code == TCN_SELCHANGE) {
OnTabSelectionChanged();
}
}
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefFrameProc(hwnd, hwndMDIClient, msg, wParam, lParam);
}
// MDI子窗口过程
LRESULT CALLBACK MDIChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static wchar_t szTitle[256];
switch (msg) {
case WM_CREATE: {
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
lstrcpyn(szTitle, (LPCWSTR)lpcs->lpszName, 256);
// 添加到子窗口列表
childWindows.push_back(hwnd);
UpdateTabControl();
return 0;
}
case WM_MDIACTIVATE: {
if (lParam == (LPARAM)hwnd) {
// 窗口被激活,更新Tab选择
int index = GetTabIndexFromChild(hwnd);
if (index != -1 && hwndTab) {
TabCtrl_SetCurSel(hwndTab, index);
}
}
return 0;
}
case WM_SIZE: {
RECT rcClient;
GetClientRect(hwnd, &rcClient);
// 创建或更新子窗口中的控件
HWND hwndStatic = GetDlgItem(hwnd, 1000);
if (!hwndStatic) {
hwndStatic = CreateWindow(
L"STATIC", szTitle,
WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
10, 10, rcClient.right - 20, rcClient.bottom - 20,
hwnd, (HMENU)1000, hInst, NULL
);
// 设置字体
HFONT hFont = CreateFont(
24, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"微软雅黑"
);
if (hFont) {
SendMessage(hwndStatic, WM_SETFONT, (WPARAM)hFont, TRUE);
}
} else {
MoveWindow(hwndStatic, 10, 10, rcClient.right - 20, rcClient.bottom - 20, TRUE);
}
return 0;
}
case WM_DESTROY: {
// 从子窗口列表中移除
auto it = std::find(childWindows.begin(), childWindows.end(), hwnd);
if (it != childWindows.end()) {
childWindows.erase(it);
}
// 更新Tab控件
UpdateTabControl();
return 0;
}
}
return DefMDIChildProc(hwnd, msg, wParam, lParam);
}
// 创建MDI子窗口
void CreateMDIChild(HWND hwndParent) {
childCounter++;
wchar_t szTitle[100];
wsprintf(szTitle, L"子窗口 %d", childCounter);
MDICREATESTRUCT mcs = {};
mcs.szTitle = szTitle;
mcs.szClass = L"MDIChildWindow";
mcs.hOwner = hInst;
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
SendMessage(hwndMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs);
}
// 更新Tab控件
void UpdateTabControl() {
if (!hwndTab) return;
// 清除所有Tab项
TabCtrl_DeleteAllItems(hwndTab);
// 添加所有子窗口到Tab控件
TCITEM tie = {};
tie.mask = TCIF_TEXT;
for (size_t i = 0; i < childWindows.size(); i++) {
wchar_t szTitle[256];
GetWindowText(childWindows[i], szTitle, 256);
tie.pszText = szTitle;
TabCtrl_InsertItem(hwndTab, i, &tie);
}
// 如果有活动的子窗口,设置对应的Tab项为选中状态
HWND hwndActiveChild = (HWND)SendMessage(hwndMDIClient, WM_MDIGETACTIVE, 0, 0);
if (hwndActiveChild) {
int index = GetTabIndexFromChild(hwndActiveChild);
if (index != -1) {
TabCtrl_SetCurSel(hwndTab, index);
}
}
}
// Tab选择改变时的处理
void OnTabSelectionChanged() {
if (!hwndTab) return;
int selected = TabCtrl_GetCurSel(hwndTab);
if (selected != -1) {
HWND hwndChild = GetChildFromTabIndex(selected);
if (hwndChild) {
// 激活选中的子窗口
SendMessage(hwndMDIClient, WM_MDIACTIVATE, (WPARAM)hwndChild, 0);
}
}
}
// 通过子窗口句柄获取Tab索引
int GetTabIndexFromChild(HWND hwndChild) {
for (size_t i = 0; i < childWindows.size(); i++) {
if (childWindows[i] == hwndChild) {
return (int)i;
}
}
return -1;
}
// 通过Tab索引获取子窗口句柄
HWND GetChildFromTabIndex(int index) {
if (index >= 0 && index < (int)childWindows.size()) {
return childWindows[index];
}
return NULL;
}