Win32控件-------Tab控件基本架构

窗口的子类化-------------------SetWindowsLongPtr(),GetWindowLongPtr()

窗口的超类化-------------------SetClassLongPtr(),GetClassLongPtr()

所谓子类化,通过同一个WNDCLASS创建窗口,这个WNDCLASS集中了一类窗口的共同特征(如背景,外观等),在CreateWindows过后,通过SetWindowLongPtr()更改响应的窗口处理函数,实现各自的功能。

顺便说一句:SetWindowLongPtr()函数可以兼容32位和64位模式,而SetWindowLong()只能是32位模式

以下是实现了一个Tab和Page,程序的结构:

WndProc()------>

InitTabControl()------->

InitPage()

RegisterWndClass()---------注册窗口类,该函数只调用一次

addPage()-----------------------每添加一个Tab页面,调用一次

InsertTabItem()-----添加标签

CreatePageWnd()---创建窗口。




#define UNICODE
#define _UNICODE
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
//控件库以及相关宏
#include <windowsx.h>//有HANDLE_MSG宏+标准控件功能函数宏
#include <commctrl.h>//高级控件函数宏
#include<stdio.h>
#include<tchar.h>
//依赖库
#pragma comment (lib,"user32.lib")
#pragma comment(lib, "comctl32.lib")
#pragma comment (lib,"gdi32.lib")
#pragma comment (lib,"gdiplus.lib")

#pragma comment (lib,"kernel32.lib")

/*全局变量区*/
HINSTANCE hInst;
HWND Page[100];
//资源区#pragma region Page1
#pragma region Page

LRESULT CALLBACK Page2Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC          hdc;
	PAINTSTRUCT  ps;
	switch (message)
	{
	case WM_PAINT:
	{
		hdc = BeginPaint(hWnd, &ps);
		//代码位置/
		Graphics graphics(hdc);
		graphics.SetSmoothingMode(SmoothingModeAntiAlias);//反锯齿设置
		Pen      pen(Color(255, 255, 0, 255));
		graphics.DrawLine(&pen, 100, 200, 200, 100);
		//graphics.DrawRectangle(&pen, 100, 100, 200, 200);
		
		EndPaint(hWnd, &ps);
	}
	return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
}LRESULT CALLBACK Page1Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC          hdc;
	PAINTSTRUCT  ps;
	switch (message)
	{
	case WM_PAINT:
	{
		hdc = BeginPaint(hWnd, &ps);
		//代码位置/
		Graphics graphics(hdc);
		graphics.SetSmoothingMode(SmoothingModeAntiAlias);//反锯齿设置
		Pen blackPen(Color(255, 0, 0, 0), 3);
		RectF rect1(10.0f, 10.0f, 100.0f, 50.0f);
		RectF rect2(40.0f, 40.0f, 100.0f, 50.0f);
		RectF rect3(80.0f, 4.0f, 50.0f, 100.0f);
		RectF rects[] = { rect1, rect2, rect3 };
		RectF* pRects = rects;
		graphics.DrawRectangles(&blackPen, pRects, 3);
		
		EndPaint(hWnd, &ps);
	}
	return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
}
//功能:向Tab中添加标签
int InsertTabItem(HWND hTab, LPTSTR pszText, int iid)
{
	TCITEM ti = { 0 };
	ti.mask = TCIF_TEXT;
	ti.pszText = pszText;
	ti.cchTextMax = wcslen(pszText);
	return (int)SendMessage(hTab, TCM_INSERTITEM, iid, (LPARAM)&ti);
}
//Page自己的窗口类,通过SetWindowLongPtr()可以子类化
ATOM RegisterPageClass()
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInst;
	wcex.hIcon = NULL;
	wcex.hIconSm = NULL;
	wcex.lpszMenuName = NULL;
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcex.lpszClassName = TEXT("Page");
	wcex.lpfnWndProc = DefWindowProc;
	return RegisterClassEx(&wcex);
}
HWND CreatePageWnd(HWND hTab, WNDPROC PageWndProc)
{
	RECT rcTabDisplay;
	//获取Tab控件客户区的的大小(Tab窗口坐标系)
	GetClientRect(hTab, &rcTabDisplay);//获取Tab窗口的大小(而不是在屏幕坐标系中)
	TabCtrl_AdjustRect(hTab, FALSE, &rcTabDisplay);//通过窗口大小,获取客户区大小。
	//创建与Tab控件客户区大小的画布
	HWND hPage = CreateWindowEx(
		NULL,		//window extend Style
		TEXT("Page"),   // window class name
		NULL,  // window caption
		WS_CHILD,      // window style
		rcTabDisplay.left,            // initial x position
		rcTabDisplay.top,            // initial y position
		rcTabDisplay.right,            // initial x size
		rcTabDisplay.bottom,            // initial y size
		hTab,                     // parent window handle
		NULL,                     // window menu handle
		hInst,                // program instance handle
		NULL);                    // creation parameters
	SetWindowLongPtr(hPage, GWLP_WNDPROC, (LONG_PTR)PageWndProc);//子类化窗口
	return hPage;
}
/*
	功能:向Tab中添加页面
	实现原理:一个窗口多个窗口处理函数,每个窗口处理函数负责一个页面的布局和处理
	注意:该添加方式是顺序添加,即AddAfter,在当前页面后添加
*/
BOOL addPage(HWND hTab, LPTSTR strPageLabel, WNDPROC PageWndProc)
{

	static int iPageIndex = 0;
	InsertTabItem(hTab, strPageLabel, iPageIndex);
	HWND hPage = CreatePageWnd(hTab, PageWndProc);
	Page[iPageIndex++] = hPage;
	return TRUE;
}

