Qt編寫自定義控制元件30-顏色多型按鈕
阿新 • • 發佈:2019-07-15
一、前言
這個控制元件一開始打算用樣式表來實現,經過初步的探索,後面發現還是不夠智慧以及不能完全滿足需求,比如要在此控制元件設定多個角標,這個用QSS就很難實現,後面才慢慢研究用QPainter來繪製,我記得當時接到這個定製控制元件任務的時候是2016年,那時候對QPainter的使用還不是很熟悉,也就是從此控制元件開始,逐步研究QPainter的繪製,把所有的內建函式都使用一遍,最終用的越來越熟悉,使得後來到了心中有座標,萬物皆painter的境界,可能就像武林中所說的打通了任督二脈吧。 本控制元件除了可以設定常規的圓角角度,邊框寬度,邊框顏色,正常顏色,按下顏色以外,還可以設定各個角標和正文文字內容/字型/對齊方式/顏色,同時還要提供三種顏色展示模式,鬆開按下兩種顏色,按下鬆開顏色上下交替,按下鬆開顏色漸變交替。QLinearGradient是個好東西,各種顏色交替效果全靠它來實現。
二、實現的功能
- 1:可設定圓角角度,邊框寬度
- 2:可設定角標和正文文字內容/字型/對齊方式/顏色
- 3:可設定邊框顏色,正常顏色,按下顏色
- 4:可設定背景圖片
- 5:可設定按鈕顏色模式
三、效果圖
四、標頭檔案程式碼
#ifndef COLORBUTTON_H #define COLORBUTTON_H /** * 多樣式超級按鈕控制元件 作者:feiyangqingyun(QQ:517216493) 2017-9-24 * 1:可設定圓角角度,邊框寬度 * 2:可設定角標和正文文字內容/字型/對齊方式/顏色 * 3:可設定邊框顏色,正常顏色,按下顏色 * 4:可設定背景圖片 * 5:可設定按鈕顏色模式 */ #include <QWidget> #ifdef quc #if (QT_VERSION < QT_VERSION_CHECK(5,7,0)) #include <QtDesigner/QDesignerExportWidget> #else #include <QtUiPlugin/QDesignerExportWidget> #endif class QDESIGNER_WIDGET_EXPORT ColorButton : public QWidget #else class ColorButton : public QWidget #endif { Q_OBJECT Q_ENUMS(ColorMode) Q_ENUMS(TextAlign) Q_PROPERTY(int borderRadius READ getBorderRadius WRITE setBorderRadius) Q_PROPERTY(int borderWidth READ getBorderWidth WRITE setBorderWidth) Q_PROPERTY(QColor borderColor READ getBorderColor WRITE setBorderColor) Q_PROPERTY(bool showSuperText READ getShowSuperText WRITE setShowSuperText) Q_PROPERTY(QString superText READ getSuperText WRITE setSuperText) Q_PROPERTY(QFont superTextFont READ getSuperTextFont WRITE setSuperTextFont) Q_PROPERTY(TextAlign superTextAlign READ getSuperTextAlign WRITE setSuperTextAlign) Q_PROPERTY(QColor superTextColor READ getSuperTextColor WRITE setSuperTextColor) Q_PROPERTY(QString text READ getText WRITE setText) Q_PROPERTY(QFont textFont READ getTextFont WRITE setTextFont) Q_PROPERTY(TextAlign textAlign READ getTextAlign WRITE setTextAlign) Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor) Q_PROPERTY(QColor normalColor READ getNormalColor WRITE setNormalColor) Q_PROPERTY(QColor pressedColor READ getPressedColor WRITE setPressedColor) Q_PROPERTY(bool canMove READ getCanMove WRITE setCanMove) Q_PROPERTY(QPixmap bgImage READ getBgImage WRITE setBgImage) Q_PROPERTY(ColorMode colorMode READ getColorMode WRITE setColorMode) public: enum ColorMode { ColorMode_Normal = 0, //鬆開按下兩種顏色 ColorMode_Replace = 1, //按下鬆開顏色上下交替 ColorMode_Shade = 2 //按下鬆開顏色漸變交替 }; enum TextAlign { TextAlign_Top_Left = 0, TextAlign_Top_Center = 1, TextAlign_Top_Right = 2, TextAlign_Center_Left = 3, TextAlign_Center_Center = 4, TextAlign_Center_Right = 5, TextAlign_Bottom_Left = 6, TextAlign_Bottom_Center = 7, TextAlign_Bottom_Right = 8 }; explicit ColorButton(QWidget *parent = 0); protected: void mousePressEvent(QMouseEvent *); protected: bool eventFilter(QObject *watched, QEvent *event); void paintEvent(QPaintEvent *); void drawBg(QPainter *painter); void drawText(QPainter *painter); private: int borderRadius; //圓角半徑 int borderWidth; //邊框寬度 QColor borderColor; //邊框顏色 bool showSuperText; //顯示角標 QString superText; //角標文字 QFont superTextFont; //角標文字字型 TextAlign superTextAlign; //角標文字對齊方式 QColor superTextColor; //角標文字顏色 QString text; //文字 QFont textFont; //文字字型 TextAlign textAlign; //文字對齊方式 QColor textColor; //文字顏色 QColor normalColor; //正常顏色 QColor pressedColor; //按下顏色 bool canMove; //是否能移動 QPixmap bgImage; //背景圖片 ColorMode colorMode; //背景色模式 bool isPressed; //是否按下 public: int getBorderRadius() const; int getBorderWidth() const; QColor getBorderColor() const; bool getShowSuperText() const; QString getSuperText() const; QFont getSuperTextFont() const; TextAlign getSuperTextAlign()const; QColor getSuperTextColor() const; QString getText() const; QFont getTextFont() const; TextAlign getTextAlign() const; QColor getTextColor() const; QColor getNormalColor() const; QColor getPressedColor() const; bool getCanMove() const; QPixmap getBgImage() const; ColorMode getColorMode() const; QSize sizeHint() const; QSize minimumSizeHint() const; public Q_SLOTS: //設定邊框圓角角度 void setBorderRadius(int borderRadius); //設定邊框寬度 void setBorderWidth(int borderWidth); //設定邊框顏色 void setBorderColor(const QColor &borderColor); //設定是否顯示角標 void setShowSuperText(bool showSuperText); //設定角標文字 void setSuperText(const QString &superText); //設定角標文字字型 void setSuperTextFont(const QFont &superTextFont); //設定角標文字對齊方式 void setSuperTextAlign(const TextAlign &superTextAlign); //設定角標文字顏色 void setSuperTextColor(const QColor &superTextColor); //設定文字 void setText(const QString &text); //設定文字字型 void setTextFont(const QFont &textFont); //設定文字對齊方式 void setTextAlign(const TextAlign &textAlign); //設定文字顏色 void setTextColor(const QColor &textColor); //設定正常顏色 void setNormalColor(const QColor &normalColor); //設定按下顏色 void setPressedColor(const QColor &pressedColor); //設定是否可以移動 void setCanMove(bool canMove); //設定背景圖片 void setBgImage(const QPixmap &bgImage); //設定顏色模式 void setColorMode(const ColorMode &colorMode); Q_SIGNALS: void clicked(); }; #endif // WKBUTTON_H
五、核心程式碼
bool ColorButton::eventFilter(QObject *watched, QEvent *event) { if (!isEnabled()) { return QWidget::eventFilter(watched, event); } static QPoint lastPoint; if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *e = static_cast<QMouseEvent *>(event); if (this->rect().contains(e->pos()) && (e->button() == Qt::LeftButton)) { lastPoint = e->pos(); isPressed = true; update(); } } else if (event->type() == QEvent::MouseMove && isPressed && canMove) { QMouseEvent *e = static_cast<QMouseEvent *>(event); int dx = e->pos().x() - lastPoint.x(); int dy = e->pos().y() - lastPoint.y(); this->move(this->x() + dx, this->y() + dy); return true; } else if (event->type() == QEvent::MouseButtonRelease && isPressed) { isPressed = false; update(); } return QWidget::eventFilter(watched, event); } void ColorButton::paintEvent(QPaintEvent *) { //繪製準備工作,啟用反鋸齒 QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); //繪製背景 drawBg(&painter); //繪製文字 drawText(&painter); } void ColorButton::drawBg(QPainter *painter) { painter->save(); //設定邊框顏色及寬度 QPen pen; pen.setColor(borderColor); pen.setWidthF(borderWidth); painter->setPen(pen); //繪製區域要減去邊框寬度 QRect rect; rect.setX(borderWidth); rect.setY(borderWidth); rect.setWidth(width() - borderWidth * 2); rect.setHeight(height() - borderWidth * 2); //如果背景圖片存在則顯示背景圖片,否則顯示背景色 if (!bgImage.isNull()) { //等比例縮放繪製 QPixmap img = bgImage.scaled(rect.width(), rect.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); painter->drawPixmap((this->rect().width() - img.width()) / 2, (this->rect().height() - img.height()) / 2, img); } else { if (colorMode == ColorMode_Normal) { if (isPressed) { painter->setBrush(QBrush(pressedColor)); } else { painter->setBrush(QBrush(normalColor)); } } else if (colorMode == ColorMode_Replace) { QLinearGradient gradient(QPoint(0, 0), QPoint(0, height())); if (isPressed) { gradient.setColorAt(0.0, pressedColor); gradient.setColorAt(0.49, pressedColor); gradient.setColorAt(0.50, normalColor); gradient.setColorAt(1.0, normalColor); } else { gradient.setColorAt(0.0, normalColor); gradient.setColorAt(0.49, normalColor); gradient.setColorAt(0.50, pressedColor); gradient.setColorAt(1.0, pressedColor); } painter->setBrush(gradient); } else if (colorMode == ColorMode_Shade) { QLinearGradient gradient(QPoint(0, 0), QPoint(0, height())); if (isPressed) { gradient.setColorAt(0.0, pressedColor); gradient.setColorAt(1.0, normalColor); } else { gradient.setColorAt(0.0, normalColor); gradient.setColorAt(1.0, pressedColor); } painter->setBrush(gradient); } painter->drawRoundedRect(rect, borderRadius, borderRadius); } painter->restore(); } void ColorButton::drawText(QPainter *painter) { if (!bgImage.isNull()) { return; } painter->save(); //如果要顯示角標,則重新計算顯示文字的區域 if (showSuperText) { int offset = 3; QRect rect; rect.setX(borderWidth * offset); rect.setY(borderWidth); rect.setWidth(width() - borderWidth * offset * 2); rect.setHeight(height() - borderWidth * 2); Qt::Alignment alignment = Qt::AlignCenter; if (superTextAlign == TextAlign_Top_Left) { alignment = Qt::AlignTop | Qt::AlignLeft; } else if (superTextAlign == TextAlign_Top_Center) { alignment = Qt::AlignTop | Qt::AlignHCenter; } else if (superTextAlign == TextAlign_Top_Right) { alignment = Qt::AlignTop | Qt::AlignRight; } else if (superTextAlign == TextAlign_Center_Left) { alignment = Qt::AlignLeft | Qt::AlignVCenter; } else if (superTextAlign == TextAlign_Center_Center) { alignment = Qt::AlignHCenter | Qt::AlignVCenter; } else if (superTextAlign == TextAlign_Center_Right) { alignment = Qt::AlignRight | Qt::AlignVCenter; } else if (superTextAlign == TextAlign_Bottom_Left) { alignment = Qt::AlignBottom | Qt::AlignLeft; } else if (superTextAlign == TextAlign_Bottom_Center) { alignment = Qt::AlignBottom | Qt::AlignHCenter; } else if (superTextAlign == TextAlign_Bottom_Right) { alignment = Qt::AlignBottom | Qt::AlignRight; } //繪製角標 painter->setPen(superTextColor); painter->setFont(superTextFont); painter->drawText(rect, alignment, superText); } int offset = 5; QRect rect; rect.setX(borderWidth * offset); rect.setY(borderWidth); rect.setWidth(width() - borderWidth * offset * 2); rect.setHeight(height() - borderWidth * 2); Qt::Alignment alignment = Qt::AlignCenter; if (textAlign == TextAlign_Top_Left) { alignment = Qt::AlignTop | Qt::AlignLeft; } else if (textAlign == TextAlign_Top_Center) { alignment = Qt::AlignTop | Qt::AlignHCenter; } else if (textAlign == TextAlign_Top_Right) { alignment = Qt::AlignTop | Qt::AlignRight; } else if (textAlign == TextAlign_Center_Left) { alignment = Qt::AlignLeft | Qt::AlignVCenter; } else if (textAlign == TextAlign_Center_Center) { alignment = Qt::AlignHCenter | Qt::AlignVCenter; } else if (textAlign == TextAlign_Center_Right) { alignment = Qt::AlignRight | Qt::AlignVCenter; } else if (textAlign == TextAlign_Bottom_Left) { alignment = Qt::AlignBottom | Qt::AlignLeft; } else if (textAlign == TextAlign_Bottom_Center) { alignment = Qt::AlignBottom | Qt::AlignHCenter; } else if (textAlign == TextAlign_Bottom_Right) { alignment = Qt::AlignBottom | Qt::AlignRight; } painter->setPen(textColor); painter->setFont(textFont); painter->drawText(rect, alignment, text); painter->restore(); }
六、控制元件介紹
- 超過149個精美控制元件,涵蓋了各種儀表盤、進度條、進度球、指南針、曲線圖、標尺、溫度計、導航條、導航欄,flatui、高亮按鈕、滑動選擇器、農曆等。遠超qwt整合的控制元件數量。
- 每個類都可以獨立成一個單獨的控制元件,零耦合,每個控制元件一個頭檔案和一個實現檔案,不依賴其他檔案,方便單個控制元件以原始碼形式整合到專案中,較少程式碼量。qwt的控制元件類環環相扣,高度耦合,想要使用其中一個控制元件,必須包含所有的程式碼。
- 全部純Qt編寫,QWidget+QPainter繪製,支援Qt4.6到Qt5.12的任何Qt版本,支援mingw、msvc、gcc等編譯器,支援任意作業系統比如windows+linux+mac+嵌入式linux等,不亂碼,可直接整合到Qt Creator中,和自帶的控制元件一樣使用,大部分效果只要設定幾個屬性即可,極為方便。
- 每個控制元件都有一個對應的單獨的包含該控制元件原始碼的DEMO,方便參考使用。同時還提供一個所有控制元件使用的整合的DEMO。
- 每個控制元件的原始碼都有詳細中文註釋,都按照統一設計規範編寫,方便學習自定義控制元件的編寫。
- 每個控制元件預設配色和demo對應的配色都非常精美。
- 超過130個可見控制元件,6個不可見控制元件。
- 部分控制元件提供多種樣式風格選擇,多種指示器樣式選擇。
- 所有控制元件自適應窗體拉伸變化。
- 整合自定義控制元件屬性設計器,支援拖曳設計,所見即所得,支援匯入匯出xml格式。
- 自帶activex控制元件demo,所有控制元件可以直接執行在ie瀏覽器中。
- 整合fontawesome圖形字型+阿里巴巴iconfont收藏的幾百個圖形字型,享受圖形字型帶來的樂趣。
- 所有控制元件最後生成一個dll動態庫檔案,可以直接整合到qtcreator中拖曳設計使用。
- 目前已經有qml版本,後期會考慮出pyqt版本,如果使用者需求量很大的話。
七、SDK下載
- SDK下載連結:https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取碼:877p
- 下載連結中包含了各個版本的動態庫檔案,所有控制元件的標頭檔案,使用demo,自定義控制元件+屬性設計器。
- 自定義控制元件外掛開放動態庫dll使用(永久免費),無任何後門和限制,請放心使用。
- 目前已提供26個版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
- 不定期增加控制元件和完善控制元件,不定期更新SDK,歡迎各位提出建議,謝謝!
- widget版本(QQ:517216493)qml版本(QQ:373955953)三峰駝(QQ:278969898)。
- 濤哥的知乎專欄 Qt進階之路 https://zhuanlan.zhihu.com/TaoQt
- 歡迎關注微信公眾號【高效程式設計師】,C++/Python、學習方法、寫作技巧、熱門技術、職場發展等內容,乾貨多多,