Qt学习笔记二:Qt经过重写paintEvent方法写一个自定义选择框

Qt经过重写paintEvent方法写一个自定义选择框

> 这几天导师下发任务,让我一个月以内熟悉一个经过Qt Widget制做的项目,第一眼看到项目,我是懵逼的。才知道本身写的那些几百行的代码算什么玩意了。看到项目里密密麻麻继承QWidget的控件,而后各类重写paintEvent方法,才发现本身彻底没有使用过Qt的绘图功能。好吧,开始学习吧!c++

前言

本文将会介绍如何经过重写QWidget类的paintEvent方法自定义一个CheckBox。固然有人问了,为何不使用QSS来设置CheckBox样式,搞个自定义这么复杂干吗?这个嘛,,,固然是闲得蛋疼了哈哈哈哈~函数

第一步:建立一个继承QWidget的对象

若要使用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-&gt;connect(this, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
}

鼠标点击事件以下:debug

// 没用到
void CheckBox::mousePressEvent(QMouseEvent *event)
{
}

void CheckBox::mouseReleaseEvent(QMouseEvent *event)
{
    isChecked = !isChecked; // 状态取反
    qDebug() &lt;&lt; "click status:" &lt;&lt; isChecked;
    emit clicked(isChecked); // 释放被点击信号,
}

onClicked槽函数以下:code

void CheckBox::onClicked()
{
    this-&gt;update();
}

这里的QWidget::update()槽函数用于刷新绘图。绘图刷新的具体流程下文会提到。orm

第二步:重写QWidget::paintEvent方法

直接贴代码:对象

void CheckBox::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    painter = new QPainter();
    painter-&gt;begin(this);
    
    // 建立一支笔,设置各类样式
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setWidth(2);
    pen.setStyle(Qt::SolidLine);
    pen.setColor("#fff");
    painter-&gt;setPen(pen);
    
    // 画一个正方形做为checkbox的框框
    painter-&gt;drawRect(4,4,10,10);

//    QStyleOption option;
//    option.initFrom(this);
//    this-&gt;style()-&gt;drawPrimitive(QStyle::PE_IndicatorCheckBox, &amp;option, painter, this);

    // 写checkbox边上的label
    QRect rect(12, -1, 50, 20);
    painter-&gt;drawText(rect, Qt::AlignCenter, QString::fromLocal8Bit("选择框"));

    // 判断checkbox是否被选中,则画一个NIKE
    if (isChecked) {
        QPoint points[] = {
            QPoint(2, 10),
            QPoint(7, 15),
            QPoint(17, 5)
        };
        painter-&gt;drawPolyline(points, 3);
    }
    painter-&gt;end();
}

这里读者会发现这几行注释:继承

QStyleOption option;
    option.initFrom(this);
    this-&gt;style()-&gt;drawPrimitive(QStyle::PE_IndicatorCheckBox, &amp;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控件图案。官方解释是: > 使用选项指定的样式选项,使用提供的画家绘制给定的基本元素。

跟我说的应该没有什么区别(逃)。

整个cpp文件放出

一个一个方法看太麻烦,因此:

#include "checkbox.h"
#include <qdebug>
#include <qpainter>
#include <qstyle>
#include <qstyleoption>

CheckBox::CheckBox(QWidget *parent) : QWidget(parent)
{
    this-&gt;connect(this, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
}

void CheckBox::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    painter = new QPainter();
    painter-&gt;begin(this);
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::RoundJoin);
    pen.setWidth(2);
    pen.setStyle(Qt::SolidLine);
    pen.setColor("#fff");
    painter-&gt;setPen(pen);
    painter-&gt;drawRect(4,4,10,10);

//    QStyleOption option;
//    option.initFrom(this);
//    this-&gt;style()-&gt;drawPrimitive(QStyle::PE_IndicatorCheckBox, &amp;option, painter, this);

    QRect rect(12, -1, 50, 20);
    painter-&gt;drawText(rect, Qt::AlignCenter, QString::fromLocal8Bit("选择框"));

    // 判断checkbox是否被选中,则画一个NIKE
    if (isChecked) {
        QPoint points[] = {
            QPoint(2, 10),
            QPoint(7, 15),
            QPoint(17, 5)
        };
        painter-&gt;drawPolyline(points, 3);
    }
    painter-&gt;end();
}

void CheckBox::mousePressEvent(QMouseEvent *event)
{
}

void CheckBox::mouseReleaseEvent(QMouseEvent *event)
{
    isChecked = !isChecked;
    qDebug() &lt;&lt; "click status:" &lt;&lt; isChecked;
    emit clicked(isChecked);
}

void CheckBox::onClicked()
{
    this->update();
}

bool CheckBox::getIsChecked() const
{
    return isChecked;
}

演示

本身画框框

image

使用drawPrimitive

image

相关文章
相关标签/搜索