当前位置: 首页 > news >正文

duiLib 解决点击标题栏中按钮无响应问题

HandMessage函数处理WM_LBUTTONDOWN消息,把点击标题栏作为拖动窗口拦截处理了,所以点击标题栏按钮不响应。问题代码如下:

else if (uMsg == WM_LBUTTONDOWN) {// 获取鼠标点击坐标POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };//ScreenToClient(m_hWnd, &pt); // 已经是客户区坐标了,不需要这一步转换// 找到标题栏控件CControlUI* pTitleBar = m_pm.FindControl(_T("title_bar"));if (pTitleBar) {// 判断鼠标点击是否在标题栏控件范围内RECT rcTitle = pTitleBar->GetPos();if (PtInRect(&rcTitle, pt)) {// 发送消息让系统处理窗口移动::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);return 0;}}
}

需判断是否点击的是按钮,代码修改如下:

else if (uMsg == WM_LBUTTONDOWN) {// 获取鼠标点击坐标POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };//ScreenToClient(m_hWnd, &pt); // 已经是客户区坐标了,不需要这一步转换// 找到标题栏控件CControlUI* pTitleBar = m_pm.FindControl(_T("title_bar"));if (pTitleBar) {// 判断鼠标点击是否在标题栏控件范围内RECT rcTitle = pTitleBar->GetPos();if (PtInRect(&rcTitle, pt)) {CControlUI* pControl = m_pm.FindControl(pt);bool isClickBtn = pControl && pControl->IsVisible() && pControl->IsEnabled() && dynamic_cast<CButtonUI*>(pControl) != nullptr;if (!isClickBtn) {// 发送消息让系统处理窗口移动::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);return 0;}}}
}

测试ok.  点击标题栏按钮能响应了。

下面贴一下demo工程完整代码,Main.cpp:

// 必须放在所有头文件包含之前. 预处理指令,编译优化,排除windows头文件(windows.h)中较少使用的组件
#define WIN32_LEAN_AND_MEAN	
// 必须放在所有头文件包含之前.  兼容性控制宏. 禁用微软对不安全函数(如scanf、strcpy等)的编译警告
#define _CRT_SECURE_NO_DEPRECATE#include <iostream>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <map>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
#include <sstream>
#include <exception>
#include <format>
#include <stack>#include <duilib/UIlib.h>
#include <windows.h>
#include <objbase.h>
#include <duilib/Core/UIContainer.h>using namespace DuiLib;// 窗口实例及消息相应部分
class CFrameWindowWnd : public CWindowWnd, public INotifyUI
{
public:CFrameWindowWnd() {};// 窗口唯一标识符LPCTSTR GetWindowClassName() const { return _T("UIMainFrame"); };// 定义窗口类样式。 UI_CLASSSTYLE_FRAME:窗口大小改变时触发重绘,通常用于带标题栏、边框的标准窗体。// CS_DBLCLKS‌:Windows 标准样式,启用窗口对鼠标双击消息的响应能力UINT GetClassStyle() const { return UI_CLASSSTYLE_FRAME | CS_DBLCLKS; };// 处理窗口生命周期终结void OnFinalMessage(HWND /*hWnd*/) { delete this; };// 核心功能:控件事件分发、消息传递枢纽void Notify(TNotifyUI& msg){if (msg.sType == _T("click")) {//if (msg.pSender->GetName() == _T("I服了You")) { // 即点击的根控件root,代码见下面//    Close(); // 关闭窗口//}if (msg.pSender->GetName() == _T("closebtn")) { // 点击关闭窗口Close();} else if (msg.pSender->GetName() == _T("minbtn")) { // 最小化//ShowWindow(m_hWnd, SW_MINIMIZE); // 不起作用::ShowWindow(m_hWnd, SW_MINIMIZE); // 通过全局作用域符强制调用Win32 API函数}else if (msg.pSender->GetName() == _T("maxbtn")) { // 最大化::ShowWindow(m_hWnd, SW_MAXIMIZE);// 隐藏最大化按钮CButtonUI* maxBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("maxbtn")));if (maxBtn) {maxBtn->SetVisible(false);}// 显示恢复按钮CButtonUI* restoreBtn = static_cast<CButtonUI*>(m_pm.FindControl(_T("restorebtn")));if (restoreBtn) {restoreBtn->SetVisible(true);}}else if (msg.pSender->GetName() == _T("restorebtn")) { // 恢复::ShowWindow(m_hWnd, SW_RESTORE);CControlUI* restoreBtn = static_cast<CControlUI*>(m_pm.FindControl(_T("restorebtn")));if (restoreBtn) restoreBtn->SetVisible(false);CControlUI* maxBtn = static_cast<CControlUI*>(m_pm.FindControl(_T("maxbtn")));if (maxBtn) maxBtn->SetVisible(true);} else if (msg.pSender->GetName() == _T("btn_test")) {// 测试读取输入框文本:CEditUI* editStr = static_cast<CEditUI*>(m_pm.FindControl(_T("edit_str")));if (editStr) {CDuiString strText = editStr->GetText(); // 获取文本内容CTextUI* textStr = static_cast<CTextUI*>(m_pm.FindControl(_T("text_str")));if (textStr) textStr->SetText(strText); // 刷新文本组件// 测试显示消息盒MessageBox(m_hWnd, L"安能摧眉折腰事权贵,使我不得开心颜!", L"消息标题", MB_OK | MB_ICONINFORMATION);}}}}LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam){if (uMsg == WM_CREATE) { // 成功创建窗口后, 系统会立即发送 WM_CREATE 消息, 标志着窗口句柄已有效但尚未显示m_pm.Init(m_hWnd); // 绑定窗口句柄,初始化绘图环境//CControlUI* root = new CButtonUI;//root->SetName(_T("I服了You"));//root->SetBkColor(0xFFcccccc);//m_pm.AttachDialog(root); // 关联控件树根节点,启动界面渲染. 根控件与绘图管理器关联. 这里根控件为root// 这里用xml文件作为页面布局:CDialogBuilder builder;CControlUI* root = builder.Create(_T("test2.xml"), 0, nullptr, &m_pm);ASSERT(root && "Failed to parse XML");m_pm.AttachDialog(root);m_pm.AddNotifier(this); // 注册事件监听器,接收控件通知(如 Notify 消息)return 0;}else if (uMsg == WM_DESTROY) { // 窗口销毁::PostQuitMessage(0); // 0表示正常退出}// 不想使用系统的标题栏和边框这些非客户区绘制,加上下面这俩分支(WM_NCACTIVATE、WM_NCCALCSIZE、WM_NCPAINT 消息)的处理else if (uMsg == WM_NCACTIVATE) { // 窗口获得焦点或失去焦点时收到该消息if (!::IsIconic(m_hWnd)) {// TRUE: 允许系统将非客户区绘制为失活状态(灰色标题栏)// FALSE: 阻止系统默认的激活状态绘制,可能用于实现自定义标题栏样式return (wParam == 0) ? TRUE : FALSE;}}else if (uMsg == WM_NCCALCSIZE) { // 当窗口大小或位置发生变化时,系统会发送该消息return 0; // 返回0屏蔽系统默认的标题栏计算. 这使得开发者可以用客户区完全模拟自定义标题栏,实现更灵活的界面设计}else if (uMsg == WM_NCPAINT) { // 用于非客户区绘制的消息,在duilib中主要用于屏蔽系统默认标题栏以实现自定义界面return 0;} else if (uMsg == WM_LBUTTONDOWN) {// 获取鼠标点击坐标POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };//ScreenToClient(m_hWnd, &pt); // 已经是客户区坐标了,不需要这一步转换// 找到标题栏控件CControlUI* pTitleBar = m_pm.FindControl(_T("title_bar"));if (pTitleBar) {// 判断鼠标点击是否在标题栏控件范围内RECT rcTitle = pTitleBar->GetPos();if (PtInRect(&rcTitle, pt)) {CControlUI* pControl = m_pm.FindControl(pt);bool isClickBtn = pControl && pControl->IsVisible() && pControl->IsEnabled() && dynamic_cast<CButtonUI*>(pControl) != nullptr;if (!isClickBtn) {// 发送消息让系统处理窗口移动::SendMessage(m_hWnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);return 0;}}}}LRESULT lRes = 0;// 将 Windows 消息(uMsg)交由 CPaintManagerUI 处理(即交给对应控件处理),若返回 true 表示消息已被消费,直接返回处理结果if (m_pm.MessageHandler(uMsg, wParam, lParam, lRes)) return lRes;return CWindowWnd::HandleMessage(uMsg, wParam, lParam); // 基类默认处理消息的流程}/* LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) {}*/public:CPaintManagerUI m_pm; // 承担界面绘制、消息处理和控件管理的核心职责
};// 程序入口及Duilib初始化部分
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int nCmdShow)
{CPaintManagerUI::SetInstance(hInstance);//CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetInstancePath());CDuiString path = CPaintManagerUI::GetInstancePath();// 设置资源路径:CPaintManagerUI::SetResourcePath(_T("skin\\")); // 相对路径CFrameWindowWnd* pFrame = new CFrameWindowWnd();if (pFrame == NULL) return 0;pFrame->Create(NULL, _T("别人笑我太疯癫,我笑他人看不穿"), UI_WNDSTYLE_FRAME, WS_EX_WINDOWEDGE);pFrame->ShowWindow(true);pFrame->CenterWindow(); // 居中显示CPaintManagerUI::MessageLoop();return 0;
}

