Windows程序设计3——细节内容补充

Windows程序设计3——细节内容补充,第1张

学习视频连接

【SDK开发】《Windows程序设计》_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1us411A7UE?p=9&spm_id_from=pageDriver

《Windows程序设计(SDK)》系列教程对应课后作业|扩展练习|案例解读|扩展阅读|知识点总结 - Powered by Discuz! (fishc.com.cn)https://fishc.com.cn/forum-255-2.html

目录

一、前面章节的难点

1.1 关闭确认

1.2 程序未响应

二、文本输出

2.1 三大核心部件

2.2 设备环境

2.3 TextOut

三、字符串函数的使用

3.1 字符串处理函数

3.2 简单使用循环打印内容

3.3 合并字符串

3.4 缓冲区溢出

四、自适应文本间距

4.1 GetTextMetrics函数

4.2 GetTextMetrics结构

4.3 自适应字体间宽度 


一、前面章节的难点 1.1 关闭确认

1、流程

如果我的程序需要在关闭前让用户判断是否确定要关闭窗口,我应该响应哪个消息呢?

如下图所示

2、错误的写法

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

        switch (message)
        {
        case WM_PAINT:
                hdc = BeginPaint(hwnd, &ps);
                GetClientRect(hwnd, &rect);
                DrawText(hdc, TEXT("大家好,这是我的第一个窗口程序!"), -1, &rect,
                        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
                EndPaint(hwnd, &ps);
                return 0;

		case WM_LBUTTONUP:
				MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
				return 0;

        case WM_DESTROY:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				PostQuitMessage(0);
			}
			else {
                return 0;
			}
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

存在的问题,选择的时候点了否,窗口没有重新打开,并且后台有进程

 

3、正确的写法

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            GetClientRect(hwnd, &rect);
            DrawText(hdc, TEXT("大家好,这是我的第一个窗口程序!"), -1, &rect,
                        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

1.2 程序未响应

如果一个case结束不了,这个程序就未响应了

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            GetClientRect(hwnd, &rect);
            DrawText(hdc, TEXT("大家好,这是我的第一个窗口程序!"), -1, &rect,
                        DT_SINGLELINE | DT_CENTER | DT_VCENTER);
            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			while (1) {}
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

点一下屏幕中间,程序就卡住了

二、文本输出 2.1 三大核心部件

我们所调用的大部分 api 都是封装在三大子系统中的

kernel:内核相关  内存管理、文件输入输出、任务管理

user:用户相关  窗口管理、用户界面、GUI

2.2 设备环境

1、定义

设备环境句柄是应用程序使用 GDI 函数的通行证

2、获取设备环境句柄

方法一:响应 WM_PAINT 消息时候使用

hdc = BeginPaint(hwnd, &ps);  // 使用 GDI 函数

EndPaint(hwnd, &ps);

方法二:

hdc = GetDC(hwnd);  // 使用 GDI 函数

ReleaseDC(hwnd, hdc);

3、前面有使用设备环境句柄绘制文本的代码

2.3 TextOut

1、结构体

BOOL TextOut(
  _In_  HDC hdc,
  _In_  int nXStart,
  _In_  int nYStart,
  _In_  LPCTSTR lpString,
  _In_  int cchString
);

2、参数解析:

参数含义
hdc设备环境句柄
nXStart指定用于字符串对齐的基准点的逻辑 x 坐标(有关基准点请看下边备注)
nYStart指定用于字符串对齐的基准点的逻辑 y 坐标
lpString1. 指向将被绘制字符串的指针
2. 该字符串不必以'\0'结束,因为 cchString 参数指定了该字符串的长度
cchStringlpString 字符串的长度(有多少个字符)



3、返回值:

(1) 如果函数调用成功,返回值为非 0

(2) 如果函数调用失败,返回值为 0
 

4、代码:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			TextOut(hdc, 400, 300, TEXT("I love China"), 12);
            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

 如果字符少于 12,则显示不全;如果字符多余12,则多的部分显示乱码

三、字符串函数的使用 3.1 字符串处理函数

3.2 简单使用循环打印内容
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[128] = TEXT("I love China!");
		int i;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				TextOut(hdc, 0, i * 20, szBuffer, 13);
			}

            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

3.3 合并字符串

1、代码

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[128];
		int i;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				wsprintf(szBuffer, TEXT("%d: %s"), i + 1, TEXT("I love China!"));
				TextOut(hdc, 0, i * 20, szBuffer, 16);
			}

            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

2、出现的问题:

第 10 行少了感叹号

修改方案1

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[128];
		int i;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				wsprintf(szBuffer, TEXT("%3d: %s"), i + 1, TEXT("I love China!"));
				TextOut(hdc, 0, i * 20, szBuffer, 18);
			}

            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

修改方案2

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[128];
		int i;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				wsprintf(szBuffer, TEXT("%d: %s"), i + 1, TEXT("I love China!"));
				TextOut(hdc, 0, i * 20, szBuffer, lstrlen(szBuffer));
			}

            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

3.4 缓冲区溢出

1、缓冲区大小为 12

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[10];
		int i;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				wsprintf(szBuffer, TEXT("%d: %s"), i + 1, TEXT("I love China!"));
				TextOut(hdc, 0, i * 20, szBuffer, lstrlen(szBuffer));
			}

            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

