Qt編寫自定義控件62-探探雷達

1、前言

隨着移動互聯網的盛行,如今手機APP大行其道,每一個人的手機沒有十幾個APP都很差意思說本身是現代人,各類聊天、購物、直播、小視頻等APP,有個陌生人社交的APP叫探探,本人用過幾回,固然不是去爲了找對象,而是純粹爲了好玩研究下他的U設計和軟件邏輯流程等,其中有個雷達控件,單擊之後能夠搜索附近的異性進行配對,這個雷達控件的效果蠻好的,因而手癢琢磨着用Qt來實現一個,畢竟本身寫了150多個控件了,已經上癮了,對各類效果都如魚得水,看到各類效果都不天然的想到編碼思路等。 這個控件的核心其實就是外圍的那個掃描圈和發散的掃描線,中間變大變小恢復正常的圓形頭像,外圍的掃描圈採用錐形漸變顏色,經過透明度控制造成掃描效果,核心方法就是drawPie,至於擴散圈,須要識別到單擊之後將擴散圈存入隊列,由於可能會單擊屢次,產生多個擴散圈,至於中間頭像的動態效果,採用三個QPropertyAnimation來實現,一個負責變大,一個負責變小,一個負責恢復正常,而後三個動畫加入到QSequentialAnimationGroup動畫序列中,按照順序執行。linux

2、實現的功能

  • 1:可設置中間圖像
  • 2:可設置圖像的邊框寬度+邊框顏色,產生圓形圖像效果
  • 3:可設置掃描線的最大半徑
  • 4:可設置掃描線的邊框寬度
  • 5:可設置擴散圈的線條寬度
  • 6:可設置掃描線的每次移動的步長
  • 7:可設置擴散圈的每次移動的步長
  • 8:可設置掃描線的顏色
  • 9:可設置擴散圈的顏色

3、效果圖

4、頭文件代碼

#ifndef SCANTANTAN_H
#define SCANTANTAN_H

/**
 * 探探雷達控件 做者:東門吹雪(QQ:709102202) 整理:feiyangqingyun(QQ:517216493) 2019-10-01
 * 1:可設置中間圖像
 * 2:可設置圖像的邊框寬度+邊框顏色,產生圓形圖像效果
 * 3:可設置掃描線的最大半徑
 * 4:可設置掃描線的邊框寬度
 * 5:可設置擴散圈的線條寬度
 * 6:可設置掃描線的每次移動的步長
 * 7:可設置擴散圈的每次移動的步長
 * 8:可設置掃描線的顏色
 * 9:可設置擴散圈的顏色
 */

#include <QWidget>

class QSequentialAnimationGroup;

#ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif

class QDESIGNER_WIDGET_EXPORT ScanTanTan : public QWidget
#else
class ScanTanTan : public QWidget
#endif

