1. 程式人生 > >Qt編寫自定義控制元件一開關按鈕

Qt編寫自定義控制元件一開關按鈕

從2010年進入網際網路+智慧手機時代以來,各種各樣的APP大行其道,手機上面的APP有很多流行的元素,開關按鈕個人非常喜歡,手機QQ、360衛士、金山毒霸等,都有很多開關控制一些操作,在Qt widgets應用專案上,在專案中應用些類似的開關按鈕,估計也會為專案增添不少新鮮感。

總結了大部分的開關按鈕控制元件,基本上有兩大類,第一類是純程式碼繪製,這種對程式碼的掌控度要求比較高,但是靈活性比較好。第二類是貼圖,專業的美工做好的各種狀態的背景圖片,只需要用程式碼將該圖片畫到介面上即可。為了能夠涵蓋兩大類的開關按鈕,特意將常見的四種類型(圓角矩形/內圓形/外圓形/圖片)都整合到了自定義的開關按鈕中。

執行效果:

1:純程式碼繪製

純程式碼繪製開關按鈕,可以很靈活的設定各種顏色、間隔、文字等,還可以產生動畫過度的滑動效果。

產生滑動效果採用定時器繪製的方式,自動計算滑塊的X軸開始座標,當滑塊的X軸開始座標到達滑塊的X軸結束座標時停止定時器。

void SwitchButton::updateValue()
{
    if (checked) {
        if (startX < endX){
            startX = startX +step;
        } else {
            startX = endX;
            timer->stop();
        }
    } else {
        if (startX > endX){
            startX = startX -step;
        } else {
            startX = endX;
            timer->stop();
        }
    }
 
    update();
}

2:貼圖繪製

void SwitchButton::drawImage(QPainter *painter)
{
    painter->save();
 
    QPixmap pix;
 
    if (!checked) {
        pix =QPixmap(imageOff);
    } else {
        pix =QPixmap(imageOn);
    }
 
    //自動等比例平滑縮放居中顯示
    int targetWidth =pix.width();
    int targetHeight =pix.height();
    pix =pix.scaled(targetWidth, targetHeight, Qt::KeepAspectRatio,Qt::SmoothTransformation);
 
    int pixX =rect().center().x() - targetWidth / 2;
    int pixY =rect().center().y() - targetHeight / 2;
    QPoint point(pixX, pixY);
    painter->drawPixmap(point,pix);
 
    painter->restore();
}

有些人說PS一張精美的圖片也不是很容易,需要專業的,這裡推薦一個好方法,讓你也可以獲取到這些圖片,其實大部分的APP都可以用解壓軟體開啟,拓展名改為.zip即可,解壓出來一般裡面都含有絕大部分的圖片,發現絕大部分的APP都喜歡用圖片作為背景來展示一些效果,而不是原原本本的用程式碼一點點繪製。騰訊就是騰訊啊,大公司!人家的美工MM設計的圖片那真的沒得話說,絕對一流,手機QQ每次升級一個版本,我都會下過來將裡面的精美圖片圖示之類的提取出來,以便專案使用。同時還推薦兩個網站:http://www.easyicon.net/ 我的所有專案用到的ico圖示都是這網站上面的。http://www.ui.cn/專業的設計師集中營,這裡面成千上萬的精美的設計的圖片,可以多多參考。

完整程式碼: 

switchbutton.h 

#ifndef SWITCHBUTTON_H
#define SWITCHBUTTON_H

/**
 * 作者:feiyangqingyun(QQ:517216493) 2016-11-6
 * 1:可設定開關按鈕的樣式 圓角矩形/內圓形/外圓形/圖片
 * 2:可設定選中和未選中時的背景顏色
 * 3:可設定選中和未選中時的滑塊顏色
 * 4:可設定顯示的文字
 * 5:可設定滑塊離背景的間隔
 * 6:可設定圓角角度
 */

#include <QWidget>

class QTimer;

