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

news/2024/6/30 15:28:47

这次我们将要给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实现进展缓慢,因此我通常都会省略一些内容,这些内容也就只能通过代码阅读来得到了。

按钮:

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

2011042410321772.png

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pgtn.cn/news/17447.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

ES集群状态、节点、索引等查看及根据字段、排序查询

ES集群基础&#xff1a; 1. 查看集群&#xff1a; http://172.xxx.xxx.8:92002. 查看状态&#xff1a; http://172.xxx.xxx.8:9200/_cat/health?v3. 查看索引&#xff1a; http://172.xxx.xxx.8:9200/_cat/indices?v4. 查看节点&#xff1a; http://172.xxx.xxx.8:9200/…

【点云空间索引】python-pcl:KdTree与八叉树

1. 点云是什么 通过雷达、激光扫描、立体摄像机等三维测量设备获得的点云数据&#xff0c;具有数据量大、分布不均匀等特点。 点云数据主要是表征目标表面的海量点集合&#xff0c;并不具备传统实体网格数据的几何拓扑信息。点云处理中最核心的问题就是建立离散点间的拓扑结构&…

【点云StatisticalOutlierFilter】python-pcl:去除离群点

点云去除离群点 方法&#xff1a;StatisticalOutlierFilter 原理&#xff1a;使用K近邻方法找到点云中每个点k近邻&#xff0c;计算出标准距离&#xff1b;设置俩个点之间距离超过标准距离*std倍数的为离群点。 结果&#xff1a;将点云分为俩部分&#xff0c;内点以及离群点…

Postgresql: 时间戳long,TimeStamp,Date,String互转

今天遇到一个神奇的问题&#xff1a;Postgre数据库里存的 10位long类型的时间戳&#xff0c;拿Java代码转完的日期年月日时分秒&#xff0c;转出来的时间和在pgAdmin里用sql转完的日期 整整差了8个小时。。。。。 你不信吗&#xff1f; 请看图 时间戳&#xff1a;1598619305 转…

Open3D DbScanClustering聚类算法及聚类分簇可视化及存储

DBSCAN聚类算法&#xff0c;是基于密度的聚类算法。该算法需要两个参数。 labels np.array(pcd.cluster_dbscan(eps0.02, min_points10, print_progressTrue)) 入参&#xff1a; eps&#xff1a; 定义到聚类邻居的距离min_points&#xff1a; 定义形成聚类所需的最小点数。 出…

端口01 - 零基础入门学习汇编语言67

第十四章&#xff1a;端口01 让编程改变世界 Change the world by program 引言 CPU可以直接读写3 个地方的数据 &#xff08;1&#xff09;CPU 内部的寄存器&#xff1b; &#xff08;2&#xff09;内存单元&#xff1b; &#xff08;3&#xff09;端口。 这一章&#xff0c…

【点云重采样Resampling】Python-pcl 基于多项式平滑点云及法线估计的曲面重建

1. 点云重采样 基于多项式平滑点云及法线估计的曲面重建以实现重采样&#xff0c;可以使得点云数据更规整一些&#xff0c;没之前那么杂乱。 set_Compute_Normals(True) 可以通过在最小二乘法中进行法线估计&#xff0c;提高重采样准确度&#xff1b;set_polynomial_fit(True…

Open3D KdTree建立、3种近邻搜索及结果可视化

1. 点云索引 Open3D KdTree,可以快速的在无序的点云中建立空间拓扑结构,使得能迅速的进行近邻搜索; 2. 近邻方法分类: Open3D这边支持的近邻搜索方法由VTK实现; K近邻搜索(K Nearest Neighbors Search)半径近邻搜索(Radius Nearest Neighbors Search)混合近邻搜索(…