Qt编写自定义控件一开关按钮

从2010年进入互联网+智能手机时代以来,各种各样的APP大行其道,手机上面的APP有很多流行的元素,开关按钮个人非常喜欢,手机QQ、360卫士、金山毒霸等,都有很多开关控制一些操作,在Qt widgets应用项目上,在项目中应用些类似的开关按钮,估计也会为项目增添不少新鲜感。

总结了大部分的开关按钮控件,基本上有两大类,第一类是纯代码绘制,这种对代码的掌控度要求比较高,但是灵活性比较好。第二类是贴图,专业的美工做好的各种状态的背景图片,只需要用代码将该图片画到界面上即可。为了能够涵盖两大类的开关按钮,特意将常见的四种类型(圆角矩形/内圆形/外圆形/图片)都集成到了自定义的开关按钮中。

运行效果:

Qt编写自定义控件一开关按钮_第1张图片

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 

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中。

设计师designer完整源码(仅限Qt4):https://pan.baidu.com/s/1t9uKOgi7PW34Kdj7rgTlrA 
设计师designer可执行文件:https://pan.baidu.com/s/1h3oUjqBun2_YD68gry84wQ 
自定义控件Qt4封装版本:https://pan.baidu.com/s/1JnpCwIW5sY9VtViqHSCi1g 
自定义控件Qt5封装版本:https://pan.baidu.com/s/17gY83gSbUOxDrvaLNYUhjA 
自定义控件android版本:https://pan.baidu.com/s/1YiRFmRzZgOtxjACGUIa5XA 
强烈建议下载设计师designer可执行文件看效果,可自行在右下角的属性栏更改属性看到效果,所见即所得!
再次强调,设计师designer完整源码只能qt4编译,不支持qt5。

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-自定义控件,qt,自定义控件,开关按钮)