class SwitchButton: public QWidget
{
	Q_OBJECT
public:
	enum ButtonStyle {
		ButtonStyle_Rect = 0,     //圓角矩形
		ButtonStyle_CircleIn = 1, //內圓形
		ButtonStyle_CircleOut = 2,//外圓形
		ButtonStyle_Image = 3     //圖片
	};

	SwitchButton(QWidget *parent = 0);
	~SwitchButton();

protected:
	void mousePressEvent(QMouseEvent *);
	void resizeEvent(QResizeEvent *);
	void paintEvent(QPaintEvent *);
	void drawBg(QPainter *painter);
	void drawSlider(QPainter *painter);
	void drawText(QPainter *painter);
	void drawImage(QPainter *painter);

private:
	bool checked;               //是否選中
	ButtonStyle buttonStyle;    //開關按鈕樣式

	QColor bgColorOff;          //關閉時背景顏色
	QColor bgColorOn;           //開啟時背景顏色

	QColor sliderColorOff;      //關閉時滑塊顏色
	QColor sliderColorOn;       //開啟時滑塊顏色

	QColor textColorOff;        //關閉時文字顏色
	QColor textColorOn;         //開啟時文字顏色

	QString textOff;            //關閉時顯示的文字
	QString textOn;             //開啟時顯示的文字

	QString imageOff;           //關閉時顯示的圖片
	QString imageOn;            //開啟時顯示的圖片

	int space;                  //滑塊離背景間隔
	int rectRadius;             //圓角角度

	int step;                   //每次移動的步長
	int startX;                 //滑塊開始X軸座標
	int endX;                   //滑塊結束X軸座標
	QTimer *timer;              //定時器繪製

private slots:
	void updateValue();

public:
	bool getChecked()const
	{
		return checked;
	}
	ButtonStyle getButtonStyle()const
	{
		return buttonStyle;
	}

	QColor getBgColorOff()const
	{
		return bgColorOff;
	}
	QColor getBgColorOn()const
	{
		return bgColorOn;
	}

	QColor getSliderColorOff()const
	{
		return sliderColorOff;
	}
	QColor getSliderColorOn()const
	{
		return sliderColorOn;
	}

	QColor getTextColorOff()const
	{
		return textColorOff;
	}
	QColor getTextColorOn()const
	{
		return textColorOn;
	}

	QString getTextOff()const
	{
		return textOff;
	}
	QString getTextOn()const
	{
		return textOn;
	}

	QString getImageOff()const
	{
		return imageOff;
	}
	QString getImageOn()const
	{
		return imageOn;
	}

	int getSpace()const
	{
		return space;
	}
	int getRectRadius()const
	{
		return rectRadius;
	}

public slots:
	//設定是否選中
	void setChecked(bool checked);
	//設定風格樣式
	void setButtonStyle(ButtonStyle buttonStyle);

	//設定背景顏色
	void setBgColor(QColor bgColorOff, QColor bgColorOn);
	//設定滑塊顏色
	void setSliderColor(QColor sliderColorOff, QColor sliderColorOn);
	//設定文字顏色
	void setTextColor(QColor textColorOff, QColor textColorOn);

	//設定文字
	void setText(QString textOff, QString textOn);

	//設定背景圖片
	void setImage(QString imageOff, QString imageOn);

	//設定間隔
	void setSpace(int space);
	//設定圓角角度
	void setRectRadius(int rectRadius);

signals:
	void checkedChanged(bool checked);
};

#endif // SWITCHBUTTON_H

switchbutton.cpp 

#include "switchbutton.h"
#include "qpainter.h"
#include "qevent.h"
#include "qtimer.h"
#include "qdebug.h"

