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

 更新时间:2022年01月24日 09:02:11   作者:中国好公民st  
在使用Qt时,可能会遇到这种问题:多个控件互斥,类似于QRadiButton控件,但又不是单纯的QRadioButton控件,互斥的可能是一个窗口,也可能是几个按钮,等等多种情况。本文将介绍利用Qt自定义Widget实现的互斥效果,需要的可以参考一下

前沿

什么叫做自定义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实现互斥内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • win10系统VS2019配置点云库PCL1.12.1的详细流程

    win10系统VS2019配置点云库PCL1.12.1的详细流程

    这篇文章主要介绍了win10系统VS2019配置点云库PCL1.12.1的教程与经验总结,本文记录小白在配置过程中踩过的一些小坑,需要的朋友可以参考下
    2022-07-07
  • 看图深入理解单链表的反转

    看图深入理解单链表的反转

    今天遇到单向链表的反转的问题,于是静下心来好好想了一番。下面这篇文章主要给大家介绍了关于单链表反转的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02
  • C++ 命名空间详解

    C++ 命名空间详解

    这篇文章主要介绍了C++ 命名空间的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下
    2021-11-11
  • C语言如何利用异或进行两个值的交换详解

    C语言如何利用异或进行两个值的交换详解

    最近在工作中遇到了两个值交换的需求,发现自己对异或有些忘记,所以索性写出来,方便以后需要的时候参考学习,下面这篇文章主要给大家介绍了关于C语言如何利用异或进行两个值的交换的相关资料,需要的朋友可以参考下。
    2017-09-09
  • C++基于hook iat改变Messagebox实例

    C++基于hook iat改变Messagebox实例

    这篇文章主要介绍了C++基于hook iat改变Messagebox的方法,以实例形式展示了针对IAT(即导入地址表)以及hook的操作,有助于深入理解Windows程序设计原理,需要的朋友可以参考下
    2014-10-10
  • 约瑟夫环问题(数组法)c语言实现

    约瑟夫环问题(数组法)c语言实现

    这篇文章主要介绍了约瑟夫环问题(数组法)c语言实现,有需要的朋友可以参考一下
    2013-12-12
  • C/C++使用C语言实现多态

    C/C++使用C语言实现多态

    这篇文章主要介绍了C/C++多态的实现机制理解的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下,希望能给你带来帮助
    2021-08-08
  • 一文带你了解Qt中槽的使用

    一文带你了解Qt中槽的使用

    这篇文章主要为大家详细介绍了Qt中槽的使用教程,文中的示例代码讲解详细,对我们学习Qt有一定的帮助,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12
  • OpenCV实现简易标定板

    OpenCV实现简易标定板

    这篇文章主要为大家详细介绍了OpenCV实现简易标定板,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • C语言版五子棋游戏的实现代码

    C语言版五子棋游戏的实现代码

    这篇文章主要为大家详细介绍了C语言版五子棋游戏的实现代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07

最新评论