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

相關文章
相關標籤/搜索