不规则窗口和控件的封装(win32 API)——TinyDlg

不规则窗口和控件的封装(win32 API)——TinyDlg


简介:
1)这里使用win32 API创建不规则窗口和控件;
2)通过设置透明像素或设置有效区域,使窗口呈现自定义的形状;
3)建议先用win32 API创建一个普通的窗口,再继续观看;


相关内容:
1)TinyDlg的介绍;
2)win32 API创建有背景的窗口;
3)设置不规则窗口的两种方式;
4)TinyDlg类间关系;


一、TinyDlg的介绍
TinyDlg可以根据提供的bmp图像,生成相应的窗口或者控件,如下图所示。
根据bmp图像生成的窗口和控件

图中包含了一个窗口和三个按钮。它们根据四个bmp图像生成,且在透明部分可以被鼠标穿过。此外,对于窗体和控件可以自定义相应事件。比如,在鼠标点击黄色圆形按钮或者蓝色五角星按钮时,跳出小框显示它们各自的名字;在鼠标点击红色带X的按钮时,整个窗体可以被关闭。


二、win32 API创建有背景的窗口
在创建有背景的窗口时,主要是对窗口控制类进行设置,如下:

// 加载bmp图像,存储到HBITMAP类型的变量
m_skin = (HBITMAP)LoadImage(0, skinPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
// 根据HBITMAP,创建HBRUSH
m_brush = CreatePatternBrush(m_skin);

// 设置窗口控制类中的背景
m_wcex.hbrBackground = m_brush;


这部分并没有什么特别的。不过,有一点需要注意,就是资源的释放,如:

DeleteObject(m_skin);
DeleteObject(m_brush);


三、设置不规则窗口的两种方式;
1、首先需要提的一点就是,窗口的创建和按钮的创建并没有太大的区别,如下:

    // 创建窗口
    HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, "windowName", 
        WS_OVERLAPPEDWINDOW, 0, 100, 200, 300,
        NULL, NULL, hInstance, NULL);

    // 使用预定义的类名"Button",创建按钮
    CreateWindowEx(0, "Button", "OK", WS_VISIBLE | WS_CHILD, 0, 100, 50, 50,
        hWnd, NULL, hInstance, NULL);


2、创建不规则形状窗口的两种方式
1)设置透明像素
这种方式就是将某个色彩的透明度设置为0。这样,只要将背景色设置为透明,窗口就会呈现为不规则的形状。在透明的区域,鼠标也可以穿透它,对窗口后面的对象进行操作。
它大体可以分为两步。首先,创建窗口时,将窗口设置为分层窗口;然后,设置分层窗口属性,修改某个色彩对应的透明度。相关代码如下:

    HWND hWnd = CreateWindowEx(WS_EX_LAYERED, wcex.lpszClassName,
        "windowName", WS_OVERLAPPEDWINDOW,
        0, 100, 200, 300,
        NULL, NULL, hInstance, NULL);

    // 使纯白色变为透明
    SetLayeredWindowAttributes(hWnd, RGB(255, 255, 255), 0, LWA_COLORKEY);

像这样:
这里写图片描述


2)设置有效区域
这种方式通过为已创建好的窗口,设置有效区域,从而实现自定义形状的窗口效果。它基本上可以分成三步:1)创建区域HRGN结构;2)创建窗体;3)设置窗体有效区域。以圆形窗口为例:

    HRGN region = CreateEllipticRgn(0, 0, 100, 100);

    HWND hWnd = CreateWindowEx(0, wcex.lpszClassName,
        "windowName", WS_OVERLAPPEDWINDOW,
        0, 100, 200, 300,
        NULL, NULL, hInstance, NULL);

    SetWindowRgn(hWnd, region, TRUE);


而在按这种方式创建不规则窗体时,主要是在region的创建上做一些改变。例如,根据图像的前景像素创建有效区域。此时,我们可以对图像中的每一个像素进行扫描,若某个像素不是纯白色,我们就在这个位置创建只有一个像素的区域,然后将这些前景像素对应的区域合并成我们真正想要的不规则区域,如下:

// 创建一个临时区域,然后合并到总区域region中
HRGN temp = CreateRectRgn(x, y, x + 1, y + 1);
CombineRgn(region, region, temp, RGN_OR);


四、TinyDlg类间关系
TinyDlg类间关系
这幅图展示了TinyDlg相关类的继承和组合关系。

1)TinyBase和TinyCtrl都是接口类,如下图:
TinyBase和TinyCtrl

2)TinyDlg和TinyCtrl
TinyDlg的成员变量中包含一个以TinyCtrl指针为元素的vector。这样,主窗口可以通过vector<TinyCtrl*>,对窗口上的创建和释放。

TinyDlg和TinyCtrl

3)TinyBtn
TinyBtn是TinyCtrl的一个实现类。这里作为一个示例,后续自己封装其它控件时,可以作为参考。这个类除了构造函数和析构函数外,其它成员都是对于TinyCtrl(TinyBase)接口的实现。
另外,参照第三节提的两种创建不规则窗口的方式,这里在创建窗口时使用了第一种,而在创建按钮时,使用了第二种。其中差异,可以自己尝试。


四、使用示例

#include "TinyDlg.h"
LRESULT CALLBACK proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
    switch (msg)
    {
    case WM_LBUTTONDOWN:
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    POINT wndPos = { 100, 100 };
    TinyDlg td(hInstance, "test", wndPos, "..\\img\\test.bmp");

    POINT btnPos1 = { 0, 0 };
    TinyBtn tb1(hInstance, "btnA", btnPos1, "..\\img\\btnA.bmp");

    POINT btnPos2 = { 240, 300 };
    TinyBtn tb2(hInstance, "btnB", btnPos2, "..\\img\\btnB.bmp");

    POINT btnPos3 = {240, 0};
    TinyBtn tb3(hInstance, "btnC", btnPos3, "..\\img\\btnC.bmp");
    tb3.SetWndProc(proc);

    td.AppendCtrl(&tb1);
    td.AppendCtrl(&tb2);
    td.AppendCtrl(&tb3);

    td.Create(NULL);    

    TinyDlg::MsgLoop();

    return 0;
}


五、说明和下载链接
正如开头简介里说的,建议先用win32 API创建一个普通的窗口,然后根据上面提到的这些,对代码进行调整。这样,可能比较有意思。

总的来说,TinyDlg做的有点粗糙。不过,好在它产生的东西跟预期是相符的。而且,它在使用上非常方便:只需要include一个TinyDlg.h,然后给出窗口的名字、位置、图像就行。

码云链接:https://gitee.com/Chieng/TinyDlg

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值