中年人学C语言Windows程序设计,21静态文本框控件和创建自己的字体

本文介绍了Windows编程中如何使用静态文本框控件显示文本,包括控件的创建、样式设置以及字体的创建和应用。通过CreateWindow函数创建静态文本框,并利用WM_SETFONT消息设置自定义字体。同时展示了在鼠标点击事件中动态改变文本框字体的示例代码。
摘要由CSDN通过智能技术生成

Windows static控件(静态文本框控件)

使用 TextOut 和 DrawText 函数有时候会不方便,例如:
文本不能自动换行,超出窗口范围会被隐藏;
每次更改文本都要先擦除背景再重新输出,比较麻烦。

实际开发中一般使用静态文本框控件来输出文本。静态文本框是Windows 的一种标准控件,可以用来在窗口上显示一段文本,并且文本容易受到控制。除了静态文本框,Windows的标准控件还有很多种,例如按钮、下拉菜单、单选按钮、复选框等。

其实,控件也是一种窗口,也使用 CreateWindow 函数来创建。但是它们使用的窗口类的名字比较特殊,是由Windows预定义的;静态文本框控件的窗口类名是static。

与前面创建的独立窗口不同,控件是子窗口,创建时必须指定父窗口,这样控件才能有“归属”。

我们先来回顾一下 CreateWindow 函数的原型:

HWND CreateWindow(
    LPCWSTR lpClassName,  //窗口类名
    LPCWSTR lpWindowName,  //窗体标题(或控件文本)
    DWORD dwStyle,  //窗口/控件样式
    int x,  //窗口相对桌面(或子窗口相对父窗口)的 X 坐标
    int y,  //窗口相对桌面(或子窗口相对父窗口)的 Y 坐标
    int nWidth,  //窗体宽度
    int nHeight,  //窗体高度
    HWND hWndParent,  //父窗口句柄
    HMENU hMenu,  //菜单句柄
    HINSTANCE hInstance,  //当前程序实例句柄
    LPVOID lpParam  //一个指向某数值的指针
);

几点说明:

  1. 对于参数 lpClassName 和 lpWindowName,一般使用宽字符,请加前缀L或使用TEXT()。

lpClassName 为窗口类的名字,可以是 RegisterClass 注册的类名,也可以是 Windows 预定义的控件类名。

如果你创建的是独立窗口,则 lpWindowName 应传入窗口的标题,若你希望创建控件,则应传入控件的文本。

  1. dwStyle 表示窗口样式或控件样式。窗口样式以 WS 开头,详情请查看《CreateWindow窗口风格取值》。这些样式既可以用于独立窗口,也可以用于控件(子窗口)。

除了窗口样式,不同的控件也有自己特有的样式。对于 static 控件,它的样式以 SS 开头,常用的有:
样式 说明
SS_LEFT 文本居左。
SS_RIGHT 文本居右。
SS_CENTER 文本居中。
SS_CENTERIMAGE 文本垂直居中。设置该样式后只能显示一行文本,即使有 ‘\n’ 也不会换行。
SS_LEFTNOWORDWRAP 文本居左,不自动换行(有 ‘\n’ 才会换行),超出控件范围的文本将被隐藏。
SS_SIMPLE 只显示一行文本(有 ‘\n’ 也不换行),且不自动换行,超出控件范围的文本将被隐藏。
3) 对于参数 hWndParent,如果是独立窗口,那么为 NULL,如果是控件,那么就需要父窗口的句柄。

  1. 参数 hMenu 十分重要,在后续介绍的需要处理控件消息的控件中,这是他们的唯一标识符。每个控件的 hMenu 参数值都应不同,并且需要强制转换到 HMENU 类型,如 (HMENU)1 ,再次强调,每个控件的(HMENU)后的值都应不同,可以从1往下递推。

Windows CreateFont:创建自己的字体

前面无论是使用文本输出函数还是 static 控件,字体都是默认的,比较丑陋,我们完全可以自己创建更加炫酷的字体。