SwitchButton::SwitchButton(QWidget *parent): QWidget(parent)
{
	checked = false;
	buttonStyle	= ButtonStyle_Rect;

	bgColorOff = QColor(225, 225, 225);
	bgColorOn = QColor(250, 250, 250);

	sliderColorOff = QColor(100, 100, 100);
	sliderColorOn = QColor(100, 184, 255);

	textColorOff = QColor(255, 255, 255);
	textColorOn = QColor(10, 10, 10);

	textOff = "";
	textOn = "";

	imageOff = ":/image/btncheckoff1.png";
	imageOn = ":/image/btncheckon1.png";

	space = 2;
	rectRadius = 5;

	step = width() / 50;
	startX = 0;
	endX = 0;

	timer = new QTimer(this);
	timer->setInterval(5);
	connect(timer, SIGNAL(timeout()), this, SLOT(updateValue()));

	setFont(QFont("Microsoft Yahei", 10));
}

SwitchButton::~SwitchButton()
{

}

void SwitchButton::mousePressEvent(QMouseEvent *)
{
	checked = !checked;
	emit checkedChanged(checked);

	//每次移動的步長為寬度的 50分之一
	step = width() / 50;

	//狀態切換改變後自動計算終點座標
	if (checked) {
		if (buttonStyle == ButtonStyle_Rect) {
			endX = width() - width() / 2;
		} else if (buttonStyle == ButtonStyle_CircleIn) {
			endX = width() - height();
		} else if (buttonStyle == ButtonStyle_CircleOut) {
			endX = width() - height() + space;
		}
	} else {
		endX = 0;
	}

	timer->start();
}

void SwitchButton::resizeEvent(QResizeEvent *)
{
	//每次移動的步長為寬度的 50分之一
	step = width() / 50;

	//尺寸大小改變後自動設定起點座標為終點
	if (checked) {
		if (buttonStyle == ButtonStyle_Rect) {
			startX = width() - width() / 2;
		} else if (buttonStyle == ButtonStyle_CircleIn) {
			startX = width() - height();
		} else if (buttonStyle == ButtonStyle_CircleOut) {
			startX = width() - height() + space;
		}
	} else {
		startX = 0;
	}

	update();
}

void SwitchButton::paintEvent(QPaintEvent *)
{
	//繪製準備工作,啟用反鋸齒
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing);

	if (buttonStyle == ButtonStyle_Image) {
		//繪製圖片
		drawImage(&painter);
	} else {
		//繪製背景
		drawBg(&painter);
		//繪製滑塊
		drawSlider(&painter);
		//繪製文字
		drawText(&painter);
	}
}

void SwitchButton::drawBg(QPainter *painter)
{
	painter->save();
	painter->setPen(Qt::NoPen);

	if (!checked) {
		painter->setBrush(bgColorOff);
	} else {
		painter->setBrush(bgColorOn);
	}

	if (buttonStyle == ButtonStyle_Rect) {
		painter->drawRoundedRect(rect(), rectRadius, rectRadius);
	} else if (buttonStyle == ButtonStyle_CircleIn) {
		QRect rect(0, 0, width(), height());
		//半徑為高度的一半
		int radius = rect.height() / 2;
		//圓的寬度為高度
		int circleWidth = rect.height();

		QPainterPath path;
		path.moveTo(radius, rect.left());
		path.arcTo(QRectF(rect.left(), rect.top(), circleWidth, circleWidth), 90, 180);
		path.lineTo(rect.width() - radius, rect.height());
		path.arcTo(QRectF(rect.width() - rect.height(), rect.top(), circleWidth, circleWidth), 270, 180);
		path.lineTo(radius, rect.top());

		painter->drawPath(path);
	} else if (buttonStyle == ButtonStyle_CircleOut) {
		QRect rect(space, space, width() - space * 2, height() - space * 2);
		painter->drawRoundedRect(rect, rectRadius, rectRadius);
	}

	painter->restore();
}