/*功能:初始化所有页面*/
BOOL InitPages(HWND hTab)
{
	RegisterPageClass();
	addPage(hTab, TEXT("Page1"), Page1Proc);
	addPage(hTab, TEXT("Page2"), Page2Proc);
	addPage(hTab, TEXT("Page3"), Page2Proc);
	return TRUE;
}
#pragma endregion
#pragma region TabControl
HWND InitTabControl(HWND hParentWnd, HWND hWndFocus, LPARAM lParam)
{
	INITCOMMONCONTROLSEX iccx;
	iccx.dwSize = sizeof(INITCOMMONCONTROLSEX);
	iccx.dwICC = ICC_TAB_CLASSES;
	if (!InitCommonControlsEx(&iccx))
		return FALSE;
	// 创建TabControl控件,其实就是一个子窗口和该窗口上的标签,这些标签是Tab控件具有的,但没有与具体的页面相连,只是Tab控件的特有属性而已。
	//创建Tab控件/
	RECT rc;
	GetClientRect(hParentWnd, &rc);
	HWND hTab = CreateWindowEx(0, WC_TABCONTROL, 0,
		TCS_FIXEDWIDTH | WS_CHILD | WS_VISIBLE,
		rc.left + 2, rc.top + 2, rc.right - 4, rc.bottom - 4,
		hParentWnd, NULL, hInst, 0);

	// Set the font of the tabs to a more typical system GUI font
	SendMessage(hTab, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
	//根据页面来初始化页面
	InitPages(hTab);
	ShowWindow(Page[0], SW_SHOW);//显示第一个页面
	return hTab;
}

//三种窗口状态:SIZE_MINIMIZE,SIZE_MAXIMIZE,SIZE_RESTORED
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND hTab;

	switch (message)
	{
	case WM_CREATE:
		hTab = InitTabControl(hWnd, NULL, lParam);//主窗口创建的时候,同时创建Tab子窗口
		break;
	case WM_SIZE://改变完成之后
		HIWORD(lParam); //客户区Height
		LOWORD(lParam);//Width
		RECT rcTab;
		// 缩放Tab
		//HIWORD(lParam)-----hWnd height,LOWORD(lParam)-----hWnd width
		MoveWindow(hTab, 0, 0, LOWORD(lParam),HIWORD(lParam), TRUE);
		//缩放Page
		GetClientRect(hTab, &rcTab);
		TabCtrl_AdjustRect(hTab, FALSE, &rcTab);
		for (int i = 0; i < TabCtrl_GetItemCount(hTab);i++)
			MoveWindow(Page[i], rcTab.left, rcTab.top, rcTab.right, rcTab.bottom, TRUE);	
		break;
	case WM_NOTIFY://WM_NOTIFY消息中,lParam是一个NMHDR结构,code字段是具体通知消息,hwndFrom是发出通知的窗口Handle
		switch (((LPNMHDR)lParam)->code)
		{
			case TCN_SELCHANGING://Tab改变前
			{
				int iPage = TabCtrl_GetCurSel(hTab);
				ShowWindow(Page[iPage], SW_HIDE);
				return FALSE;
			}
			case TCN_SELCHANGE://Tab改变后
			{
				int iPage = TabCtrl_GetCurSel(hTab);
				ShowWindow(Page[iPage], SW_SHOW);
				return TRUE;
			}
		}
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
	HWND                hWnd;
	MSG                 msg;
	WNDCLASS            wndClass;
	GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR           gdiplusToken;
	hInst = hInstance;
	// Initialize GDI+.
	GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = MainWndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = TEXT("GettingStarted");

	RegisterClass(&wndClass);

	hWnd = CreateWindow(
		TEXT("GettingStarted"),   // window class name
		TEXT("Getting Started"),  // window caption
		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,      // window style
		CW_USEDEFAULT,            // initial x position
		CW_USEDEFAULT,            // initial y position
		CW_USEDEFAULT,            // initial x size
		CW_USEDEFAULT,            // initial y size
		NULL,                     // parent window handle
		NULL,                     // window menu handle
		hInstance,                // program instance handle
		NULL);                    // creation parameters
	ShowWindow(hWnd, iCmdShow);
	UpdateWindow(hWnd);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	GdiplusShutdown(gdiplusToken);
	return msg.wParam;
}



  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值