创建字体使用 CreateFont 函数,它的原型是:
HFONT CreateFont(
int cHeight, //字体的逻辑高度
int cWidth, //字体的逻辑宽度
int cEscapement, //指定移位向量相对X轴的偏转角度
int cOrientation, //指定字符基线相对X轴的偏转角度
int cWeight, //设置字体粗细程度
DWORD bItalic, //是否启用斜体
DWORD bUnderline, //是否启用下划线
DWORD bStrikeOut, //是否启用删除线
DWORD iCharSet, //指定字符集
DWORD iOutPrecision, //输出精度
DWORD iClipPrecision, //剪裁精度
DWORD iQuality, //输出质量
DWORD iPitchAndFamily, //字体族
LPCSTR pszFaceName //字体名
);
上面的14个参数完全记住几乎不可能,下面是简单的说明,其他的“照猫画虎”即可。

  1. 参数 cWidth 和 cHeight 通常取负值,且高度为宽度的2倍,如 -18 和 -9,即可指定 13.5 |(H+W)/2| 磅的字体。

  2. 对于字体粗细程度 cWeight,可以使用 FW_ 开头的宏定义;一般取 FW_NORMAL (400),此参数需要值的值域为 [0,1000]。

  3. 对于参数 bItalic、bUnderline、bStrikeOut,直接使用 TRUE 或 FALSE 传值即可。

  4. 对于字符集 iCharSet,一般可以直接使用 DEFAULT_CHARSET 让系统自动处理。
    注意:字体也是一种 GDI 对象,使用完后也要在 WM_DESTROY 消息中删除。
    创建完字体后并不能立即使用,还需要手动触发 WM_SETFONT 消息,让Windows 将当前字体设置为我们创建的字体。

发送消息使用 SendMessage 函数,它可以让我们在必要时主动向窗口发送各种消息,原型为:
LRESULT SendMessage(
HWND hWnd, //发送消息的目标窗口句柄
UINT msg, //将要发送的消息
WPARAM wParam, //附加消息1
LPARAM lParam //附加消息2
);
这些参数和 WndProc 函数非常类似。没错,SendMessage 发送的消息就是由窗口过程来处理的。

设置字体的消息是 WM_SETFONT,只要向附加参数 wParam 传入 CreateFont 返回的句柄即可(需要转换到 WPARAM 类型)。

代码实例

下面的代码,会在 WM_CREATE 事件中创建 static 控件,并修改字体为微软雅黑:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    回调函数
    参数:
    hwnd : 窗口句柄
    message : 消息ID
    wParam和lParam:消息参数
        //int i;
        //size_t j;
    HDC hdc;//定义设备环境句柄  
    static TCHAR  szBuffer[128];
    //TEXTMETRIC tm;
   // SCROLLINFO si;
    PAINTSTRUCT ps;
    size_t iStrLength;
    static int cxChar, cyChar, cxClient, cyClient;
    static HWND hStatic;//静态文本框
    static HFONT hFont; //声明一个逻辑字体句柄为静态变量
    switch (message)
    {
        case WM_SIZE://窗体大小改变
            hdc = GetDC(hWnd);
            //GetClientRect(hwnd, &rect);
            cxClient = LOWORD(lParam);//当前x像素
            cyClient = HIWORD(lParam);//当前y像素
            StringCchPrintf(szBuffer, 128, TEXT("当前客户区的分辨率:%d * %d px"), cxClient, cyClient);
            StringCchLength(szBuffer, 128, &iStrLength);
            SetTextAlign(hdc, TA_CENTER | TA_TOP);
            TextOut(hdc, cxClient / 2, 0, szBuffer, iStrLength);
            ReleaseDC(hWnd, hdc);
            return 0;

       

        case  WM_CREATE:
            hFont = CreateFont(
                -16/*高度*/, -8/*宽度*/, 0/*不用管*/, 0/*不用管*/, 400 ,//设置字体粗细程度一般这个值设为400,
                FALSE/*不带斜体*/, FALSE/*不带下划线*/, FALSE/*不带删除线*/,
                DEFAULT_CHARSET,  //这里我们使用默认字符集,还有其他以 _CHARSET 结尾的常量可用
                OUT_CHARACTER_PRECIS, //输出精度
                CLIP_CHARACTER_PRECIS,  //剪裁精度
                DEFAULT_QUALITY,  //默认输出质量
                FF_DONTCARE,  //不指定字体族*/
                TEXT("微软雅黑")  //字体名
            );
            hStatic = CreateWindow(
                TEXT("static"), //静态文本框的类名
                TEXT("我其实是一个静态文本框"),  //控件的文本
                WS_CHILD /*子窗口*/ | WS_VISIBLE /*创建时显示*/ | WS_BORDER /*带边框*/ | SS_CENTER /*水平居中*/ | SS_CENTERIMAGE /*垂直居中*/,
                20 /*X坐标*/, 20 /*Y坐标*/, 200 /*宽度*/, 100 /*高度*/,
                hWnd,  //父窗口句柄
                (HMENU)1,  //为控件指定一个唯一标识符
                hInst,  //当前程序实例句柄
                NULL
            );
            //设置控件字体
            SendMessage(
                hStatic,  //欲设置字体的控件句柄
                WM_SETFONT,  //消息名(消息类型)
                (WPARAM)hFont,  //字体句柄
                NULL  //传空值即可
            );
            //SendMessage(hStatic, WM_SETFONT, (WPARAM)hFont, NULL);
            break;
           
        case WM_PAINT://窗口绘画:点
        {
            //int x, xLast;
            HDC hdc = BeginPaint(hWnd, &ps);//函数为指定窗口进行绘画作准备,并用将和绘画有关的信息填充到一个 PAINTSTRUCT 结构中。
            EndPaint(hWnd, &ps);
            return 0;
        }
        case WM_DESTROY:
            //DeleteObject(hFont);
            DeleteObject(hFont);//删除创建的字体
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    return 0;
}

