Qt自定义Widget实现互斥效果详解

目录
  • 前沿
  • 功能实现
    • 知识点
    • 问题
    • 讲解知识点1
    • 讲解知识点2
    • 讲解知识点3
  • 总结

前沿

什么叫做自定义Widget实现互斥效果呢?

在使用Qt做一个界面美观性比较强的功能时,可能会遇到这种问题:多个控件互斥,类似于QRadiButton控件,但又不是单纯的QRadioButton控件,互斥的可能是一个窗口,也可能是几个按钮,等等多种情况。

这里我只是列举了一个简单的互斥例子,虽然简单,但是包含了各种坑,有需要的掘友们可以小笔记们记一下,尤其是对Qt新手来说,还是很有必要的。

由效果图可以看出创建了3个自定义widget,点击其中一个时,另外两个背景色以及文本颜色变化,处于选中状态。

接下来,针对效果图展示的功能进行逐一讲解,包含了知识点以及踩坑记录。

功能实现

实现自定义互斥widget过程中遇到了如下知识点以及问题,看看有没有你曾经遇到的或者是刚好需要的功能吧!

知识点

1:Widget模拟按钮的四态功能,包括了:常态、按下、聚焦、禁用

2:Widget自定义类的背景色设置以及文本内容风格设置

3:如何让多个widget实现互斥效果

问题

1:自定义Widget背景色设置之后为什么不生效?

针对上述知识点以及问题来讲述这个简单的功能吧!

讲解知识点1

使用Widget模拟按钮的四态功能,需要用到Widget自身的消息:鼠标按下,鼠标进入、鼠标离开。

virtual void mousePressEvent(QMouseEvent *event); //鼠标按下响应消息
virtual void enterEvent(QEvent *event); //鼠标进入响应消息
virtual void leaveEvent(QEvent *event); //鼠标离开响应消息

有没有人会问道,为什么没有mouseMoveEvent消息?

解答:在Qt中直接使用mouseMoveEvent消息鼠标是无法触发的,必须要设置setMouseTracking(true)让鼠标跟踪事件在当前窗口处于有效状态。

根据使用的具体情况是否需要设置这个功能。当前的小demo中,只是做图片的转换,没有必要在mouseMove中一直消耗资源。

(题外话:在MFC框架下的鼠标mosemove事件是直接可用的不需要进行特殊设置)

鼠标进入到widget之后,就可以标记为鼠标一直在该widget中活动,除非触发了leaveEvent消息。

鼠标按下响应消息

void QCustomWidget::mousePressEvent(QMouseEvent *event)
{
	this->SetWidgetStyle(Style_Down);
	QWidget::mousePressEvent(event);
}

当前采用的枚举类型:鼠标按下响应。

鼠标进入widget响应消息

void QCustomWidget::enterEvent(QEvent *event)
{
	this->SetWidgetStyle(Style_Focus);
	QWidget::enterEvent(event);
}

当前采用的枚举类型:鼠标聚焦状态,使用进入消息代替了mousemove消息。

如果大家打日志会发现,该触发函数只会在鼠标进入的时候走一次,当鼠标持续在widget内部移动时是不触发的,极大的减少了消息处理。

鼠标离开widget响应消息

void QCustomWidget::leaveEvent(QEvent *event)
{
	this->SetWidgetStyle(Style_Normal);
	QWidget::leaveEvent(event);
}

当前采用的枚举类型:鼠标离开状态。

我只是展示了最简单的离开设置,有一点需要考虑,当前widget如果处于按下状态,此刻鼠标离开了,该如何展示呢?

难道还要显示常态风格吗?

答案肯定是NO!

虽然鼠标已经移开,但是选中状态已经由常态变成了按下状态。在程序中我们需要用一个bool值变量来记录当前widget是否已经被选中过,如果选中过,当鼠标离开时就需要更改为选中状态

修改如下所示:

if (m_bClickedState == true)
{
	this->SetWidgetStyle(Style_Down);
}
else
	this->SetWidgetStyle(Style_Normal);

讲解知识点2

在程序中对于模拟的状态采用了枚举的类型进行表示。

类型 说明
Style_Normal 鼠标未做任何操作的初始状态
Style_Down 鼠标在wiget中进行了按下操作
Style_Focus 鼠标在widget中进行移动时操作状态
Style_Disable 当前widget处于进行状态

每一个widget中都展示了相同的内容:编号,文本

因为只是做了展示功能,所以全部使用了QLabel控件

QLabel *m_labNumber; //编号类指针

QLabel *m_LabContent; //内容类指针

对应的实际处理

