好久没有记录博客了,今天记录下简单的win32对应的GDI吧,上次写博客都过了两个月了,一个是那时候快过年,一个是个人在做些东西,博客没有时间去更新,今天简单记录下win32对应东西吧。本文章是基于 win32程序设计(第5版本),详细的可查阅本书。
今天简单了解 TEXTMETRIC 结构体对字体的处理:TEXTMETRIC 结构体有20个栏位,这里只简单的介绍7个。
typedef struct tagTEXTMETRIC
{
LONG tmHeight ;
LONG tmAscent ;
LONG tmDescent ;
LONG tmInternalLeading ;
LONG tmExternalLeading ;
LONG tmAveCharWidth ;
LONG tmMaxCharWidth ;
其他结构栏位
}
TEXTMETRIC, * PTEXTMETRIC ;
对应的变量含义:
程序运行出来会有这样的效果。
首先我们定义一个后头文件,用来写对应数据。
sysmets.h
#pragma once
#include <windows.h>
#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))
struct
{
int Index;
TCHAR * szLabel;
TCHAR * szDesc;
}sysmetrics[] =
{
SM_CXSCREEN, TEXT("SM_CXSCREEN"),
TEXT("Screen width in pixels"),
SM_CYSCREEN, TEXT("SM_CYSCREEN"),
TEXT("Screen height in pixels"),
SM_CXVSCROLL, TEXT("SM_CXVSCROLL"),
TEXT("Vertical scroll width"),
SM_CYHSCROLL, TEXT("SM_CYHSCROLL"),
TEXT("Horizontal scroll height"),
SM_CYCAPTION, TEXT("SM_CYCAPTION"),
TEXT("Caption bar height"),
SM_CXBORDER, TEXT("SM_CXBORDER"),
TEXT("Window border width"),
SM_CYBORDER, TEXT("SM_CYBORDER"),
TEXT("Window border height"),
SM_CXFIXEDFRAME,TEXT("SM_CXFIXEDFRAME"),
TEXT("Dialog window frame width"),
SM_CYFIXEDFRAME,TEXT("SM_CYFIXEDFRAME"),
TEXT("Dialog window frame height"),
SM_CYVTHUMB, TEXT("SM_CYVTHUMB"),
TEXT("Vertical scroll thumb height"),
SM_CXHTHUMB, TEXT("SM_CXHTHUMB"),
TEXT("Horizontal scroll thumb width"),
SM_CXICON, TEXT("SM_CXICON"),
TEXT("Icon width"),
SM_CYICON, TEXT("SM_CYICON"),
TEXT("Icon height"),
SM_CXCURSOR, TEXT("SM_CXCURSOR"),
TEXT("Cursor width"),
SM_CYCURSOR, TEXT("SM_CYCURSOR"),
TEXT("Cursor height"),
SM_CYMENU, TEXT("SM_CYMENU"),
TEXT("Menu bar height"),
SM_CXFULLSCREEN,TEXT("SM_CXFULLSCREEN"),
TEXT("Full screen client area width"),
SM_CYFULLSCREEN,TEXT("SM_CYFULLSCREEN"),
TEXT("Full screen client area height"),
SM_CYKANJIWINDOW,TEXT("SM_CYKANJIWINDOW"),
TEXT("Kanji window height"),
SM_MOUSEPRESENT, TEXT("SM_MOUSEPRESENT"),
TEXT("Mouse present flag"),
SM_CYVSCROLL, TEXT("SM_CYVSCROLL"),
TEXT("Vertical scroll arrow height"),
SM_CXHSCROLL, TEXT("SM_CXHSCROLL"),
TEXT("Horizontal scroll arrow width"),
SM_DEBUG, TEXT("SM_DEBUG"),
TEXT("Debug version flag"),
SM_SWAPBUTTON, TEXT("SM_SWAPBUTTON"),
TEXT("Mouse buttons swapped flag"),
SM_CXMIN, TEXT("SM_CXMIN"),
TEXT("Minimum window width"),
SM_CYMIN, TEXT("SM_CYMIN"),
TEXT("Minimum window height"),
SM_CXSIZE, TEXT("SM_CXSIZE"),
TEXT("Min/Max/Close button width"),
SM_CYSIZE, TEXT("SM_CYSIZE"),
TEXT("Min/Max/Close button height"),
SM_CXSIZEFRAME, TEXT("SM_CXSIZEFRAME"),
TEXT("Window sizing frame width"),
SM_CYSIZEFRAME, TEXT("SM_CYSIZEFRAME"),
TEXT("Window sizing frame height"),
SM_CXMINTRACK, TEXT("SM_CXMINTRACK"),
TEXT("Minimum window tracking width"),
SM_CYMINTRACK, TEXT("SM_CYMINTRACK"),
TEXT("Minimum window tracking height"),
SM_CXDOUBLECLK, TEXT("SM_CXDOUBLECLK"),
TEXT("Double click x tolerance"),
SM_CYDOUBLECLK, TEXT("SM_CYDOUBLECLK"),
TEXT("Double click y tolerance"),
SM_CXICONSPACING,TEXT("SM_CXICONSPACING"),
TEXT("Horizontal icon spacing"),
SM_CYICONSPACING,TEXT("SM_CYICONSPACING"),
TEXT("Vertical icon spacing"),
SM_MENUDROPALIGNMENT, TEXT("SM_MENUDROPALIGNMENT"),
TEXT("Left or right menu drop"),
SM_PENWINDOWS, TEXT("SM_PENWINDOWS"),
TEXT("Pen extensions installed"),
SM_DBCSENABLED, TEXT("SM_DBCSENABLED"),
TEXT("Double-Byte Char Set enabled"),
SM_CMOUSEBUTTONS, TEXT("SM_CMOUSEBUTTONS"),
TEXT("Number of mouse buttons"),
SM_SECURE, TEXT("SM_SECURE"),
TEXT("Security present flag"),
SM_CXEDGE, TEXT("SM_CXEDGE"),
TEXT("3-D border width"),
SM_CYEDGE, TEXT("SM_CYEDGE"),
TEXT("3-D border height"),
SM_CXMINSPACING, TEXT("SM_CXMINSPACING"),
TEXT("Minimized window spacing width"),
SM_CYMINSPACING, TEXT("SM_CYMINSPACING"),
TEXT("Minimized window spacing height"),
SM_CXSMICON, TEXT("SM_CXSMICON"),
TEXT("Small icon width"),
SM_CYSMICON, TEXT("SM_CYSMICON"),
TEXT("Small icon height"),
SM_CYSMCAPTION, TEXT("SM_CYSMCAPTION"),
TEXT("Small caption height"),
SM_CXSMSIZE, TEXT("SM_CXSMSIZE"),
TEXT("Small caption button width"),
SM_CYSMSIZE, TEXT("SM_CYSMSIZE"),
TEXT("Small caption button height"),
SM_CXMENUSIZE, TEXT("SM_CXMENUSIZE"),
TEXT("Menu bar button width"),
SM_CYMENUSIZE, TEXT("SM_CYMENUSIZE"),
TEXT("Menu bar button height"),
SM_ARRANGE, TEXT("SM_ARRANGE"),
TEXT("How minimized windows arranged"),
SM_CXMINIMIZED, TEXT("SM_CXMINIMIZED"),
TEXT("Minimized window width"),
SM_CYMINIMIZED, TEXT("SM_CYMINIMIZED"),
TEXT("Minimized window height"),
SM_CXMAXTRACK, TEXT("SM_CXMAXTRACK"),
TEXT("Maximum draggable width"),
SM_CYMAXTRACK, TEXT("SM_CYMAXTRACK"),
TEXT("Maximum draggable height"),
SM_CXMAXIMIZED, TEXT("SM_CXMAXIMIZED"),
TEXT("Width of maximized window"),
SM_CYMAXIMIZED, TEXT("SM_CYMAXIMIZED"),
TEXT("Height of maximized window"),
SM_NETWORK, TEXT("SM_NETWORK"),
TEXT("Network present flag"),
SM_CLEANBOOT, TEXT("SM_CLEANBOOT"),
TEXT("How system was booted"),
SM_CXDRAG, TEXT("SM_CXDRAG"),
TEXT("Avoid drag x tolerance"),
SM_CYDRAG, TEXT("SM_CYDRAG"),
TEXT("Avoid drag y tolerance"),
SM_SHOWSOUNDS, TEXT("SM_SHOWSOUNDS"),
TEXT("Present sounds visually"),
SM_CXMENUCHECK, TEXT("SM_CXMENUCHECK"),
TEXT("Menu check-mark width"),
SM_CYMENUCHECK, TEXT("SM_CYMENUCHECK"),
TEXT("Menu check-mark height"),
SM_SLOWMACHINE, TEXT("SM_SLOWMACHINE"),
TEXT("Slow processor flag"),
SM_MIDEASTENABLED, TEXT("SM_MIDEASTENABLED"),
TEXT("Hebrew and Arabic enabled flag"),
SM_MOUSEWHEELPRESENT, TEXT("SM_MOUSEWHEELPRESENT"),
TEXT("Mouse wheel present flag"),
SM_XVIRTUALSCREEN, TEXT("SM_XVIRTUALSCREEN"),
TEXT("Virtual screen x origin"),
SM_YVIRTUALSCREEN, TEXT("SM_YVIRTUALSCREEN"),
TEXT("Virtual screen y origin"),
SM_CXVIRTUALSCREEN, TEXT("SM_CXVIRTUALSCREEN"),
TEXT("Virtual screen width"),
SM_CYVIRTUALSCREEN, TEXT("SM_CYVIRTUALSCREEN"),
TEXT("Virtual screen height"),
SM_CMONITORS, TEXT("SM_CMONITORS"),
TEXT("Number of monitors"),
SM_SAMEDISPLAYFORMAT, TEXT("SM_SAMEDISPLAYFORMAT"),
TEXT("Same color format flag")
};
然后通过,win32基本代码添加数据。
#include <windows.h>
#include "sysmets.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
static TCHAR szAppName[] = TEXT("SysMets1");
HWND hwnd; //视窗代号
MSG msg; //消息讯息结构
WNDCLASS wndclass; //创建windows类
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
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 = szAppName;
if (!RegisterClass(&wndclass)) //为程式视窗注册视窗类别。
{
MessageBox(NULL,TEXT("This program requires Windows NT!"), //显示讯息方块。
szAppName,MB_ICONERROR);
return 0;
}
//创建windows
//根据视窗类别建立一个视窗。
hwnd = CreateWindow(szAppName, //window class name
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // 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, nShowCmd);// 在萤幕上显示视窗。
UpdateWindow(hwnd); //指示视窗自我更新。
while (GetMessage(&msg,NULL,0,0)) // 从讯息伫列中取得讯息。
{
TranslateMessage(&msg); //转译某些键盘讯息。
DispatchMessage(&msg); //将讯息发送给视窗讯息处理程式
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxChar, cxCaps, cyChar;
HDC hdc; //装置内容代号
int i;
PAINTSTRUCT ps; //绘图结构
TCHAR szBuffer[10];
RECT rect; //矩形结构
TEXTMETRIC tm; //文字结构体
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd); //呼叫 GetDC 取得视窗的装置内容
GetTextMetrics(hdc, &tm); //呼叫 GetTextMetrics 取得内定系统字体的文字大小
cxChar = tm.tmAveCharWidth; //将平均字元宽度保存在 cxChar 中
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) *cxChar / 2;//cxCaps 设定为 cxChar 乘以 150%。
cyChar = tm.tmHeight + tm.tmExternalLeading; //将字元的总高度(包括外部间距)保存在 cyChar 中。
ReleaseDC(hwnd, hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //开始绘制视窗。
//GetClientRect(hwnd, &rect); //取得视窗显示区域的大小。
//DrawText(hdc, TEXT("Hello, Windows !"),-1,
// &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); //显示字串。
for (i = 0; i< NUMLINES; i++)
{
TextOut(hdc,0,cyChar*i,
sysmetrics[i].szLabel,
lstrlen(sysmetrics[i].szLabel));
TextOut(hdc, 22 * cxCaps, cyChar * i,
sysmetrics[i].szDesc,
lstrlen(sysmetrics[i].szDesc));
SetTextAlign(hdc, TA_RIGHT | TA_TOP); //向右对齐
TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer,
wsprintf(szBuffer, TEXT("%5d"),
GetSystemMetrics(sysmetrics[i].Index)));
SetTextAlign(hdc, TA_LEFT | TA_TOP);
}
EndPaint(hwnd, &ps); //结束绘制视窗
return 0;
case WM_DESTROY:
PostQuitMessage(0); //在讯息伫列中插入一个「退出程式」讯息。
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam); //执行内定的讯息处理。
}
cxCaps 等於 cxChar。对於可变宽度字体,cxCaps 设定为 cxChar 乘以 150%。对於可变宽度字体,TEXTMETRIC 结构中的 tmPitchAndFamily 栏位的低位元为 1,对於固定宽度字体,该值为 0。 SYSMETS1 使用这个位元从 cxChar
计算 cxCaps:
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) *cxChar / 2;
然后通过上面的方式就会发现必须要全部打开,而且没有滚动条可以看下面的东西,如果想添加的话,就必须添加一个卷动列。
卷动列:
卷动列既有垂直方向的(供上下移动),也有水平方向的(供左右移动)。
话不多说了,开始添加功能,为了方便,这里只变化回调函数对应的东西。
运行后会出现这个卷动条。
对应改变的代码:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxChar, cxCaps, cyChar, cyClient, iVscrollPos;
HDC hdc; //装置内容代号
int i;
PAINTSTRUCT ps; //绘图结构
TCHAR szBuffer[10];
RECT rect; //矩形结构
TEXTMETRIC tm; //文字结构体
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd); //呼叫 GetDC 取得视窗的装置内容
GetTextMetrics(hdc, &tm); //呼叫 GetTextMetrics 取得内定系统字体的文字大小
cxChar = tm.tmAveCharWidth; //将平均字元宽度保存在 cxChar 中
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) *cxChar / 2;//cxCaps 设定为 cxChar 乘以 150%。
cyChar = tm.tmHeight + tm.tmExternalLeading; //将字元的总高度(包括外部间距)保存在 cyChar 中。
ReleaseDC(hwnd, hdc);
//在这里设置卷列表
//第二个参数 SB_VERT 或者 SB_HORZ,
SetScrollRange(hwnd, SB_VERT, 0, NUMLINES - 1, FALSE);
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
return 0;
case WM_SIZE:
cyClient = HIWORD(lParam);
return 0;
case WM_VSCROLL:
switch (LOWORD(wParam))
{
case SB_LINEUP:
iVscrollPos -= 1;
break;
case SB_LINEDOWN:
iVscrollPos += 1;
break;
case SB_PAGEUP:
iVscrollPos -= cyClient / cyChar;
break;
case SB_PAGEDOWN:
iVscrollPos += cyClient / cyChar;
break;
case SB_THUMBPOSITION:
iVscrollPos = HIWORD(wParam);
break;
default:
break;
}
iVscrollPos = max(0, min(iVscrollPos, NUMLINES - 1));
if (iVscrollPos != GetScrollPos(hwnd, SB_VERT))
{
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); //开始绘制视窗。
//GetClientRect(hwnd, &rect); //取得视窗显示区域的大小。
//DrawText(hdc, TEXT("Hello, Windows !"),-1,
// &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); //显示字串。
for (i = 0; i< NUMLINES; i++)
{
TextOut(hdc,0,cyChar*i,
sysmetrics[i].szLabel,
lstrlen(sysmetrics[i].szLabel));
TextOut(hdc, 22 * cxCaps, cyChar * i,
sysmetrics[i].szDesc,
lstrlen(sysmetrics[i].szDesc));
SetTextAlign(hdc, TA_RIGHT | TA_TOP); //向右对齐
TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i, szBuffer,
wsprintf(szBuffer, TEXT("%5d"),
GetSystemMetrics(sysmetrics[i].Index)));
SetTextAlign(hdc, TA_LEFT | TA_TOP); //向左对齐
}
EndPaint(hwnd, &ps); //结束绘制视窗
return 0;
case WM_DESTROY:
PostQuitMessage(0); //在讯息伫列中插入一个「退出程式」讯息。
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam); //执行内定的讯息处理。
}
然后在CreateWindow 里面第3个参数,变成:
WS_OVERLAPPEDWINDOW | WS_VSCROLL, // window style
这样写出来的代码,会有滚动条出现,但是没有达到理想的状态,毕竟win32方式处理细节是非常多的,不过也是非常有意思的。
详细细节请产考win32程序设计(第5版本)。
好久没有更新博客了,不能荒废,一点一点都会有所收获。