这次我们将要给Widget增加一些状态,并使其能够接受出消息处理扩展,测试工程中实现了一个按钮的消息处理扩展。

Widget状态:

之前的控件只是绘制了一个边框,并且总是会在窗口中显示。实际上我们往往会希望能够让某个控件显示或者隐藏、可用或者不可用等等,那么控件应该具有能够标识这些状态的属性,于是我们给Widget增加了状态概念。

// 状态相关
void AddStates(size_t states);
void SubStates(size_t states);
bool CheckState(widget::StateBitField s);

上面是状态相关的几个接口,包括了增加状态组,减少状态组,检测状态。这里有个状态组的概念,是因为我将状态用位域来实现,那么他们就可以通过or运算来得到多个状态的集合,我就这个集合称为状态组。

enum StateBitField{
STATE_VISIBLE = 1 << 0, // 控件可见?决定控件是否被绘制
STATE_ENABLE = 1 << 1, // 控件可用?决定控件是否响应鼠标键盘消息
STATE_TRANSPARENT = 1 << 2, // 控件透明?决定控件是否响应鼠标键盘消息以及是否显示tooltip
};

目前我给Widget定义了3个状态:可见、可用、透明。默认创建的Widget是不可见、不可用、不透明的,需要在创建成功后手动设置,例如:

// 建立根控件
auto pRootWidget = ghost::Widget::Create();
pRootWidget->AddStates(
  ghost::widget::STATE_VISIBLE|ghost::widget::STATE_ENABLE|ghost::widget::STATE_TRANSPARENT);

消息处理扩展:

通常对于控件来说,没有消息处理就等于没有生命意义,那么为Widget添加消息处理扩展就意味着使Widget活起来,这次我们就来完成这个任务,期待Widget活起来的那激动人心的一刻。和以往添加扩展支持一样,为扩展编写一个抽象基类,在Widget的关联对象管理中添加这个扩展的关联处理,然后在Widget的SendMessage处理逻辑里增加对消息处理扩展的支持。那么我们的SendMessage实现就变成了这样:

int Widget::SendMessage(widget::Message message, void* param1/* = 0*/, void* param2/* = 0*/)
{
if (!CheckState(widget::STATE_ENABLE))
{
// 不响应鼠标键盘消息
if ((widget::MSG_MOUSE_FIRST <= message
&& widget::MSG_MOUSE_LAST >= message)
||(widget::MSG_KEY_FIRST <= message
&& widget::MSG_KEY_LAST >= message))
{
return widget::MSG_RESULT_NONE;
}
}
if (CheckState(widget::STATE_TRANSPARENT))
{
// 不响应鼠标键盘消息,不显示tooltip
if ((widget::MSG_MOUSE_FIRST <= message
&& widget::MSG_MOUSE_LAST >= message)
||(widget::MSG_KEY_FIRST <= message
&& widget::MSG_KEY_LAST >= message))
{
return widget::MSG_RESULT_NONE;
}
}

auto pRelatedObject = GetRelatedObject();
if (pRelatedObject)
{
auto pMessageHandle = pRelatedObject->GetMessageHandle();
if (pMessageHandle)
{
bool handled = false;
int res = pMessageHandle->OnMessage(this, message, param1, param2, handled);
if (handled)
{
return res;
}
}
}

switch (message)
{
#ifdef _DEBUG
case widget::MSG_DRAW:
{
HBRUSH hBrush = ::CreateSolidBrush(pImpl_->testFrameColor_);
::FrameRect((HDC)param1, &pImpl_->absoluteRect_, hBrush);
::DeleteObject(hBrush);
}
break;
#endif // _DEBUG
case widget::MSG_HIT_TEST:
if (::PtInRect(&pImpl_->absoluteRect_, *(const POINT*)param1))
{
return ~widget::MSG_RESULT_NONE;
}
break;
}
return widget::MSG_RESULT_NONE;
}

我多次提到了tooltip,但是我们这次并没有为Widget增加其支持,它将在后面被加入到Widget中来。可以看到这里处理有对消息处理扩展的支持,还有状态对于消息的影响。这里出现了一个MSG_HIT_TEST,这是一个新增的消息。这次为Widget添加了很多的消息,包括了鼠标、键盘等,要将鼠标消息准确的发送给正确的控件,那么点击测试是必不可少的,这个MSG_HIT_TEST消息则是用于控件处理点击测试的。

点击测试:

当容器产生了鼠标事件的时候,我们能够得到鼠标热点在容器中的坐标。前面我也多次提到,模拟控件是容器中的某个区域,那么当鼠标热点位于某个控件所处的区域的时候,那么这个鼠标事件我们就应当交由这个控件进行处理(这是通常情况,也有可能某个控件作为透明控件,不接受任何点击测试)。于是我们便通过点击测试(HitTest)这个访问接口来找到应该处理鼠标事件的控件。在找到控件之后,我们还将坐标映射到了控件的相对坐标系,这样控件就可以以自身的相对位置来处理鼠标事件了。

当然,这次的内容非常多,包括坐标映射、区域映射,捕获鼠标的控件、活动控件、焦点控件等概念都未提到,但在代码中还是能够看到这些概念的。如果一一介绍,那文章就会非常冗长,也会使Widget实现进展缓慢,因此我通常都会省略一些内容,这些内容也就只能通过代码阅读来得到了。

按钮:

为了测试我们这次实现的内容,我们编写了一个按钮的消息处理扩展。简单起见,我们使其不产生命令、不绘制文本,仅仅只是展示对鼠标消息的处理和状态的变化而已。