void QCustomWidget::SetWidgetStyle(ENUM_WidgetStyle enumStyle)
{
	//TODO:设置widget风格
	QString qsStyle = "", gStyleNumberNormal = "", gStyleContentNormal = "";
	switch (enumStyle)
	{
	case Style_Normal: //常态显示
	{
		//设置:背景
		qsStyle = "QWidget{background-color:#FFD700}";
		//设置:编号风格
		gStyleNumberNormal = "QLabel{color:#666666; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
		//设置:内容风格
		gStyleContentNormal = "QLabel{color:#666666; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
	}
		break;
	case Style_Down: //按下
	{
		//设置:背景
		qsStyle = "QWidget{background-color:#FFB6C1}";
		//设置:编号风格
		gStyleNumberNormal = "QLabel{color:#0000FF; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
		//设置:内容风格
		gStyleContentNormal = "QLabel{color:#00FFFF; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
	}
		break;
	case Style_Focus: //聚焦
	{
		//设置:背景
		qsStyle = "QWidget{background-color:#FFF0F5}";
		//设置:编号风格
		gStyleNumberNormal = "QLabel{color:#98FB98; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
		//设置:内容风格
		gStyleContentNormal = "QLabel{color:#98FB98; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
	}
		break;
	case Style_Disable: //禁用
	{
		//设置:背景
		qsStyle = "QWidget{background-color:#DCDCDC}";
		//设置:编号风格
		gStyleNumberNormal = "QLabel{color:#696969; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
		//设置:内容风格
		gStyleContentNormal = "QLabel{color:#696969; font-family:Microsoft YaHei UI; font-size:14px;} QLabel{background-color: transparent}";
	}
		break;
	default:
		break;
	}
	this->setStyleSheet(qsStyle);
	m_labNumber->setStyleSheet(gStyleNumberNormal);
	m_labContent->setStyleSheet(gStyleContentNormal);
}

根据不同的类型对应的背景风格也不同。大家可以将代码带入,运行查看下效果,是不是跟我展示的效果一致呢?

哈哈!如果你尝试了,就会发现是这个样子的效果:

为什么只能显示文字,我的背景呢?去了哪里?我不是已经设置了吗?

很多Qt新手在这里都会遇到这样的问题,于是开启了各种搜索模式,尝试各种方法,有的时候改着改着就对了,也就忽略了这个问题。

当我们创建一个自定义widget时,通用的方法使用new实例的方式,在new的过程中,为了层级关系好打理已经父子关系明确,都会传入this作为新创建窗口的父指针。

一旦我们传入了this指针之后,并未在自定义Widget中做任何处理时,此时就会出现这样的情况。

子类继承了父窗口的风格样式。

一般遇到这种情况时,会有两种处理方式:重写当前窗口的paintEvent函数,设置不沿用父窗口风格

为了方便起见,当窗口绘制的背景图不复杂的情况下都会采用第二种方式设置:

this->setAttribute(Qt::WA_StyledBackground);

在当前自定义widget类构造函数中设置上述代码后,之前出现的设置了背景风格却看不见的问题就迎刃而解了。

讲解知识点3

如何实现多个widget之间的互斥呢?

使用过QRadioButton控件的掘友们都知道,该控件想要设置互斥只需要简单的设置函数就可以了。

对于我们自定义的widget来说,是不存在这种函数的,互斥效果只能是手动用代码设置并根据选中与非选中状态来更换对应的展示效果。

假设,当前选中了“内容1”的自定义Widget,此时需要在Widget中鼠标按下响应中触发一个消息,通知外界,当前自定义Widget做了按下操作,需要做特殊的处理

void QCustomWidget::mousePressEvent(QMouseEvent *event)
{
	this->SetWidgetStyle(Style_Down);
	emit Msg_SendClicked();
	QWidget::mousePressEvent(event);
}

在调用自定义Widget的父类中响应对应的槽函数做特殊处理。

总结

到这里实现自定义Widget互斥效果就简单实现了。

对于互斥操作的实现很简单,最最需要掌握的就是如何设置widget的背景。

很多情况下子窗口与父窗口嵌套层级过多时,这种问题最容易出现了,因为我们在每次创建一个新widget对象时,最好的方式每次都不沿用父窗口的样式。

