**在开始阅读本文之前,如果您有学习创建Qt自定义控件并在其他项目中引用的需求,请参考:**
Linux系统下在Qt Creator中创建自定义控件并在其他项目中引用https://blog.csdn.net/YMGogre/article/details/128920804
1、应用场景:
- 当我们需要一个组合控件可以通过键盘输入或者打开Qt的颜色对话框来设置其他控件的颜色时;
2、所需资源:
(无,本质即 Qt 的几个自带控件的组合)
3、界面布局:
整体布局如下图所示,该自定义控件由一个GraphicsView、一个LineEdit、一个PushButton组成。窗口整体设置了 baseSize 为 140 × 25:
3.1、各布局/控件属性:
MyPalette属性
horizontalLayout属性
ColorDisplay属性
ColorLineEdit属性
btn_SelectColor属性
4、源代码:
4.1、h文件
/* mypalette.h */
#ifndef MYPALETTE_H
#define MYPALETTE_H
#include <QObject>
#include <QWidget>
#include <QColorDialog>
#include <QColor>
#include <QPalette>
#include <QString>
#include <QRegExpValidator>
#include <QtUiPlugin/QDesignerExportWidget>
#include <QEvent>
#include <QMouseEvent>
#include <QPushButton>
namespace Ui {
class MyPalette;
}
class QDESIGNER_WIDGET_EXPORT MyPalette : public QWidget
{
Q_OBJECT
public:
explicit MyPalette(QWidget *parent = nullptr);
~MyPalette();
QColor currentColor();
void setColor(int r, int g, int b, int a = 255);
void setColor(QColor color);
protected:
bool eventFilter(QObject *watchedm, QEvent *event) override; //重写事件过滤器方法
signals:
void colorchanged(QColor); //自定义颜色改变信号
private:
Ui::MyPalette *ui;
QColor color = QColor(Qt::white);
};
#endif // MYPALETTE_H
4.2、cpp文件
/* mypalette.cpp */
#include "mypalette.h"
#include "ui_mypalette.h"
MyPalette::MyPalette(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyPalette)
{
ui->setupUi(this);
//QGraphicsView的鼠标事件会传递给它所显示的QGraphicsScene,然后再传递给场景中的QGraphicsItem。我们设置该控件属性:传递给父对象做鼠标事件处理
ui->ColorDisplay->setAttribute(Qt::WA_TransparentForMouseEvents);
/*****************************************
* 为自定义控件的子控件安装该自定义控件的事件过滤器
****************************************/
ui->ColorLineEdit->installEventFilter(this);
ui->btn_SelectColor->installEventFilter(this);
/*使用正则表达式限制输入(正确输入格式应当形如 ———— "255; 255; 255",最后允许跟随一个分号以及一个0~255的alpha通道值)
* (2[0-4][0-9];?\\s?) ———— 限制输入200~249正整数(尾部允许跟随0~1个分号";"和空格" ")
* (25[0-5];?\\s?) ———— 限制输入250~255正整数(尾部允许跟随0~1个分号";"和空格" ")
* (1[0-9][0-9];?\\s?) ———— 限制输入100~199正整数(尾部允许跟随0~1个分号";"和空格" ")
* ([1-9]?[0-9];?\\s?) ———— 限制输入0~99正整数(尾部允许跟随0~1个分号";"和空格" ")
*/
ui->ColorLineEdit->setValidator(new QRegExpValidator(QRegExp("^((2[0-4][0-9];\\s?)|(25[0-5];\\s?)|(1[0-9][0-9];\\s?)|([1-9]?[0-9];\\s?)){0,3}((2[0-4][0-9])|(25[0-5])|(1[0-9][0-9])|([1-9]?[0-9]))?$")));
connect(ui->ColorLineEdit, &QLineEdit::textChanged, this, [=](){
//使用正则表达式删除字符串中所有空格
QString colorStr = ui->ColorLineEdit->text().remove(QRegExp("\\s"));
//使用split方法按";"分号分割字符串为字符串数组
QStringList colorStrList = colorStr.split(";");
//当LineEdit只有rgb的值时
if(colorStrList.size() == 3)
{
//使用字符串数组内容初始化一个QColor对象并赋值给color成员变量
color = QColor(colorStrList[0].toInt(), colorStrList[1].toInt(), colorStrList[2].toInt());
//当颜色改变时,发送“颜色改变信号”
emit colorchanged(color);
}
//当LineEdit除了rgb的值还有alpha通道的值时
else if(colorStrList.size() == 4)
{
//使用字符串数组内容初始化一个QColor对象并赋值给color成员变量
color = QColor(colorStrList[0].toInt(), colorStrList[1].toInt(), colorStrList[2].toInt(), colorStrList[3].toInt());
//当颜色改变时,发送“颜色改变信号”
emit colorchanged(color);
}
//获取调色板
QPalette pal = ui->ColorDisplay->palette();
//设置调色板
pal.setColor(QPalette::Base, color);
//设置控件底色
ui->ColorDisplay->setPalette(pal);
});
//当文本框编辑结束时,根据color成员变量显示其RGB字符串
connect(ui->ColorLineEdit, &QLineEdit::editingFinished, this, [=](){
//当alpha通道值为255(默认)时,LineEdit默认不显示alpha通道值
if(color.alpha() == 255)
{
QString colorStr = QString::number(color.red()) + "; " + QString::number(color.green()) + "; " + QString::number(color.blue());
ui->ColorLineEdit->setText(colorStr);
}
else
{
QString colorStr = QString::number(color.red()) + "; " + QString::number(color.green()) + "; " + QString::number(color.blue()) + "; " + QString::number(color.alpha());
ui->ColorLineEdit->setText(colorStr);
}
});
connect(ui->btn_SelectColor, &QPushButton::clicked, this, [=](){
//打开一个颜色对话框并将其返回值交给局部变量_color
QColor _color = QColorDialog::getColor();
//判断返回的颜色是否有效
if(_color.isValid())
{
//有效则改变颜色并发送信号
color = _color;
//当颜色改变时,发送“颜色改变信号”
emit colorchanged(color);
}
//根据对话框返回的颜色修改颜色展示方块的颜色
QPalette pal = ui->ColorDisplay->palette();
//设置调色板
pal.setColor(QPalette::Base, color);
//设置控件底色
ui->ColorDisplay->setPalette(pal);
//根据对话框返回的颜色获取RGB三色字符串
QString colorStr = QString::number(color.red()) + "; " + QString::number(color.green()) + "; " + QString::number(color.blue());
ui->ColorLineEdit->setText(colorStr);
});
}
/**
* @brief 获取当前颜色方法
* @return QColor ———— 返回当前QColor颜色对象
*/
QColor MyPalette::currentColor()
{
return color;
}
/**
* @brief 设置颜色方法
* @param int r ———— 红色
* @param int g ———— 绿色
* @param int b ———— 蓝色
* @param int a ———— Alpha通道值(0完全透明~255完全不透明)
*/
void MyPalette::setColor(int r, int g, int b, int a)
{
if(a == 255)
{
//设置RGB三色字符串
QString colorStr = QString::number(r) + "; " + QString::number(g) + "; " + QString::number(b);
//setText()方法也会触发QLineEdit的textChanged信号
ui->ColorLineEdit->setText(colorStr);
}
else
{
//设置RGB三色字符串
QString colorStr = QString::number(r) + "; " + QString::number(g) + "; " + QString::number(b) + "; " + QString::number(a);
//setText()方法也会触发QLineEdit的textChanged信号
ui->ColorLineEdit->setText(colorStr);
}
}
/**
* @brief 设置颜色方法
* @param QColor color ———— QColor颜色对象
*/
void MyPalette::setColor(QColor color)
{
if(color.alpha() == 255)
{
//设置RGB三色字符串
QString colorStr = QString::number(color.red()) + "; " + QString::number(color.green()) + "; " + QString::number(color.blue());
//setText()方法也会触发QLineEdit的textChanged信号
ui->ColorLineEdit->setText(colorStr);
}
else
{
//设置RGB三色字符串
QString colorStr = QString::number(color.red()) + "; " + QString::number(color.green()) + "; " + QString::number(color.blue()) + "; " + QString::number(color.alpha());
//setText()方法也会触发QLineEdit的textChanged信号
ui->ColorLineEdit->setText(colorStr);
}
}
/**
* @brief 重写事件过滤器方法
* @attention 这里简要说下为什么要重写该方法,这是因为当我们的自定义控件中有其他子控件时,
* 点击子控件的点击响应是相应到子控件上的,而通常我们希望所有子控件的父对象(也就是自定义控
* 件本身)也会在点击这些子控件时有响应
* @param QMouseEvent *event ———— 事件对象
*/
bool MyPalette::eventFilter(QObject *watched, QEvent *event)
{
//拦截子控件的鼠标按下或释放事件
if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)
{
//QEvent类型转换为QMouseEvent类型
QMouseEvent *mouseevent = static_cast<QMouseEvent *>(event);
this->QWidget::mousePressEvent(mouseevent); //调用基类的mousePressEvent方法
//如果事件的被监视对象是QPushButton
if(qobject_cast<QPushButton *>(watched))
this->setFocus(); //设置自定义控件本身获得焦点
return false; //传递事件给子控件,让其正常响应点击
//return true; //事件处理完毕(不传递事件给子控件,只响应自定义控件本身被选中)
}
//其他类型的事件交由基类处理
return QWidget::eventFilter(watched, event);
}
MyPalette::~MyPalette()
{
delete ui;
}
4.3、ui文件
❗ UI文件仅能在设计模式下编辑,这里仅供布局参考!
<!-- mypalette.ui -->
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MyPalette</class>
<widget class="QWidget" name="MyPalette">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>299</width>
<height>188</height>
</rect>
</property>
<property name="baseSize">
<size>
<width>140</width>
<height>25</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,0">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGraphicsView" name="ColorDisplay">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="baseSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="ColorLineEdit">
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>255; 255; 255</string>
</property>
<property name="maxLength">
<number>18</number>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_SelectColor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="baseSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
5、使用方法:
- 颜色选择组合控件封装了一个自定义信号 colorchanged,该信号会在颜色发生改变时被发送,使用该信号连接你的槽函数即可;
** colorchanged **信号是一个带参信号,可以传递一个 QColor 对象。比如说我们可以通过类似于以下的代码去设置一个 PushButton 控件的颜色:
connect(ui->myPalette, &MyPalette::colorchanged, this, [=](QColor color){ QPalette pal = ui->btn->palette(); //注:使用QPalette::Button枚举值设置按钮颜色时,alpha通道值是无效的 pal.setColor(QPalette::Button, color); ui->btn->setPalette(pal); });
- 通过 currentColor() 成员方法可以在代码里获取对象的颜色属性,该方法返回一个 QColor 对象;
- 通过 ***setColor() ***成员方法可以在代码里设置对象的颜色属性,该方法有一个重载;
当然,***setColor() ***成员方法也会触发发送 **colorchanged** 信号。
6、注意事项:
请参考文章:Qt自定义控件 —— 子控件与父控件的鼠标事件问题https://blog.csdn.net/YMGogre/article/details/129357734
💠本文提供的代码是已经解决了上面文章中涉及的问题后的代码。
7、源码下载:
CSDN下载:Qt自定义控件-颜色选择组合控件-C++文档类资源-CSDN文库https://download.csdn.net/download/YMGogre/87541452
版权归原作者 YMGogre 所有, 如有侵权,请联系我们删除。