void SwitchButton::drawSlider(QPainter *painter)
{
	painter->save();
	painter->setPen(Qt::NoPen);

	if (!checked) {
		painter->setBrush(sliderColorOff);
	} else {
		painter->setBrush(sliderColorOn);
	}

	if (buttonStyle == ButtonStyle_Rect) {
		int sliderWidth = width() / 2 - space * 2;
		int sliderHeight = height() - space * 2;
		QRect sliderRect(startX + space, space, sliderWidth , sliderHeight);
		painter->drawRoundedRect(sliderRect, rectRadius, rectRadius);
	} else if (buttonStyle == ButtonStyle_CircleIn) {
		QRect rect(0, 0, width(), height());
		int sliderWidth = rect.height() - space * 2;
		QRect sliderRect(startX + space, space, sliderWidth, sliderWidth);
		painter->drawEllipse(sliderRect);
	} else if (buttonStyle == ButtonStyle_CircleOut) {
		QRect rect(0, 0, width() - space, height() - space);
		int sliderWidth = rect.height();
		QRect sliderRect(startX, space / 2, sliderWidth, sliderWidth);
		painter->drawEllipse(sliderRect);
	}

	painter->restore();
}

void SwitchButton::drawText(QPainter *painter)
{
	painter->save();

	if (!checked) {
		painter->setPen(textColorOff);
		painter->drawText(width() / 2, 0, width() / 2 - space, height(), Qt::AlignCenter, textOff);
	} else {
		painter->setPen(textColorOn);
		painter->drawText(0, 0, width() / 2 + space * 2, height(), Qt::AlignCenter, textOn);
	}

	painter->restore();
}

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

	QPixmap pix;

	if (!checked) {
		pix = QPixmap(imageOff);
	} else {
		pix = QPixmap(imageOn);
	}

	//自動等比例平滑縮放居中顯示
	int targetWidth = pix.width();
	int targetHeight = pix.height();
	pix = pix.scaled(targetWidth, targetHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation);

	int pixX = rect().center().x() - targetWidth / 2;
	int pixY = rect().center().y() - targetHeight / 2;
	QPoint point(pixX, pixY);
	painter->drawPixmap(point, pix);

	painter->restore();
}

void SwitchButton::updateValue()
{
	if (checked) {
		if (startX < endX) {
			startX = startX + step;
		} else {
			startX = endX;
			timer->stop();
		}
	} else {
		if (startX > endX) {
			startX = startX - step;
		} else {
			startX = endX;
			timer->stop();
		}
	}

	update();
}

void SwitchButton::setChecked(bool checked)
{
	if (this->checked != checked) {
		this->checked = checked;
		emit checkedChanged(checked);
		update();
	}
}

void SwitchButton::setButtonStyle(SwitchButton::ButtonStyle buttonStyle)
{
	this->buttonStyle = buttonStyle;
	update();
}

void SwitchButton::setBgColor(QColor bgColorOff, QColor bgColorOn)
{
	this->bgColorOff = bgColorOff;
	this->bgColorOn = bgColorOn;
	update();
}

void SwitchButton::setSliderColor(QColor sliderColorOff, QColor sliderColorOn)
{
	this->sliderColorOff = sliderColorOff;
	this->sliderColorOn = sliderColorOn;
	update();
}

void SwitchButton::setTextColor(QColor textColorOff, QColor textColorOn)
{
	this->textColorOff = textColorOff;
	this->textColorOn = textColorOn;
	update();
}

void SwitchButton::setText(QString textOff, QString textOn)
{
	this->textOff = textOff;
	this->textOn = textOn;
	update();
}

void SwitchButton::setImage(QString imageOff, QString imageOn)
{
	this->imageOff = imageOff;
	this->imageOn = imageOn;
	update();
}

void SwitchButton::setSpace(int space)
{
	this->space = space;
	update();
}

void SwitchButton::setRectRadius(int rectRadius)
{
	this->rectRadius = rectRadius;
	update();
}

此自定義控制元件整合在QFramework中。

QFramework簡介:

QFramework是一套通用的Qt程式開發框架,整合主介面佈局、各種自定義控制元件、資料庫處理、excel極速匯出、資料列印、串列埠通訊、網路通訊、協議解析、全域性熱鍵、郵件傳送,簡訊傳送,百度地圖呼叫、ffmpeg+vlc處理等功能,將常用的功能封裝成類庫,提供統一直觀的呼叫介面,方便使用者使用,對應封裝的庫都有對應的demo程式。QQ:517216493

QFramework基本功能:

1:支援從4.7.0到5.7.0的任何Qt版本,不受版本限制。用了此框架,不會再有Qt版本不同而引起的程式編譯通不過的煩惱。

2:極速匯出資料到excel,支援表格資料或者查詢的資料,不依賴任何元件,支援任何excel、wps等表格軟體版本,匯出10萬行資料8個欄位只需要3秒完成。對匯出的表格樣式可自定義主標題和副標題,可對匯出的資料按照指定條件紅色突出顯示。

3:資料匯出到pdf及列印功能,支援表格資料或者查詢的資料,支援橫向縱向列印,自動分頁。

4:資料分頁dbapi類,只需傳入表格物件,表名,翻頁按鈕即可。無需再寫重複的方法處理翻頁。

5:各種自定義控制元件,例如開關按鈕、發光按鈕,儀表盤控制元件、音量控制元件、溫溼度控制元件、儀表儀器類控制元件等。

6:全新超級中英雙拼輸入法,非常適合觸控裝置。

7:全域性熱鍵處理。

8:串列埠熱敏印表機列印。

9:qcustomplot 2D圖形曲線繪製(含滑鼠資料跟蹤)。

10:多執行緒郵件傳送,支援多個接收郵箱。

11:多執行緒簡訊傳送,支援多個接收號碼及長簡訊。

12:Qffmpeg+Qvlc視訊處理。

13:取字模,字元轉LED資料處理。

14:全域性日誌輸出類 applog,可動態掛載和解除安裝。

15:全域性程式控制類 appkey,可控制程式的使用時間、執行時間、裝置數量限制等。

16:封裝百度地圖呼叫介面,支援裝置標註、路線查詢、位置顯示等。

17:自動清理程式早期資料類 cleanapi,傳入要清理的資料庫表名,執行間隔,保留的最大記錄數即可。這樣保證了整個系統儲存的都是最新的資料。

18:NTP校時服務程式。

19:全域性截圖處理,可以很方便的直接在ARM上對程式進行截圖。

20:程式存活檢測功能 applive,通過udp通訊實時傳送心跳命令,這樣可以保證程式7*24小時執行,在ARM上可採用appdog看門狗程式。

21:已執行時間+當前時間+實時CPU使用率+實時記憶體使用率等。

22:自定義程式主介面底部資訊。

23:Echart圖表的互動使用。

相關推薦

Qt編寫定義控制元件開關按鈕

從2010年進入網際網路+智慧手機時代以來,各種各樣的APP大行其道,手機上面的APP有很多流行的元素,開關按鈕個人非常喜歡,手機QQ、360衛士、金山毒霸等,都有很多開關控制一些操作,在Qt widgets應用專案上,在專案中應用些類似的開關按鈕,估計也會為專案增添不少新鮮

Qt定義控制元件開關按鈕