在这里插入图片描述
给 CreateWindow 函数传入的第三个参数为窗口样式或控件样式(子窗口样式)。不同的控件样式一般不同,而窗口样式则大同小异:
WS_CHILD:表明是一个子窗口,也就是控件,不是独立窗口。
WS_VISIBLE:创建时显示,如果没有该样式,则需要调用 ShowWindow 函数来显示。
WS_BORDER:带边框。

给 CreateWindow 函数传入的倒数第二个参数为 hInst,表示当前程序的实例句柄。hInst 在 WndProc 函数中并不存在,因为当前实例句柄是通过 WinMain 函数的参数传入的,所以必须要定义一个全局变量 hInst,然后在 WinMain 中给它赋值后才能使用。如下所示:

#include <windows.h>

HINSTANCE hInst;

int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    PSTR szCmdLine,
    int iCmdShow
){
    // TODO: 其他代码
    hInst = hInstance;
    // TODO: 其他代码
}

另外,你也可以通过((LPCREATESTRUCT)lParam)->hInstance语句获得当前程序实例句柄,有兴趣的朋友请自行Google或百度。
获取、修改控件文本
GetWindowText 函数用于将指定窗口的标题文本(如果存在)拷贝到一个缓存区内;如果指定的窗口是一个控件,则拷贝控件的文本。它的原型为:

Int GetWindowText(
    HWND hWnd,  //窗口/控件句柄
    LPTSTR lpString,  //指向接收文本的缓冲区指针
    Int nMaxCount  //要保存在缓冲区内的字符的最大个数
);

说明:
nMaxCount 指定要保存在缓冲区内的字符的最大个数,其中包含NULL字符。如果文本超过界限,它就被截断。
函数执行成功,返回拷贝的字符的个数。

代码举例:
//定义缓冲区

TCHAR szStaticBuf[100];
//获取 static 控件的文本
GetWindowText(hStatic, szStaticBuf, 100);

类似的,SetWindowText 函数可以用来设置窗口标题或控件文本,它的原型为:

BOOL SetWindowText(
    HWND hwnd,
    LPCTSTR lpString
);

综合实例2

