一般情况下,我们是用不带边框的对话框来充当Tab Control的每个选项卡的内容的。
例如,主对话框IDD_TABBOX上有一个Tab Control,上面有两个选项卡,第一个选项卡用的是IDD_DIALOG1充当内容,第二个用的则是IDD_DIALOG2。IDD_DIALOG1和IDD_DIALOG2的Border属性设为None,Style属性设为Child,如下三张图所示。
但是用对话框充当选项卡内容会有烦人的深色对话框背景,和选项卡的样式并不搭,看起来也不好看,如下图所示。
其实,要去掉这个深色对话框背景很简单,只需要在每个选项卡的对话框的消息处理函数的WM_INITDIALOG里面加一句EnableThemeDialogTexture(hdlg, ETDT_ENABLETAB);就行了。有多少个选项卡,就加多少句这句话。
使用EnableThemeDialogTexture函数前,需要包含头文件Uxtheme.h和库文件Uxtheme.lib。该函数支持Windows XP系统。
#include <Uxtheme.h>
#pragma comment(lib, "Uxtheme.lib")
注意:使用这个函数后,如果程序处理了Static控件的WM_CTLCOLORSTATIC消息,直接return 0就可以用渐变背景了。不需要返回HBRUSH背景刷,SetTextColor设置的文字颜色就能生效。
运行之后是这样的:
深色的对话框背景就成功去除掉了。话说XP系统的选项卡界面真的挺好看的,是一个渐变色。
【完整C语言代码】
main.c:
/* 参考资料:https://stackoverflow.com/questions/43768291/how-to-get-correct-background-and-control-colors-in-property-pages */
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <WindowsX.h>
#include <CommCtrl.h>
#include <Uxtheme.h>
#include "resource.h"#pragma comment(lib, "comctl32.lib")
#pragma comment(linker, "\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' language='*' publicKeyToken='6595b64144ccf1df'\"")
#pragma comment(lib, "Uxtheme.lib")#define COLOR_BLUE RGB(0, 0, 255)
#define COLOR_RED RGB(255, 0, 0)
#define COLOR_ORANGE RGB(255, 201, 14)
#define COLOR_GREEN RGB(0, 255, 0)COLORREF msg_color = COLOR_RED;
HFONT big_font;
HINSTANCE main_instance;
HWND main_dlg;/* 获取指定选项卡的对话框窗口 */
HWND get_tab_page(int index)
{HWND tabctrl;TCITEM item;tabctrl = GetDlgItem(main_dlg, IDC_TAB1);item.mask = TCIF_PARAM;TabCtrl_GetItem(tabctrl, index, &item);return (HWND)item.lParam;
}/* 修改文本内容和颜色 */
void change_static2_text(const char *str, COLORREF color)
{HWND page;page = get_tab_page(0);msg_color = color;SetDlgItemTextA(page, IDC_STATIC2, str);
}/* 在下拉菜单框中显示串口列表 */
int display_comm_ports(HWND combobox)
{char name[50];char value[50];DWORD index, type, namelen, valuelen;HKEY key;LSTATUS status;ComboBox_ResetContent(combobox);status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_READ, &key);if (status != ERROR_SUCCESS)return -1;index = 0;while (1){namelen = sizeof(name);valuelen = sizeof(value);status = RegEnumValueA(key, index, name, &namelen, NULL, &type, (LPBYTE)value, &valuelen);if (status != ERROR_SUCCESS)break;SendMessageA(combobox, CB_ADDSTRING, 0, (LPARAM)value);index++;}if (index != 0)ComboBox_SetCurSel(combobox, 0);RegCloseKey(key);return 0;
}/* 选项卡1消息响应函数 */
INT_PTR CALLBACK page1_proc(HWND hdlg, UINT umsg, WPARAM wparam, LPARAM lparam)
{int id;switch (umsg){case WM_COMMAND:id = LOWORD(wparam);switch (id){case IDOK:// 点击“连接”按钮后执行的代码EnableWindow((HWND)lparam, FALSE);SetWindowTextA((HWND)lparam, "已连接");EnableWindow(GetDlgItem(hdlg, IDC_COMBO1), FALSE);EnableWindow(GetDlgItem(hdlg, IDC_RADIO1), FALSE);EnableWindow(GetDlgItem(hdlg, IDC_RADIO2), FALSE);change_static2_text("连接成功", COLOR_GREEN);break;case IDC_CHECK1:if (Button_GetCheck((HWND)lparam))EnableWindow(GetDlgItem(hdlg, IDC_EDIT1), TRUE);elseEnableWindow(GetDlgItem(hdlg, IDC_EDIT1), FALSE);break;case IDC_CHECK2:if (Button_GetCheck((HWND)lparam)){EnableWindow(GetDlgItem(hdlg, IDC_EDIT2), TRUE);EnableWindow(GetDlgItem(hdlg, IDC_SPIN1), TRUE);}else{EnableWindow(GetDlgItem(hdlg, IDC_EDIT2), FALSE);EnableWindow(GetDlgItem(hdlg, IDC_SPIN1), FALSE);}break;}break;case WM_CTLCOLORSTATIC:// 设置文本颜色id = GetDlgCtrlID((HWND)lparam);if (id == IDC_STATIC2)SetTextColor((HDC)wparam, msg_color);break;case WM_INITDIALOG:EnableThemeDialogTexture(hdlg, ETDT_ENABLETAB); // 删除选项卡灰色背景display_comm_ports(GetDlgItem(hdlg, IDC_COMBO1)); // 在下拉菜单框中显示串口列表Button_SetCheck(GetDlgItem(hdlg, IDC_RADIO1), BST_CHECKED); // 选中第一个单选框SendDlgItemMessage(hdlg, IDC_STATIC2, WM_SETFONT, (WPARAM)big_font, TRUE); // 设置文本字体SendDlgItemMessage(hdlg, IDC_SPIN1, UDM_SETRANGE, 0, MAKELPARAM(100, 0)); // 设置数值上下调整框的调整范围SendDlgItemMessage(hdlg, IDC_SPIN1, UDM_SETPOS, 0, 25); // 设置数值上下调整框的当前值为25 (倒数第二个参数没有作用, 一般设置为0)break;}return 0;
}/* 选项卡2消息响应函数 */
INT_PTR CALLBACK page2_proc(HWND hdlg, UINT umsg, WPARAM wparam, LPARAM lparam)
{char name[50];int i;HICON icon;HIMAGELIST imglist;HWND list_wnd;LVITEMA lvi;switch (umsg){case WM_INITDIALOG:EnableThemeDialogTexture(hdlg, ETDT_ENABLETAB); // 删除选项卡灰色背景list_wnd = GetDlgItem(hdlg, IDC_LIST1);ListView_SetExtendedListViewStyle(list_wnd, LVS_EX_DOUBLEBUFFER); // 使用蓝色半透明选择框// 创建图像列表imglist = ImageList_Create(32, 32, ILC_COLOR24, 1, 1);ListView_SetImageList(list_wnd, imglist, LVSIL_NORMAL); // 绑定图像列表(绑定后,关闭窗口时会自动删除图像列表)icon = LoadImage(main_instance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); // 加载图标ImageList_AddIcon(imglist, icon); // 将图标复制到图像列表中(注意是复制,不是绑定)DestroyIcon(icon); // 复制完后要删除刚才加载的图标// 添加显示项目for (i = 0; i < 50; i++){lvi.mask = LVIF_IMAGE | LVIF_TEXT;lvi.iItem = i; // 行号lvi.iSubItem = 0; // 列号_snprintf_s(name, sizeof(name), sizeof(name) - 1, "测试项目%02d", i + 1); // 第三个参数MaxCount是字符数,不包括'\0',所以必须减1lvi.pszText = name; // 名称lvi.iImage = 0; // 使用的图标序号lvi.iItem = (int)SendMessage(list_wnd, LVM_INSERTITEMA, 0, (LPARAM)&lvi); // 返回值为排序后的行号 (若启用了自动排序功能的话)}break;}return 0;
}/* 加载字体 */
void create_font()
{LOGFONTA font = {0};font.lfCharSet = DEFAULT_CHARSET;strcpy_s(font.lfFaceName, sizeof(font.lfFaceName), "Times New Roman");font.lfHeight = 24;font.lfWeight = FW_BOLD;big_font = CreateFontIndirectA(&font);
}/* 删除字体 */
void delete_font()
{DeleteObject(big_font);
}/* 初始化选项卡控件 */
void init_tabs()
{char *titles[2] = {"第一个选项卡", "第二个选项卡"};int pages[2] = {IDD_DIALOG1, IDD_DIALOG2};DLGPROC procs[2] = {page1_proc, page2_proc};int i;HWND tabctrl, page;RECT rect;TCITEMA item;UINT flags;tabctrl = GetDlgItem(main_dlg, IDC_TAB1);for (i = 0; i < _countof(pages); i++){item.mask = TCIF_TEXT;item.pszText = titles[i];SendMessage(tabctrl, TCM_INSERTITEMA, i, (LPARAM)&item);}GetClientRect(tabctrl, &rect);TabCtrl_AdjustRect(tabctrl, FALSE, &rect);for (i = 0; i < _countof(pages); i++){page = CreateDialog(main_instance, MAKEINTRESOURCE(pages[i]), tabctrl, procs[i]);flags = (i == 0) ? SWP_SHOWWINDOW : 0;SetWindowPos(page, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags);item.mask = TCIF_PARAM;item.lParam = (LPARAM)page;TabCtrl_SetItem(tabctrl, i, &item);}
}/* 切换选项卡 */
void switch_tab()
{int i, n, curr;HWND tabctrl;TCITEM item;tabctrl = GetDlgItem(main_dlg, IDC_TAB1);n = TabCtrl_GetItemCount(tabctrl);curr = TabCtrl_GetCurSel(tabctrl);for (i = 0; i < n; i++){item.mask = TCIF_PARAM;TabCtrl_GetItem(tabctrl, i, &item);if (i == curr)ShowWindow((HWND)item.lParam, SW_SHOW);elseShowWindow((HWND)item.lParam, SW_HIDE);}
}/* 主对话框(仅包含选项卡控件)消息响应函数 */
INT_PTR CALLBACK tabbox_proc(HWND hdlg, UINT umsg, WPARAM wparam, LPARAM lparam)
{int id;LPNMHDR lpnmhdr;switch (umsg){case WM_COMMAND:id = LOWORD(wparam);switch (id){case IDCANCEL:EndDialog(hdlg, 0);main_dlg = NULL;delete_font();break;}break;case WM_INITDIALOG:main_dlg = hdlg;lparam = (LPARAM)LoadImage(main_instance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);SendMessage(hdlg, WM_SETICON, ICON_BIG, lparam);lparam = (LPARAM)LoadImage(main_instance, MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);SendMessage(hdlg, WM_SETICON, ICON_SMALL, lparam);create_font();init_tabs();break;case WM_NOTIFY:lpnmhdr = (LPNMHDR)lparam;switch (lpnmhdr->code){case TCN_SELCHANGE:switch_tab();break;}break;}return 0;
}/* 主函数 */
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{LRESULT ret;main_instance = hInstance;InitCommonControls();ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_TABBOX), NULL, tabbox_proc);return (int)ret;
}
resource.h:
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by remove_tab_page_background.rc
//
#define IDI_ICON1 101
#define IDD_DIALOG1 102
#define IDD_DIALOG2 103
#define IDD_TABBOX 104
#define IDC_COMBO1 1001
#define IDC_RADIO1 1002
#define IDC_RADIO2 1003
#define IDC_STATIC2 1004
#define IDC_CHECK1 1005
#define IDC_EDIT1 1006
#define IDC_CHECK2 1007
#define IDC_EDIT2 1008
#define IDC_SPIN1 1009
#define IDC_LIST1 1010
#define IDC_TAB1 1011// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1012
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
remove_tab_page_background.rc:
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"/
#undef APSTUDIO_READONLY_SYMBOLS/
// 中文(简体,中国) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//1 TEXTINCLUDE
BEGIN"resource.h\0"
END2 TEXTINCLUDE
BEGIN"#include ""afxres.h""\r\n""\0"
END3 TEXTINCLUDE
BEGIN"\r\n""\0"
END#endif // APSTUDIO_INVOKED/
//
// Icon
//// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "icon1.ico"/
//
// Dialog
//IDD_DIALOG1 DIALOGEX 0, 0, 354, 138
STYLE DS_SETFONT | WS_CHILD | WS_SYSMENU
FONT 9, "新宋体", 400, 0, 0x0
BEGINLTEXT "串口号: ",IDC_STATIC,14,18,33,8COMBOBOX IDC_COMBO1,52,15,81,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOPDEFPUSHBUTTON "连接",IDOK,137,15,50,14CTEXT "未连接串口",IDC_STATIC2,197,14,139,37,SS_CENTERIMAGE | SS_SUNKENCONTROL "模式1",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,52,39,36,10CONTROL "模式2",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,105,39,36,10CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,63,340,1CONTROL "电池电压",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,115,81,48,10EDITTEXT IDC_EDIT1,170,79,67,14,ES_AUTOHSCROLL | WS_DISABLEDLTEXT "V",IDC_STATIC,242,82,8,8CONTROL "温度",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,115,105,32,10EDITTEXT IDC_EDIT2,170,103,40,14,ES_AUTOHSCROLL | WS_DISABLEDCONTROL "",IDC_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | WS_DISABLED,263,103,11,14LTEXT "℃",IDC_STATIC,214,106,15,8
ENDIDD_DIALOG2 DIALOGEX 0, 0, 354, 138
STYLE DS_SETFONT | WS_CHILD | WS_SYSMENU
FONT 9, "新宋体", 400, 0, 0x0
BEGINCONTROL "",IDC_LIST1,"SysListView32",WS_BORDER | WS_TABSTOP,7,7,338,121
ENDIDD_TABBOX DIALOGEX 0, 0, 374, 166
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "移除选项卡灰色背景"
FONT 9, "新宋体", 400, 0, 0x0
BEGINCONTROL "",IDC_TAB1,"SysTabControl32",0x0,7,7,360,152
END/
//
// DESIGNINFO
//#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGINIDD_DIALOG1, DIALOGBEGINLEFTMARGIN, 7RIGHTMARGIN, 347TOPMARGIN, 7ENDIDD_DIALOG2, DIALOGBEGINLEFTMARGIN, 7RIGHTMARGIN, 345TOPMARGIN, 7ENDIDD_TABBOX, DIALOGBEGINLEFTMARGIN, 7RIGHTMARGIN, 309TOPMARGIN, 7END
END
#endif // APSTUDIO_INVOKED#endif // 中文(简体,中国) resources
/#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
///
#endif // not APSTUDIO_INVOKED