2、没有设置结束点

lstrlen 判断结束点是找到最近的一个 '\0'

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[] = {'A', 'B', 'c', 'D'};
		int i, j;

        switch (message)
        {
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				// wsprintf(szBuffer, TEXT("%d: %s"), i + 1, TEXT("I love China!"));
				j = lstrlen(szBuffer);
				TextOut(hdc, 0, i * 20, szBuffer, j);
			}

            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

四、自适应文本间距 4.1 GetTextMetrics函数

1、作用

函数将当前字体的信息填充到指定缓冲区

2、函数

BOOL GetTextMetrics(
  _In_   HDC hdc,
  _Out_  LPTEXTMETRIC lptm
);

3、参数解析:

参数含义
hdc设备环境句柄
lptm指向 TEXTMETRIC 结构的指针,该结构用于获得字体信息

4、返回值:

1. 如果函数调用成功,返回值是非 0;

2. 如果函数调用失败,返回值是 0。

4.2 GetTextMetrics结构

1、简介

TEXTMETRIC 结构记录当前设备环境中有关字体的各种信息。

TEXTMETRIC 结构成员的值的单位取决于设备环境中当前选定的映射模式,默认的映射模式是 MM_TEXT,所以它们的值是以像素为单位的。

2、结构

typedef struct tagTEXTMETRIC {
  LONG  tmHeight;
  LONG  tmAscent;
  LONG  tmDescent;
  LONG  tmInternalLeading;
  LONG  tmExternalLeading;
  LONG  tmAveCharWidth;
  LONG  tmMaxCharWidth;
  LONG  tmWeight;
  LONG  tmOverhang;
  LONG  tmDigitizedAspectX;
  LONG  tmDigitizedAspectY;
  TCHAR tmFirstChar;
  TCHAR tmLastChar;
  TCHAR tmDefaultChar;
  TCHAR tmBreakChar;
  BYTE  tmItalic;
  BYTE  tmUnderlined;
  BYTE  tmStruckOut;
  BYTE  tmPitchAndFamily;
  BYTE  tmCharSet;
} TEXTMETRIC, *PTEXTMETRIC;

3、成员解析:

成员含义
tmHeight字符高度(tmAscent + tmDescent)
tmAscent字符上部高度(基线以上)
tmDescent字符下部高度(基线以下)
tmInternalLeading内部间距(包含在 tmHeight 中),该间距通常被用于显示重音符号
tmExternalLeading外部间距,这个值是字体设计者建议在两行文字间留出的空间大小
tmAveCharWidth1. 字体中小写字符的平均宽度(一般定义为字母 x 的宽度)
2. 字体中大写字符的平均宽度一般是该值的 1.5 倍计算
3. 此值不包括字体所需要的加粗和倾斜字符
tmMaxCharWidth字体中最宽字符的宽度
tmWeight字体的粗细轻重程度
tmOverhang加入某些拼接字体上的附加高度
tmDigitizedAspectX字体设计所针对的设备水平方向
tmDigitizedAspectY字体设计所针对的设备垂直方向
tmFirstChar为字体定义的第一个字符
tmLastChar为字体定义的最后一个字符
tmDefaultChar字体中所没有字符的替代字符
tmBreakChar定义文本对齐截断 *** 作所显示的字符
tmItalic如果该值非零,则为斜体字体
tmUnderlined如果该值非零,则为带下横线字体
tmStruckOut如果该值非零,则为带删除线字体(字符中间画一条线)
tmPitchAndFamily1. 如果低位为 0,表示等宽字体,小写和大写字母平均宽度一样
2. 如果低位为 1,表示变宽字体,大写字母是小写平均宽度的 3/2 倍
tmCharSet字体的字符集

 

4.3 自适应字体间宽度 
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT rect;

		TCHAR szBuffer[128];
		int i;
		TEXTMETRIC tm;
		static int cxChar, cyChar;

        switch (message)
        {
		case WM_CREATE:
			hdc = GetDC(hwnd);
			GetTextMetrics(hdc, &tm);
			cxChar = tm.tmAveCharWidth;
			cyChar = tm.tmHeight + tm.tmExternalLeading;
			ReleaseDC(hwnd, hdc);
			
		case WM_PAINT:
			hdc = BeginPaint(hwnd, &ps);
			for (i = 0; i < 10; i++) {
				wsprintf(szBuffer, TEXT("%d: %s"), i + 1, TEXT("I love China!"));
				TextOut(hdc, cxChar, (cyChar + 5) * i, szBuffer, lstrlen(szBuffer));
			}
            EndPaint(hwnd, &ps);
            return 0;

		case WM_LBUTTONUP:
			MessageBox(hwnd, TEXT("我被按了一下"), TEXT("我是标题"), MB_OK);
			return 0;

		case WM_CLOSE:
			if (MessageBox(hwnd, TEXT("是否真的关闭?"), TEXT("请确认"), MB_YESNO) == IDYES) {
				DestroyWindow(hwnd);
			}
			else {
                return 0;
			}

        case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
        }

        return DefWindowProc(hwnd, message, wParam, lParam);
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/921483.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存