布局test2.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!--界面布局-->
<!-- 窗口设置 -->
<Window roundcorner="5,5" size="600,450"  mininfo="80,60"  caption="0,0,0,36"> <!--caption属性定义标题栏的矩形区域,可拖动区域--><!--定义默认字体--><Font id="0" name="微软雅黑" size="12" bold="false" default="true" shared="true" /><Font id="1" name="微软雅黑" size="12" bold="true" shared="true" /><VerticalLayout bkcolor="#FFFFFFFF" bordersize="2" bordercolor="#FF0934DA" name ="root"><!--标题栏区域--><HorizontalLayout name="title_bar" height="36" bkcolor="#FF4775CC"><HorizontalLayout><Control width="10"/><Label name="apptitle" text="我是标题" font="1" textcolor="#FFFFFFFF" /></HorizontalLayout>  <HorizontalLayout height="25" width="96"><Button name="minbtn" tooltip="最小化" height="18" width="26" normalimage="file='minimize.png'" hotimage="file='minimize_h.png'" pushedimage="file='minimize_p.png'"/><Button name="maxbtn" tooltip="最大化" height="18" width="25" normalimage="file='maximize.png'" hotimage="file='maximize_h.png'" pushedimage="file='maximize_p.png'"/><Button name="restorebtn" visible="false" tooltip="恢复" height="18" width="25" normalimage="file='restore.png'" hotimage="file='restore_h.png'" pushedimage="file='restore_p.png'"/> <Button name="closebtn" tooltip="关闭" height="18" width="43" normalimage="file='close.png'" hotimage="file='close_h.png'" pushedimage="file='close_p.png'"/> </HorizontalLayout></HorizontalLayout><VerticalLayout name="body" padding="10,10,2,2"><Text name="text_str" wordbreak="true" text="安能摧眉折腰事权贵,使我不得开心颜" fontColor="0xFF333333" textPadding="5,5,5,5"/><Control height="10" /><Edit name="edit_str" width="120" height="26" textpadding="1,1,1,1" bkcolor="#FFFAEBD7"/><Control height="10" /><Button name="btn_test" text="测试" height="30" width="120" normalimage="file='button.png'" hotimage="file='button_h.png'" pushedimage="file='button_p.png'"/> </VerticalLayout></VerticalLayout>
</Window>

资源文件:

ok.  运行:

http://www.lryc.cn/news/623980.html

相关文章:

  • C# 反射和特性(自定义特性)
  • 健身房预约系统SSM+Mybatis实现(三、校验 +页面完善+头像上传)
  • RISC-V汇编新手入门
  • 【LeetCode】单链表经典算法:移除元素,反转链表,约瑟夫环问题,找中间节点,分割链表
  • 开发指南132-DOM的宽度、高度属性
  • HTTP0.9/1.0/1.1/2.0
  • SWE-bench:真实世界软件工程任务的“试金石”
  • 人工智能入门②:AI基础知识(下)
  • C++入门自学Day11-- String, Vector, List 复习
  • 如何利用gemini-cli快速了解一个项目以及学习新的组件?
  • 数据结构03(Java)--(递归行为和递归行为时间复杂度估算,master公式)
  • 人脸AI半球梯控/门禁读头的功能参数与技术实现方案
  • MySQL的事务基础概念:
  • 力扣刷题904——水果成篮
  • 黑马商城day08-Elasticsearch作业(个人记录、仅供参考、详细图解)
  • MLArena:一款不错的AutoML工具介绍
  • 【Linux】IO多路复用
  • SpringCloud 07 微服务网关
  • linux-高级IO(上)
  • 【撸靶笔记】第五关:GET - Double Injection - Single Quotes - String
  • Linux目录介绍
  • 002.Redis 配置及数据类型
  • 第三十八天(Node.JS)
  • AUTOSAR ARXML介绍
  • gin结合minio来做文件存储
  • Oracle Undo Tablespace 使用率暴涨案例分析
  • UE5多人MOBA+GAS 49、创建大厅
  • java设计模式之迪米特法则使用场景分析
  • ​​Vue 3 开发速成手册
  • PHP现代化全栈开发:测试驱动开发与持续交付实践