到此这篇关于Qt自定义Widget实现互斥效果详解的文章就介绍到这了,更多相关Qt Widget实现互斥内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C/C++ Qt TreeWidget 单层树形组件应用小结

    TreeWidget 目录树组件,该组件适用于创建和管理目录树结构,在开发中我们经常会把它当作一个升级版的ListView组件使用,因为ListView每次只能显示一列数据集,而使用TableWidget组件显示多列显得不够美观,此时使用Tree组件显示单层结构是最理想的方式,本章博文将通过TreeWidget实现多字段显示,并增加一个自定义菜单,通过在指定记录上右键可弹出该菜单并对指定记录进行操作. 1.通过TreeView组件实现一个只读属性的树形目录,该目录中指定三个字段,分别用来表示ID

  • C/C++表格组件Qt TableWidget应用详解

    TableWidget 表格结构组件,该组件可以看作是TreeWidget树形组件的高级版,表格组件相比于树结构组件灵活性更高,不仅提供了输出展示二维表格功能,还可以直接对表格元素直接进行编辑与修改操作,表格结构分为表头,表中数据两部分,表格结构可看作一个二维数组,通过数组行列即可锁定特定元素,如下代码是针对表格结构的基本使用方法,分别实现了表头数据的初始化,元素的插入等基本操作. 在研究Widget组件之前先来熟悉一下View组件,View组件相对Widget组件来说只是不具备编辑功能,其他功

  • C/C++ Qt 选择夹TabWidget组件实现导航栏切换

    目录 在Qt中通过使用选择夹组件可以实现在一个页面中集成多种功能,我们以TabWidget选择夹组件为例,实现在单个页面中集成多个功能,并给每一个子夹增加对应的Ico图标. 如果我们使用选择夹组件,必须提前拖入UI界面中(无法代码生成),如下我们找到TabWidget并将其拖入UI界面中. 其次需要增加与美化代码对应的子夹数量,这里我们分别增加三个子夹,此处只需要增加不需要重命名. 接着我们需要增加三个子夹对应的图标组,插入图标组需要执行以下步骤. 选择Forms → 右键(AddNew) →

  • C/C++中使用列表框组件Qt ListWidget

    ListWidget列表框组件,该组件与TreeWidget有些相似,区别在于TreeWidget可以实现嵌套以及多字段结构,而ListWidget组件则只能实现单字段结构,ListWidget组件常用于显示单条记录,例如只显示IP地址,用户名等数据,如下笔记是本人在开发中经常用到的一些基本操作技巧,包括列表框组件的基本操作方法. 常用节点间的操作方法如下: ListView 组件与应用基础 ListWidget 初始化 ListWidget 变化行(触发事件) ListWidget 编辑状态设

  • C/C++ Qt TreeWidget 嵌套节点操作使用

    目录 简单的节点遍历 初始化树形节点 单击双击节点反馈 添加 父节点/子节点 删除选中节点 修改指定节点名称 枚举所有节点元素 枚举选中节点元素 获取选中子节点的父节点 在上一篇博文<C/C++ Qt TreeWidget 单层树形组件应用>中给大家演示了如何使用TreeWidget组件创建单层树形结构,并给这个树形组件增加了右键菜单功能,接下来将继续延申树形组件的使用,并实现对树形框多节点的各种操作. 常用树形框节点间的操作方法如下: 节点遍历 初始化节点 单击双击节点 添加根节点 添加子节

  • Qt自定义Widget实现互斥效果详解

    目录 前沿 功能实现 知识点 问题 讲解知识点1 讲解知识点2 讲解知识点3 总结 前沿 什么叫做自定义Widget实现互斥效果呢? 在使用Qt做一个界面美观性比较强的功能时,可能会遇到这种问题:多个控件互斥,类似于QRadiButton控件,但又不是单纯的QRadioButton控件,互斥的可能是一个窗口,也可能是几个按钮,等等多种情况. 这里我只是列举了一个简单的互斥例子,虽然简单,但是包含了各种坑,有需要的掘友们可以小笔记们记一下,尤其是对Qt新手来说,还是很有必要的. 由效果图可以看出创

  • Qt实现小功能之复杂抽屉效果详解

    目录 功能讲解 自定义标题widget 标题名称控件的创建 QCheckBox控件的创建 自定义内容Widget 创建显示高度描述控件 QScrollArea中widget实现 QScrollArea子窗口的提升 在Qt自带的控件中,也存在抽屉控件:QToolBar.但是,该控件有个缺点:一次只能展开一个抽屉信息,无法实现多个展开.为此,实现了如下效果的程序: 下面对这种实现效果进行讲解~ 功能讲解 开发环境:VS2017 + Qt5.14.2 64位 实现的核心技术: 1:QScrollAre

  • Android通过自定义view实现刮刮乐效果详解

    前言 已经有两个月没有更新博客了,其实这篇文章我早在两个月前就写好了,一直保存在草稿箱里没有发布出来.原因是有一些原理性的东西还没了解清楚,最近抽时间研究了一下混合模式,终于也理解了刮刮乐是怎么实现的,所以想继续分享一下自己的一些心得,先上效果图. 效果图: 实现原理 其实刮刮乐实现原理也不算很复杂,最关键的还是需要了解Paint的混合模式.因为刮刮乐是由两个bitmap组成的,一个是源图另一个是目标图,我们需要把目标图的颜色改成灰色,在源图上面盖上了一张灰色的目标图.当手指滑动屏幕时paint

  • C/C++ Qt TabWidget 实现多窗体创建详解

    在开发窗体应用时通常会伴随分页,TabWidget组件配合自定义Dialog组件,可实现一个复杂的多窗体分页结构,此类结构也是ERP等软件通用的窗体布局方案. 首先先来实现一个只有TabWidget分页的简单结构,如下窗体布局,布局中空白部分是一个TabWidget组件,下方是一个按钮,当用户点击按钮时,自动将该窗体新增到TabWidget组件中. 该页面关联代码如下所示,当用户点击on_pushButton_clicked()时自动新增一个窗体并将窗体的Tab设置为指定的IP地址. t->se

  • QT实现贪吃蛇游戏代码详解

    目录 一.新建一个Qt项目 二.添加要用到的头文件 三.写类声明信息 四.对类函数的实现 构造函数 界面刷新 随机奖励的生成 移动 绘图 按键事件 判断蛇身是否相撞 五.结束 一.新建一个Qt项目 新建Qt Widgets Application,项目名称为HappySnake,基类选择QWidget,类名默认 二.添加要用到的头文件 #include <QKeyEvent> #include <QRectF> #include <QPainter> #include

  • Flutter利用Canvas绘制精美表盘效果详解

    目录 前言 初始化 面板 刻度 刻度线 刻度值 指针 时针 分针 秒针 动起来 前言 趁着周末空闲时间使用 Flutter 的 Canvas制作了一个精美表盘. 最终实现的效果还不错,如下: 前面说到使用 Canvas 实现该表盘效果,而在 Flutter 中使用 Canvas 更多的则是继承 CustomPainter 类实现 paint 方法,然后在 CustomPaint 中使用自定义实现的 CustomPainter. 比如这里创建的 DialPainter 使用如下: @overrid

  • Android Flutter实现五种酷炫文字动画效果详解

    目录 前言 波浪涌动效果 波浪线跳动文字组 彩虹动效 滚动广告牌效果 打字效果 其他效果 自定义效果 总结 前言 偶然逛国外博客,看到了一个介绍文字动画的库,进入 pub 一看,立马就爱上这个动画库了,几乎你能想到的文字动画效果它都有!现在正式给大家安利一下这个库:animated_text_kit.本篇我们介绍几个酷炫的效果,其他的效果大家可以自行查看官网文档使用. 波浪涌动效果 波浪涌动 上面的动画效果只需要下面几行代码,其中loadUntil用于控制波浪最终停留的高度,取值是0-1.0,如

  • Android 菜单栏DIY实现效果详解

    目录 前言 实现的效果和思路 1. 绘制底部布局 2. 添加子view 3. 处理事件分发 4. 做个动画 5. 小结 前言 个人打算开发个视频编辑的APP,然后把一些用上的技术总结一下,这次主要是APP的底部菜单栏用到了一个自定义View去绘制实现的,所以这次主要想讲讲自定义View的一些用到的点和自己如何去DIY一个不一样的自定义布局. 实现的效果和思路 可以先看看实现的效果 两个页面的内容还没做,当前就是一个Demo,可以看到底部的菜单栏是一个绘制出来的不规则的一个布局,那要如何实现呢.可

  • Android自定义view实现侧滑栏详解

    目录 前言 需求 效果图 编写代码 主要问题 前言 上一篇文章学了下自定义View的onDraw函数及自定义属性,做出来的滚动选择控件还算不错,就是逻辑复杂了一些.这篇文章打算利用自定义view的知识,直接手撕一个安卓侧滑栏,涉及到自定义LayoutParams.带padding和margin的measure和layout.利用requestLayout实现动画效果等,有一定难度,但能重新学到很多知识! 需求 这里类似旧版QQ(我特别喜欢之前的侧滑栏),有两层页面,滑动不是最左侧才触发的,而是从

  • Flutter Widget 之FocusableActionDetector使用详解

    目录 Material按钮 GestureDetector自定义按钮 为按钮添加一些条件性的样式 Material按钮 Material按钮会很好 但我们知道它们不一定适合你的应用程序,所以你要自己编写.可悲的是,从头开始编写自己的空间可能是一项艰巨的工作. 桌面用户期待悬停高亮.焦点和键盘快捷键,这是很难做好的. GestureDetector自定义按钮 是这样的,你在你的应用程序中创建一个自定义的按钮, 使用GestureDetector,当你点击它的时候,按钮会做一些事情 GestureD

随机推荐