{
    Q_OBJECT
    Q_PROPERTY(QPixmap image READ getImage WRITE setImage)
    Q_PROPERTY(int imageBorderWidth READ getImageBorderWidth WRITE setImageBorderWidth)
    Q_PROPERTY(QColor imageBorderColor READ getImageBorderColor WRITE setImageBorderColor)

    Q_PROPERTY(int scanRadius READ getScanRadius WRITE setScanRadius)
    Q_PROPERTY(int scanWidth READ getScanWidth WRITE setScanWidth)
    Q_PROPERTY(int ringWidth READ getRingWidth WRITE setRingWidth)

    Q_PROPERTY(int scanStep READ getScanStep WRITE setScanStep)
    Q_PROPERTY(int ringStep READ getRingStep WRITE setRingStep)

    Q_PROPERTY(QColor scanColor READ getScanColor WRITE setScanColor)
    Q_PROPERTY(QColor ringColor READ getRingColor WRITE setRingColor)

public:
    struct RingData {
        int radius;     //半徑
        float width;    //畫筆粗細
        int alpha;      //透明度
    };

    explicit ScanTanTan(QWidget *parent = 0);

protected:
    void mousePressEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
    void paintEvent(QPaintEvent *);
    void drawScan(QPainter *painter);
    void drawRing(QPainter *painter);
    void drawImage(QPainter *painter);

private slots:
    void changeScan();
    void changeRing();
    void updateImage(const QVariant &value);
    double twoPtDistance(const QPointF &pt1, const QPointF &pt2);

private:
    QPixmap image;          //中間圖片
    int imageBorderWidth;   //圖片邊框寬度
    QColor imageBorderColor;//圖片邊框顏色

    int scanRadius;         //掃描線最大半徑
    int scanWidth;          //掃描線邊框寬度
    int ringWidth;          //擴散圈線條寬度

    int scanStep;           //掃描線每次移動的步長
    int ringStep;           //擴散圈每次移動的步長

    QColor scanColor;       //掃描線顏色
    QColor ringColor;       //擴散圈顏色

    bool isPressed;         //鼠標是否按下
    int ringRadius;         //擴散圈半徑
    int imageRadius;        //圖片半徑
    int scanDeg;            //當前掃描線角度

    //擴散圈集合,鼠標可能按下屢次則產生多個擴散圈,用隊列存起來
    QList<RingData> rings;
    //動畫組合,用於中間圖片的變大放小
    QSequentialAnimationGroup *animationGroup;

public:
    QPixmap getImage()          const;
    int getImageBorderWidth()   const;
    QColor getImageBorderColor()const;

    int getScanRadius()         const;
    int getScanWidth()          const;
    int getRingWidth()          const;

    int getScanStep()           const;
    int getRingStep()           const;

    QColor getScanColor()       const;
    QColor getRingColor()       const;

    QSize sizeHint()            const;
    QSize minimumSizeHint()     const;

public Q_SLOTS:
    //設置圖片+圖片邊框寬度+圖片邊框顏色
    void setImage(const QPixmap &image);
    void setImageBorderWidth(int imageBorderWidth);
    void setImageBorderColor(const QColor &imageBorderColor);

    //設置掃描線最大半徑+掃描線邊框寬度+擴散圈線條寬度
    void setScanRadius(int scanRadius);
    void setScanWidth(int scanWidth);
    void setRingWidth(int ringWidth);

    //設置掃描線步長+擴散圈步長
    void setScanStep(int scanStep);
    void setRingStep(int ringStep);

    //設置掃描線顏色+擴散圈顏色
    void setScanColor(const QColor &scanColor);
    void setRingColor(const QColor &ringColor);
};

#endif // SCANTANTAN_H

5、核心代碼

void ScanTanTan::paintEvent(QPaintEvent *)
{
    int width = this->width();
    int height = this->height();
    int side = qMin(width, height);

    //繪製準備工做,啓用反鋸齒,平移座標軸中心,等比例縮放
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.translate(width / 2, height / 2);
    painter.scale(side / 200.0, side / 200.0);

    //繪製掃描線
    drawScan(&painter);
    //繪製擴散圈
    drawRing(&painter);
    //繪製中間圖片
    drawImage(&painter);
}

void ScanTanTan::drawScan(QPainter *painter)
{
    painter->save();

    //錐形漸變顏色,經過透明度控制造成掃描效果
    QConicalGradient conicalGradient(0, 0, scanDeg);
    QColor color = scanColor;
    color.setAlpha(50);
    conicalGradient.setColorAt(0, color);
    color.setAlpha(0);
    conicalGradient.setColorAt(1, color);

    //設置畫筆畫刷
    QPen pen;
    pen.setWidth(scanWidth);
    pen.setBrush(conicalGradient);
    painter->setPen(pen);
    painter->setBrush(conicalGradient);

    //繪製餅圓
    QRect rect(-scanRadius, -scanRadius, scanRadius * 2, scanRadius * 2);
    painter->drawPie(rect, scanDeg * 16, 360 * 16);

    painter->restore();
}

