win32 button 可以设置icon大小

背景

记录一下win32编程,其实这种东西没有任何意义,只是回味一下win32编程,只是现在工具用的win32开发的,不想用第三方的界面库。

加载icon

方法一,这种无法设置icon的大小

    HICON folderico = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
    ::SendMessage(btn_control_home, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)folderico);

方法二,可以设置大小

    HANDLE new_image = LoadImage(NULL, L"res\\Power.ico", IMAGE_ICON, 28, 28, LR_LOADFROMFILE); 
    ::SendMessage(btn_control_power, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)new_image);

总结

win32 因为所有控件都是窗口,所以设置属性或者获取属性都是发送消息,但参数各式各样,这个谁记得住呢,所以才需要封装,点几个属性设置一下就可以了。。。所以win32界面开发的话,效率是过时的。如果不重要界面的话,那就无所谓。减少体积挺好的。

duilib 消息自己简单总结

背景

最近由于各种原因又学习了duilib c/c++界面库

总结

  1. CWindowWnd::__WndPro
  2. pThis->HandleMessage
  3. m_PaintManager.MessageHandler(uMsg, wParam, lParam, lRes)[这个是最重要的]

前2步

调用虚函数 HandleMessage, 我们做界面开发时候会继承CWindowWnd其实前面2步,只是把窗口HWND 与 我们代码对象绑定起来,建立关系,duilib 提供 WindowImplBase 方便我们开发界面而已,我们也可以不继承这个类,自己写事件和一些事件处理。

m_PaintManager.MessageHandle

进入界面库核心逻辑,前面都是只是传统界面逻辑,这里根据windwos 系统消息[WM_PAINT, WM_LBUTTONDOWN] 等等事件。

  1. 属性【画图】
  2. 行为

画图

根据我们的节点,一个一个画出来,这个类似html技术,目前所有主流界面开发都有点类似html 界面开发思路。

行为

根据鼠标和按键触发对应行为,dulib的行为基本都是通过notify 时间投递,这个投递在当前HWND里面。

这个类似win32 界面开发, 传统win32开发增加一个按钮事件 ,那么就投递 BM_CLICK给父窗口,父窗口在消息处理函数中处理这个消息。

例子

Button 点击例子代码分析

    case WM_LBUTTONUP:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            if( m_pEventClick == NULL ) break;
            ReleaseCapture();
            TEventUI event = { 0 };
            event.Type = UIEVENT_BUTTONUP;
            event.pSender = m_pEventClick;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            // By daviyang35 at 2015-6-5 16:10:13
            // 在Click事件中弹出了模态对话框,退出阶段窗口实例可能已经删除
            // this成员属性赋值将会导致heap错误
            // this成员函数调用将会导致野指针异常
            // 使用栈上的成员来调用响应,提前清空成员
            // 当阻塞的模态窗口返回时,回栈阶段不访问任何类实例方法或属性
            // 将不会触发异常
            CControlUI* pClick = m_pEventClick;
            m_pEventClick = NULL;
            pClick->Event(event);
        }
        break;

在CPaintManagerUI::MessageHandler中处理windows 窗口消息,这里贴出来处理鼠标点击松开事件,基本都是这种写法来处理自绘的界面,记得很久很久之前自己写自绘的按钮就是在WM_PAINT 进行贴图,然后点击处理点击事件,就可以实现图片的按钮,比自己修改win32 button还方便一些,因为整个自绘逻辑都是自己开发的,用系统Button,很多逻辑都是系统,这样子导致很多限制,要打补丁的地方太多了。

            TEventUI event = { 0 };
            event.Type = UIEVENT_BUTTONUP;
            event.pSender = m_pEventClick;
            event.wParam = wParam;
            event.lParam = lParam;
            event.ptMouse = pt;
            event.wKeyState = (WORD)wParam;
            event.dwTimestamp = ::GetTickCount();
            // By daviyang35 at 2015-6-5 16:10:13
            // 在Click事件中弹出了模态对话框,退出阶段窗口实例可能已经删除
            // this成员属性赋值将会导致heap错误
            // this成员函数调用将会导致野指针异常
            // 使用栈上的成员来调用响应,提前清空成员
            // 当阻塞的模态窗口返回时,回栈阶段不访问任何类实例方法或属性
            // 将不会触发异常
            CControlUI* pClick = m_pEventClick;
            m_pEventClick = NULL;
            pClick->Event(event);

这里获取到点击控件,通过坐标计算找到合适控件【通过计算】,然后触发事件,这里事件就是UIEVENT_BUTTONUP,然后控件开始处理该事件。这个是虚函数,基本不会重载该虚函数,

button 控件处理函数

void CControlUI::Event(TEventUI& event)
{
    if( OnEvent(&event) ) DoEvent(event);
}

所有控件的基类,OnEvent 是委托事件,用户代码基本不会委托这个函数,除了一些复杂的控件。
DoEvent是虚函数,所有控件基本都会重载这个函数,用来专门事件处理的。

butto调用 DoEvent

        if( event.Type == UIEVENT_BUTTONUP )
        {
            if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
                if( ::PtInRect(&m_rcItem, event.ptMouse) && IsEnabled()) Activate();
                m_uButtonState &= ~(UISTATE_PUSHED | UISTATE_CAPTURED);
                Invalidate();
            }
            return;
        }

Activate 激活按钮触发点击事件,Button还有其他事件要处理,来显示不同点击事件

    bool CButtonUI::Activate()
    {
        if( !CControlUI::Activate() ) return false;
        if( m_pManager != NULL ) m_pManager->SendNotify(this, DUI_MSGTYPE_CLICK);
        return true;
    }

触发通知,这个等同win32变成的发送 BN_CLICKED事件,m_pManager里面有一个list 包含notify listener,遍历进行通知。
duilib窗口对象都会绑定一个CPaintManagerUI,窗口创建后就添加事件监听。
我们开发代码都会实现INotifyUI或者直接继承WindowImplBase,我们业务代码基本都在notify实现的。
总结
这里这么多代码,无法就是子控件与窗口建立联系,方便回调。
duiib这个界面库,基本在各大厂商进行验证,可以算是windows pc上面一个标准了,官方开源版本太老,可以用其他大厂的开源duilib直接开发,不过自己继续在官方版本也可以。
如果跨平台基本就是electron,但这种内存比较大,几百M跑不掉,对内容类型的界面用这个比较方便,对于性能要求比较高还是用duilib比较好。
QT也是不错的选择,不过我自己没有用过,wps yy貌似都是qt开发的。
选择哪个开发主要看自己业务,没有完美的东西