簡述 接觸過iOS系統的童鞋們應該對開關按鈕很熟悉,在設定裡面經常遇到,切換時候的滑動效果比較帥氣。 通常說的開關按鈕,有兩個狀態:on、off。 下面,我們利用自定義控制元件來實現一個開關按鈕。 原理 重寫滑鼠按下事件(mousePres

Qt編寫定義控制元件9-導航按鈕控制元件

前言 導航按鈕控制元件,主要用於各種漂亮精美的導航條,我們經常在web中看到導航條都非常精美,都是html+css+js實現的,還

Qt編寫定義控制元件37-發光按鈕(會呼吸的痛)

一、前言 這個控制元件是好早以前寫的,已經授權過好幾個人開源過此控制元件程式碼,比如紅磨坊小胖,此控制元件並不是來源於真實需求,而

Qt編寫定義控制元件屬性設計器

以前做.NET開發中,.NET直接就集成了屬性設計器,VS不愧是宇宙第一IDE,你能夠想到的都給你封裝好了,用起來不要太爽!因為專案需要自從全面轉Qt開發已經6年有餘,在工業控制領域,有一些應用場景需要自定義繪製一些控制元件滿足特定的需求,比如儀器儀表、組態等,而且需要直接使用者通過屬性設計的形式生成匯出控制

Qt編寫定義控制元件外掛開放動態庫dll使用(永久免費)

這套控制元件陸陸續續完善了四年多,目前共133個控制元件,除了十幾個控制元件參考網友開源的程式碼寫的,其餘全部原創,在釋出之初就有

Qt編寫定義控制元件1-汽車儀表盤

前言 汽車儀表盤幾乎是qt寫儀表盤控制元件中最常見的,一般來說先要求美工做好設計圖,然後設計效果圖給到程式設計師,由程式設計師根據

Qt編寫定義控制元件2-進度條標尺

前言 進度條標尺控制元件的應用場景一般是需要手動拉動進度,上面有標尺可以看到當前進度,類似於qslider控制元件,其實就是qsl

Qt編寫定義控制元件6-指南針儀表盤

前言 指南針儀表盤,主要用來指示東南西北四個方位,雙向對稱兩個指標旋轉,其實就是360度打轉,功能屬於簡單型,可能指標的繪製稍微難

Qt編寫定義控制元件7-定義可拖動多邊形

前言 自定義可拖動多邊形控制元件,原創作者是趙彥博(QQ:408815041 [email protected]),創作之初主要

Qt編寫定義控制元件11-裝置防區按鈕控制元件

前言 在很多專案應用中,需要根據資料動態生成物件顯示在地圖上,比如地圖標註,同時還需要可拖動物件到指定位置顯示,能有多種狀態指示,

Qt編寫定義控制元件12-進度儀表盤

前言 進度儀表盤主要應用場景是標識一個任務進度完成的狀況等,可以自由的設定範圍值和當前值,為了美觀還提供了四種指示器(圓形指示器/

Qt編寫定義控制元件13-多型進度條

前言 多型進度條,顧名思義,有多重狀態,其實本控制元件主要是用來表示百分比進度的,由於之前已經存在了百分比進度條控制元件,名字被霸

Qt編寫定義控制元件14-環形進度條

前言 環形進度條,用來展示當前進度,為了滿足大屏UI的需要特意定製,以前有個叫圓環進度條,不能滿足專案需要,只能重新定做,以前的進

Qt編寫定義控制元件15-百分比儀表盤

前言 百分比儀表盤,主要的應用場景是展示銷售完成率、產品合格率等,也可以作為一個進度百分比展示,可以獨立設定對應的標題文字,標題文

Qt編寫定義控制元件16-魔法老鼠

前言 五一期間一直忙著大屏電子看板軟體的開發,沒有再去整理控制元件,今天已經將大屏電子看板的所有子視窗都實現了任意停靠和雙擊獨立再

Qt編寫定義控制元件18-魔法小魚

前言 上次發了個純painter繪製的老鼠,那個就是qt目錄下的demo,改的,只是比demo中的老鼠稍微胖一點,估計人到中年都發

Qt編寫定義控制元件19-圖片背景時鐘

前言 圖片背景時鐘控制元件,是全套控制元件(目前共145個)中唯一的幾個貼圖的控制元件,這個背景要是不貼圖,會畫到猝死,必須用美工

Qt編寫定義控制元件20-定義餅圖

一、前言 上次在寫視覺化資料大屏電子看板專案的時候,為了逐步移除對QChart的依賴(主要是因為QChart真的太垃圾了,是所有Q

Qt編寫定義控制元件28-顏色滑塊面板

一、前言 相比於上一個顏色按鈕面板,此控制元件就要難很多,顏色值有三種表示形式,除了程式設計師最常用的RGB以外,還有HSB和CM