void ScanTanTan::drawRing(QPainter *painter)
{
    painter->save();
    painter->setBrush(Qt::NoBrush);

    //繪製全部擴散圈,擴散圈其實就是個沒有背景顏色的圓形
    for (int i = 0; i < rings.count(); i++) {
        RingData ring = rings.at(i);
        int radius = ring.radius;
        float width = ring.width;
        int alpha = 255 - ring.alpha;
        QColor color = ringColor;
        color.setAlpha(alpha);

        QPen pen;
        pen.setWidthF(width);
        pen.setColor(color);
        painter->setPen(pen);
        painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
    }

    painter->restore();
}

void ScanTanTan::drawImage(QPainter *painter)
{
    painter->save();

    //設置圓形遮罩路徑,產生圓形頭像效果
    QPainterPath path;
    path.addEllipse(QPoint(0, 0), imageRadius, imageRadius);
    painter->setClipPath(path);

    //繪製圖片
    QRect rect(-imageRadius, -imageRadius, imageRadius * 2, imageRadius * 2);
    painter->drawPixmap(rect, image);

    //繪製圖片邊緣圓形
    QPen pen;
    pen.setWidth(imageBorderWidth);
    pen.setColor(imageBorderColor);
    painter->setPen(pen);
    painter->setBrush(Qt::NoBrush);

    //如下兩種方法二選一,其實繪製360度的圓弧=繪製無背景的圓形
    //painter->drawArc(rect, 0, 360 * 16);
    painter->drawEllipse(rect);

    painter->restore();
}

6、控件介紹

  1. 超過160個精美控件,涵蓋了各類儀表盤、進度條、進度球、指南針、曲線圖、標尺、溫度計、導航條、導航欄,flatui、高亮按鈕、滑動選擇器、農曆等。遠超qwt集成的控件數量。
  2. 每一個類均可以獨立成一個單獨的控件,零耦合,每一個控件一個頭文件和一個實現文件,不依賴其餘文件,方便單個控件以源碼形式集成到項目中,較少代碼量。qwt的控件類環環相扣,高度耦合,想要使用其中一個控件,必須包含全部的代碼。
  3. 所有純Qt編寫,QWidget+QPainter繪製,支持Qt4.6到Qt5.13的任何Qt版本,支持mingw、msvc、gcc等編譯器,支持任意操做系統好比windows+linux+mac+嵌入式linux等,不亂碼,可直接集成到Qt Creator中,和自帶的控件同樣使用,大部分效果只要設置幾個屬性便可,極爲方便。
  4. 每一個控件都有一個對應的單獨的包含該控件源碼的DEMO,方便參考使用。同時還提供一個全部控件使用的集成的DEMO。
  5. 每一個控件的源代碼都有詳細中文註釋,都按照統一設計規範編寫,方便學習自定義控件的編寫。
  6. 每一個控件默認配色和demo對應的配色都很是精美。
  7. 超過130個可見控件,6個不可見控件。
  8. 部分控件提供多種樣式風格選擇,多種指示器樣式選擇。
  9. 全部控件自適應窗體拉伸變化。
  10. 集成自定義控件屬性設計器,支持拖曳設計,所見即所得,支持導入導出xml格式。
  11. 自帶activex控件demo,全部控件能夠直接運行在ie瀏覽器中。
  12. 集成fontawesome圖形字體+阿里巴巴iconfont收藏的幾百個圖形字體,享受圖形字體帶來的樂趣。
  13. 全部控件最後生成一個動態庫文件(dll或者so等),能夠直接集成到qtcreator中拖曳設計使用。
  14. 目前已經有qml版本,後期會考慮出pyqt版本,若是用戶需求量很大的話。
  15. 自定義控件插件開放動態庫使用(永久免費),無任何後門和限制,請放心使用。
  16. 目前已提供26個版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
  17. 不按期增長控件和完善控件,不按期更新SDK,歡迎各位提出建議,謝謝!
  18. Qt入門書籍推薦霍亞飛的《Qt Creator快速入門》《Qt5編程入門》,Qt進階書籍推薦官方的《C++ GUI Qt4編程》。
  19. 強烈推薦程序員自我修養和規劃系列書《大話程序員》《程序員的成長課》《解憂程序員》,受益不淺,受益終生!
  20. SDK地址:https://gitee.com/feiyangqingyun/QUCSDK
相關文章
相關標籤/搜索