minigui[基础篇][6]—— 控件的高级编程

1.自定义控件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efcGTqsQ-1664940513075)(C:\Users\cjy\AppData\Roaming\Typora\typora-user-images\image-20221005105659098.png)]

/* 定义控件类的名字 */
#define MY_CTRL_NAME "mycontrol"

static int MyControlProc (HWND hwnd, int message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    switch (message) {
        case MSG_PAINT:	
            /* 仅仅输出“hello, world! – from my control” */
            hdc = BeginPaint (hwnd);
            TextOut (hdc, 0, 0, "Hello, world! – from my control");
            EndPaint (hwnd, hdc);
            return 0;
    }
	return DefaultControlProc (hwnd, message, wParam, lParam);
}

/* 该函数向系统中注册“mycontrol”控件 */
static BOOL RegisterMyControl (void)
{
    WNDCLASS MyClass;
    MyClass.spClassName = MY_CTRL_NAME;
    MyClass.dwStyle = 0;
    MyClass.hCursor = GetSystemCursor (IDC_ARROW);
    MyClass.iBkColor = COLOR_lightwhite;
    MyClass.WinProc = MyControlProc;
    return RegisterWindowClass (&MyClass);
}

/* 从系统中注销该控件 */
static void UnregisterMyControl (void)
{
	UnregisterWindowClass (MY_CTRL_NAME);
}

/* 注册控件类 */
RegisterMyControl();
...
/* 在某个主窗口中建立该控件类的实例 */
hwnd = CreateWindow (MY_CTRL_NAME, “”, WS_VISIBLE, IDC_STATIC, 0, 0, 200, 20, parent, 0);
...
/* 使用完毕后销毁控件并注销控件类 */
DestroyWindow (hwnd);
UnregisterMyControl();

相关API

BOOL GUIAPI RegisterWindowClass (PWNDCLASS pWndClass);
BOOL GUIAPI UnregisterWindowClass (const char *szClassName);
const char* GUIAPI GetClassName (HWND hWnd);
BOOL GUIAPI GetWindowClassInfo (PWNDCLASS pWndClass);

2.控件的子类化

方式1:对某个控件对象子类化 --》 只会影响该对象
方式2: 对某个控件类子类化 ---》 影响创建的所有该控件类的控件实例
方式3: 某个控件类的基础上新注册一个子类化的控件类 ---》 超类化 ---》 不会影响原有控件类 

demo — 对某个控件对象子类化(通过重新设置回调函数的处理)

#define IDC_CTRL1 100
#define IDC_CTRL2 110
#define IDC_CTRL3 120
#define IDC_CTRL4 130

#define MY_ES_DIGIT_ONLY 0x0001
#define MY_ES_ALPHA_ONLY 0x0002

static WNDPROC old_edit_proc; //全局变量保存原来的默认处理函数

static int RestrictedEditBox (HWND hwnd, int message, WPARAM wParam, LPARAM lParam)
{
    if (message == MSG_CHAR) {
        DWORD my_style = GetWindowAdditionalData (hwnd);
        /* 确定被屏蔽的按键类型 */
        if ((my_style & MY_ES_DIGIT_ONLY) && (wParam < '0' || wParam > '9'))
            return 0;
        else if (my_style & MY_ES_ALPHA_ONLY)
            if (!((wParam >= 'A' && wParam <= 'Z') || (wParam >= 'a' && wParam <= 'z')))
                /* 收到被屏蔽的按键消息,直接返回 */
                return 0;
    }
    /* 由老的窗口过程处理其余消息 */
    return (*old_edit_proc) (hwnd, message, wParam, lParam);
}

static int ControlTestWinProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
        case MSG_CREATE:
            {
                HWND hWnd1, hWnd2, hWnd3;
                //创建只能编辑数字的对话框
                CreateWindow (CTRL_STATIC, "Digit-only box:", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0,10, 10, 180, 24, hWnd, 0);
                hWnd1 = CreateWindow (CTRL_EDIT, "", WS_CHILD | WS_VISIBLE | WS_BORDER, IDC_CTRL1,200, 10, 180, 24, hWnd, MY_ES_DIGIT_ONLY);//附加数据 MY_ES_DIGIT_ONLY
                
                //创建只能编辑字母的编辑框
                CreateWindow (CTRL_STATIC, "Alpha-only box:", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0,10, 40, 180, 24, hWnd, 0);
                hWnd2 = CreateWindow (CTRL_EDIT, "", WS_CHILD | WS_BORDER | WS_VISIBLE, IDC_CTRL2,200, 40, 180, 24, hWnd, MY_ES_ALPHA_ONLY);//附加数据 MY_ES_ALPHA_ONLY
                
                //原来的编辑框
                CreateWindow (CTRL_STATIC, "Normal edit box:", WS_CHILD | WS_VISIBLE | SS_RIGHT, 0,10, 70, 180, 24, hWnd, 0);
                hWnd3 = CreateWindow (CTRL_EDIT, "", WS_CHILD | WS_BORDER | WS_VISIBLE, IDC_CTRL2, 200, 70, 180, 24, hWnd, MY_ES_ALPHA_ONLY);//附加数据 MY_ES_ALPHA_ONLY
                
                CreateWindow ("button", "Close", WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, IDC_CTRL4, 100, 100, 60, 24, hWnd, 0);
                
                /* 用自定义的窗口过程替换编辑框的窗口过程,并保存老的窗口过程。*/
                old_edit_proc = SetWindowCallbackProc (hWnd1, RestrictedEditBox);
                SetWindowCallbackProc (hWnd2, RestrictedEditBox);
                break;
            }
            ......
    }
    return DefaultMainWinProc (hWnd, message, wParam, lParam);
}