我们将原先测试代码中的中间那个控件关联了按钮的消息处理,那么它就称为了一个按钮控件了。我们可以将鼠标移到它上面点击看看会发生什么。

下载测试工程代码 因为我一直都在使用VC10来编写Widget,也用到了一些新的特性,所以子啊这次的测试工程我生成了一份release下的程序,没有VC10的人至少能够看到其运行效果。

转载于:https://www.cnblogs.com/EvilGhost/archive/2011/04/24/Abstract_Widget_9.html

一步一步实现自己的模拟控件(9)——消息处理相关推荐

  1. 一步一步实现自己的模拟控件(6)——控件树及控件区域

    控件树 一步一步实现自己的模拟控件(1)中的图上我们可以看到,我们的控件体系其实就是一个控件树.每一个窗口关联一个根控件,所有控件都在这个根控件之下,父控件包容并管理子控件,那么我们的Widget就应 ...

  2. 2023-02-24 Android app java 模拟控件点击事件,使用performClick方法去实现

    一.Android app java 模拟控件点击事件,使用performClick方法去实现. 二.实际使用 private TextView m_bt_connect ;m_bt_connect ...

  3. 简单三步!教你用前端表格控件SpreadJS做购物车

    SpreadJS结合40余年专业控件技术和在电子表格应用领域的经验而推出的纯前端表格控件,基于 HTML5,兼容 450 多种 Excel 公式,具备"高性能.跨平台.与 Excel 高度兼 ...

  4. C# SSH Shell终端模拟控件Rebex SSH Shell详细介绍

    具备终端模拟的SSH Shell.这使您能简单地在Unix/Windows SSH服务器上执行命令或将终端模拟功能添加到您的应用程序之中. 100%可托管的代码 遵循CLS(通用语言规范) 稳定以及彻 ...

  5. 一步一步实现自己的模拟控件(5)——隐藏类

    隐藏驱动类: 为了让用户有更简单的使用接口,我们需要把不必要的东西进行一定的隐藏.前面我就提到WidgetDriver对于用户来说是不关心的东西,那么我们就将其进行隐藏. 方案1: 将WidgetDr ...

  6. 一步一步教你写一个快递查询APP(适合新手)

    前言: 水平:自学Android十五天,以前有过混日子的编程经验. 目标: <第一行代码>学完之后,总想写个APP,天气的APP写了个初版,后面再说,今天演示的是制作快递查询APP的整个经 ...

  7. 详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息

    Windows消息的分类 1. 标准消息(队列消息)   除WM_COMMAND之外,所有以WM_开头的消息都是标准消息,如WM_MOUSEMOVE.WM_LBUTTONUP.WM_KEYDOWN.W ...

  8. 【转】详解Windows消息分类以及WM_COMMAND与WM_NOTIFY的区别,以及模拟发送控件通知消息

    转自:http://blog.sina.com.cn/s/blog_4b3c1f950100nten.html Windows消息的分类 1. 标准消息(队列消息)   除WM_COMMAND之外,所 ...

  9. 一步一步学WF系列(四)——工作流模拟登陆

    1. 摘要 我们之前已经熟悉了关于WF的基本概念,相信各位也都跃跃欲试.想步入真正的WF开发. 从本文开始,我们就先来熟悉在WF中的活动. 2. 活动 WF的核心就是一系列的活动. 而工作流就是多个活 ...

最新文章

  1. 如何自制你自己的二极管
  2. python中rand和randn_rand、randn、randi区别及用法
  3. Windows四大傻X功能——那些拖慢系统性能的罪魁祸首
  4. Algorithm:C++语言实现之贪心法算法相关问题
  5. linux 多线程客户端服务端通信,[转载]多线程实现服务器和客户端、客户端和客户端通信;需要代码,留言...
  6. Hadoop学习之路(十三)MapReduce的初识
  7. 121 项目 024 笔记向 内省机制
  8. Spark history-server 配置 !运维人员的强大工具
  9. HDFS集群常见异常及排查步骤
  10. bootstrap from必填_bootstrap表单必填项
  11. Delphi10.2下载和安装详解教程(很全的教程)
  12. steam+linux+64+fedora,在fedora中安装steam游戏平台
  13. nodog+adbyby实现密码认证与视频广…
  14. stata面板数据单位根检验llc_stata面板单位根检验怎样看结果?LLC、ADF_Fisher以及IPS,求助...
  15. linux thinkphp5 php7.0禁用eval
  16. 75---Python绘制动态狄拉克delta函数
  17. Word、PPT、PDF 文件怎么批量插入首页、扉页、尾页?怎么在指定位置插入页?
  18. [渝粤教育] 西南科技大学 英语泛读 在线考试复习资料
  19. 周报-暑假留校第三份
  20. 数据中台全景架构及模块解析!一文入门中台架构师!

热门文章

  1. IDEA的Docker插件实战(Dockerfile篇)
  2. 2022-2028年中国农用塑料薄膜行业市场研究及前瞻分析报告
  3. OpenCV 笔记(03)— 读取视频、通过摄像头采集视频、采集视频 canny 边缘检测
  4. Git 常用操作(3)- 本地分之显示、创建、切换、合并和删除操作
  5. debian10 Unable to correct problems, you have held broken packages.
  6. RPC远程调用通俗理解
  7. CMD 输入中文看不到输入法的解决方法
  8. LeetCode简单题之判断字符串的两半是否相似
  9. LeetCode简单题之找到所有数组中消失的数字
  10. 部署可扩展的目标检测管道:推理过程(上)