创建6中字体,和静态文本框,然后用户每次点击一次鼠标显示显示鼠标点击的次数,并且循环改变静态文本框内的字体显示:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    回调函数
    参数:
    hwnd : 窗口句柄
    message : 消息ID
    wParam和lParam:消息参数
        //int i;
        //size_t j;
    HDC hdc;//定义设备环境句柄  
    static TCHAR  szBuffer[128];
    //TEXTMETRIC tm;
   // SCROLLINFO si;
    PAINTSTRUCT ps;
    size_t iStrLength;
    static int cxChar, cyChar, cxClient, cyClient;
    static HWND hStatic;//静态文本框
    static HFONT hFont[6]; //声明一个逻辑字体句柄为静态变量
    int i,n;
    //size_t iLength;
    static int iClick = 0;
    static TCHAR  szFont[10][6] = { TEXT("微软雅黑"),  TEXT("宋体"), TEXT("黑体"),  TEXT("楷体"),  TEXT("幼圆"),  TEXT("隶书") };
    switch (message)
    {
        case WM_SIZE://窗体大小改变
            hdc = GetDC(hWnd);
            //GetClientRect(hwnd, &rect);
            cxClient = LOWORD(lParam);//当前x像素
            cyClient = HIWORD(lParam);//当前y像素
            StringCchPrintf(szBuffer, 128, TEXT("当前客户区的分辨率:%d * %d px"), cxClient, cyClient);
            StringCchLength(szBuffer, 128, &iStrLength);
            SetTextAlign(hdc, TA_CENTER | TA_TOP);
            TextOut(hdc, cxClient / 2, 0, szBuffer, iStrLength);
            ReleaseDC(hWnd, hdc);
            return 0;

        case  WM_CREATE:        
            for (i = 0; i < 6; i++)
            {
                hFont[i] = CreateFont(
                    -20/*高度*/, -10/*宽度*/, 0/*不用管*/, 0/*不用管*/, 400,//设置字体粗细程度一般这个值设为400,
                    FALSE/*不带斜体*/, FALSE/*不带下划线*/, FALSE/*不带删除线*/,
                    DEFAULT_CHARSET,  //这里我们使用默认字符集,还有其他以 _CHARSET 结尾的常量可用
                    OUT_CHARACTER_PRECIS, //输出精度
                    CLIP_CHARACTER_PRECIS,  //剪裁精度
                    DEFAULT_QUALITY,  //默认输出质量
                    FF_DONTCARE,  //不指定字体族*/
                    szFont[i]  //字体名
                );
            }
            
            hStatic = CreateWindow(
                TEXT("static"), //静态文本框的类名
                TEXT("我其实是一个静态文本框"),  //控件的文本
                WS_CHILD /*子窗口*/ | WS_VISIBLE /*创建时显示*/ | WS_BORDER /*带边框*/ | SS_CENTER /*水平居中*/ | SS_CENTERIMAGE /*垂直居中*/,
                20 /*X坐标*/, 20 /*Y坐标*/, 400 /*宽度*/, 300 /*高度*/,
                hWnd,  //父窗口句柄
                (HMENU)1,  //为控件指定一个唯一标识符
                hInst,  //当前程序实例句柄
                NULL
            );
            break;
           
        case WM_PAINT://窗口绘画:点
        {
            //int x, xLast;
            HDC hdc = BeginPaint(hWnd, &ps);//函数为指定窗口进行绘画作准备,并用将和绘画有关的信息填充到一个 PAINTSTRUCT 结构中。
            EndPaint(hWnd, &ps);
            return 0;
        }
        case WM_LBUTTONDOWN:  //鼠标左键单击消息
            iClick++;
            //设置控件字体
            n = (iClick) % 6-1;
            SendMessage(
                hStatic,  //欲设置字体的控件句柄
                WM_SETFONT,  //消息名(消息类型)
                (WPARAM)hFont[n],  //字体句柄
                NULL  //传空值即可
            );     
            StringCchPrintf(szBuffer, 128, TEXT("鼠标左键被单击%d次"), iClick);            
            SetWindowText(hStatic, szBuffer);            
            break;
            
        case WM_DESTROY:
            DeleteObject(hFont);//删除创建的字体
            PostQuitMessage(0);
            break;             
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    return 0;
}

显示在这里插入图片描述
鼠标点击1次
在这里插入图片描述
点击第二次
在这里插入图片描述

第三个

在这里插入图片描述
点击第4次

在这里插入图片描述

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值