3.控件的组合使用

• 编辑框中以“HH:MM:SS”的形式显示时间。
• 当输入焦点位于编辑框中时,用户不能直接编辑时间,而必须以光标键和 PageDown 及 PageUp 键来控制光标所在位
置的时间单元值。为此,我们必须将该编辑框子类化,以捕获输入其中的按键,并做适当处理。
• 编辑框旁边安置一个旋钮控件,用户单击旋钮控件即可对光标所在的时间单元进行调整,增加或者减小。为实现这
一目的,我们可以利用旋钮控件的功能,将其目标窗口句柄设置为编辑框。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>
#include <minigui/mgext.h>

#define IDC_EDIT 100
#define IDC_SPINBOX 110

static PLOGFONT timefont;//用于编辑框的字体
static WNDPROC old_edit_proc;  //保存老的编辑框窗口过程

/* 本函数根据当前插入符的位置,修改相应的时间单元值 */
static void on_down_up (HWND hwnd, int offset)
{
    char time [10];
    int caretpos;//光标位置
    int hour, minute, second;
    
    GetWindowText (hwnd, time, 8);//得到时间值
    caretpos = SendMessage (hwnd, EM_GETCARETPOS, 0, 0); //得到光标位置
    
    hour = atoi (time);
    minute = atoi (time + 3);
    second = atoi (time + 6);
    if (caretpos > 5) { /* change second */
        /* 在秒的位置 */
        second += offset;
        if (second < 0)
            second = 59;
        if (second > 59)
            second = 0;
    }
    else if (caretpos > 2) { /* change minute */
        /* 在分的位置 */
        minute += offset;
        if (minute < 0)
            minute = 59;
        if (minute > 59)
            minute = 0;
    }
    else { /* change hour */
        /* 在时的位置 */
        hour += offset;
        if (hour < 0)
            hour = 23;
        if (hour > 23)
            hour = 0;
    }
    
    sprintf (time, "%02d:%02d:%02d", hour, minute, second); //将修改后的时间字符串置于编辑框
    SetWindowText (hwnd, time);
    SendMessage (hwnd, EM_SETCARETPOS, 0, caretpos); /* 设置插入符位置 */
}

/* 这是编辑框的子类化窗口过程函数 */
static int TimeEditBox (HWND hwnd, int message, WPARAM wParam, LPARAM lParam)
{
    /* 只处理按键消息。下面这些键按下时,调用 on_down_up 函数修改时间值 */
    if (message == MSG_KEYDOWN) {
        switch (wParam) {
            case SCANCODE_CURSORBLOCKUP: //上下键
                on_down_up (hwnd, 1);
                return 0;
            case SCANCODE_CURSORBLOCKDOWN:
                on_down_up (hwnd, -1);
                return 0;
            case SCANCODE_PAGEUP: //page上下键
                on_down_up (hwnd, 10);
                return 0;
            case SCANCODE_PAGEDOWN:
                on_down_up (hwnd, -10);
                return 0;
            case SCANCODE_CURSORBLOCKLEFT: //左右键
            case SCANCODE_CURSORBLOCKRIGHT:
                break;
            default:
                return 0;
        }
 }
	/* 忽略下面两个消息,用户只能通过上面的按键进行操作 */
    if (message == MSG_KEYUP || message == MSG_CHAR) 
        return 0;
    return (*old_edit_proc) (hwnd, message, wParam, lParam);
}

//主窗口消息处理函数
static int TimeEditorWinProc (HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
        case MSG_CREATE:
            {
                HWND hwnd;
                HDC hdc;
                HWND timeedit, spin;
                SIZE size;
                
                //1.创建说明静态框
                hwnd = CreateWindow (CTRL_STATIC, ".....",
 WS_CHILD | WS_VISIBLE | SS_LEFT,IDC_STATIC,10, 10, 220, 200, hWnd, 0);
                //2.创建逻辑字体
                timefont = CreateLogFont (NULL, "Arial", "ISO8859-1",
 FONT_WEIGHT_BOOK, FONT_SLANT_ROMAN, FONT_FLIP_NIL,FONT_OTHER_NIL, FONT_UNDERLINE_NONE, FONT_STRUCKOUT_NONE,30, 0);
                
               //3计算输出时间所用的大小和宽度
                hdc = GetClientDC (hWnd);
                SelectFont (hdc, timefont);
                GetTextExtent (hdc, "00:00:00", -1, &size); //设置时间
                ReleaseDC (hdc);
                
                //4.按照计算出的值创建编辑框窗口
                timeedit = CreateWindow (CTRL_SLEDIT,"00:00:00",WS_CHILD | WS_VISIBLE | ES_BASELINE,IDC_EDIT,40, 220, size.cx + 4, size.cy + 4, hWnd, 0);
                SetWindowFont (timeedit, timefont); 
                old_edit_proc = SetWindowCallbackProc (timeedit, TimeEditBox);// 子类化编辑框
                //5.创建旋钮控件
                spin = CreateWindow (CTRL_SPINBOX, "",WS_CHILD | WS_VISIBLE,IDC_SPINBOX,
40 + size.cx + 6, 220 + (size.cy - 14) / 2, 0, 0, hWnd, 0);
                SendMessage (spin, SPM_SETTARGET, 0, timeedit); //与编辑框绑定
                break;
            }
        case MSG_DESTROY:
            DestroyAllControls (hWnd);
            DestroyLogFont (timefont);
            return 0;
		case MSG_CLOSE:
            DestroyMainWindow (hWnd);
            PostQuitMessage (hWnd);
            return 0;
    }
    return DefaultMainWinProc (hWnd, message, wParam, lParam);
}
/* 以下创建主窗口的代码从略 */

运行效果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值