> 这几天导师下发任务,让我一个月以内熟悉一个经过Qt Widget制做的项目,第一眼看到项目,我是懵逼的。才知道本身写的那些几百行的代码算什么玩意了。看到项目里密密麻麻继承QWidget的控件,而后各类重写paintEvent方法,才发现本身彻底没有使用过Qt的绘图功能。好吧,开始学习吧!c++
本文将会介绍如何经过重写QWidget类的paintEvent方法自定义一个CheckBox。固然有人问了,为何不使用QSS来设置CheckBox样式,搞个自定义这么复杂干吗?这个嘛,,,固然是闲得蛋疼了哈哈哈哈~函数
若要使用Qt的绘图功能,就须要建立一个继承自QPaintDevice的类,包括QWidget、QImage、QPixmap等。这里咱们重点说一下QWidget,不少控件都继承自QWidget,咱们能够操做的如QLineEdit、QAbstractButton无一例外的继承自QWidget。这就觉得着咱们自己能够经过重写QWidget对象中的方法来实现注入Button的操做。本文编写了一个CheckBox类,代码以下:学习
#ifndef CHECKBOX_H #define CHECKBOX_H #include <qobject> #include <qwidget> class CheckBox : public QWidget { Q_OBJECT public: explicit CheckBox(QWidget *parent = nullptr); bool getIsChecked() const; protected: virtual void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; virtual void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE; Q_SIGNALS: void clicked(bool isChecked); public Q_SLOTS: void onClicked(); private: bool isChecked = false; QPainter *painter; }; #endif // CHECKBOX_H
这里注意的是我重写了paintEvent方法和鼠标点击和释放方法。isCheckedbool值用来储存checkbox的选中状态。this
构造函数以下:翻译
CheckBox::CheckBox(QWidget *parent) : QWidget(parent) { this->connect(this, SIGNAL(clicked(bool)), this, SLOT(onClicked())); }
鼠标点击事件以下:debug
// 没用到 void CheckBox::mousePressEvent(QMouseEvent *event) { } void CheckBox::mouseReleaseEvent(QMouseEvent *event) { isChecked = !isChecked; // 状态取反 qDebug() << "click status:" << isChecked; emit clicked(isChecked); // 释放被点击信号, }
onClicked槽函数以下:code
void CheckBox::onClicked() { this->update(); }
这里的QWidget::update()槽函数用于刷新绘图。绘图刷新的具体流程下文会提到。orm
直接贴代码:对象
void CheckBox::paintEvent(QPaintEvent *event) { Q_UNUSED(event); painter = new QPainter(); painter->begin(this); // 建立一支笔,设置各类样式 QPen pen; pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); pen.setWidth(2); pen.setStyle(Qt::SolidLine); pen.setColor("#fff"); painter->setPen(pen); // 画一个正方形做为checkbox的框框 painter->drawRect(4,4,10,10); // QStyleOption option; // option.initFrom(this); // this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, this); // 写checkbox边上的label QRect rect(12, -1, 50, 20); painter->drawText(rect, Qt::AlignCenter, QString::fromLocal8Bit("选择框")); // 判断checkbox是否被选中,则画一个NIKE if (isChecked) { QPoint points[] = { QPoint(2, 10), QPoint(7, 15), QPoint(17, 5) }; painter->drawPolyline(points, 3); } painter->end(); }
这里读者会发现这几行注释:继承
QStyleOption option; option.initFrom(this); this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, this);
QStyleOption在开发文档中是这样描述的: > QStyleOption and its subclasses contain all the information that QStyle functions need to draw a graphical element.
意思是QStyleOption和它的子类包含了全部QStyle须要画一个图形元素的函数的全部信息。
initFrom方法描述我就直接翻译给各位看官: > QStyleOption.initFrom(const QWidget *widget)根据指定的窗口小部件初始化state,direction,rect,palette,fontMetrics和styleObject成员变量。
QStyle::drawPrimitive方法让开发者快速绘画出系统Qt控件图案。官方解释是: > 使用选项指定的样式选项,使用提供的画家绘制给定的基本元素。
跟我说的应该没有什么区别(逃)。
一个一个方法看太麻烦,因此:
#include "checkbox.h" #include <qdebug> #include <qpainter> #include <qstyle> #include <qstyleoption> CheckBox::CheckBox(QWidget *parent) : QWidget(parent) { this->connect(this, SIGNAL(clicked(bool)), this, SLOT(onClicked())); } void CheckBox::paintEvent(QPaintEvent *event) { Q_UNUSED(event); painter = new QPainter(); painter->begin(this); QPen pen; pen.setCapStyle(Qt::RoundCap); pen.setJoinStyle(Qt::RoundJoin); pen.setWidth(2); pen.setStyle(Qt::SolidLine); pen.setColor("#fff"); painter->setPen(pen); painter->drawRect(4,4,10,10); // QStyleOption option; // option.initFrom(this); // this->style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter, this); QRect rect(12, -1, 50, 20); painter->drawText(rect, Qt::AlignCenter, QString::fromLocal8Bit("选择框")); // 判断checkbox是否被选中,则画一个NIKE if (isChecked) { QPoint points[] = { QPoint(2, 10), QPoint(7, 15), QPoint(17, 5) }; painter->drawPolyline(points, 3); } painter->end(); } void CheckBox::mousePressEvent(QMouseEvent *event) { } void CheckBox::mouseReleaseEvent(QMouseEvent *event) { isChecked = !isChecked; qDebug() << "click status:" << isChecked; emit clicked(isChecked); } void CheckBox::onClicked() { this->update(); } bool CheckBox::getIsChecked() const { return isChecked; }
本身画框框
使用drawPrimitive