QT 自定义控件 数值选择器

自定义控件,基于QWidget 实现数值选择器;

1.支持水平、垂直两种方向;

2. 支持设置文字颜色,选中文字颜色,背景色,选中背景色;

3.支持设置后缀显示如 ℃,KG 等

4.可设置选中字体大小;

5.支持设置自定义文字,纯数字时支持设置显示位数如(01, 001)

6.支持拖动后动画效果

//设置数字选项,

//设置文字为选项

使用示例:

    CValueSelector * valSelector = new CValueSelector(this, Qt::Vertical);

    valSelector ->setShowNum(2);
    valSelector ->SetFontSize(30);
    valSelector ->SetRange(0, 23);
    valSelector ->SetValue(0);
    valSelector ->SetColors(QColor("#FFFFFF"), QColor("#FFFFFF"), QColor("#1B1C1E"), QColor(0xEA, 0x55, 0x32, 0x90));
    valSelector ->setFixedSize(300, 400);
    //信号
    connect(valSelector , &CValueSelector::ValueChanged, this, ...);

上代码:

#pragma once


#include <QMouseEvent>
#include <QColor>
#include <QPainter>
#include <QTime>
#include <QDate>
#include <QWidget>
#include <QPropertyAnimation>


//数值选择器
class CValueSelector : public QWidget {
	Q_OBJECT
		Q_PROPERTY(int32_t deviation READ ReadDeviation WRITE SetDeviation)
public:
	explicit CValueSelector(QWidget *parent = nullptr, Qt::Orientation ori = Qt::Horizontal);
	virtual ~CValueSelector();
	//初始化
	bool Init();
	//设置值显示个数 推荐为 5 默认
	void SetValueCount(uint8_t valNum);
	//设置值范围
	void SetRange(int32_t min, int32_t max);
	//设置值
	void SetValue(int32_t val);
	//获取当前值
	int32_t Value();
	//设置字体大小  
	void SetFontSize(uint8_t fontPix);
	//设置文字 
	void SetTextList(const QStringList & tests);
	//设置Color
	void SetColors(const QColor & textCol, const QColor & textHCol, const QColor & bkgCol = Qt::NoBrush, const QColor & selectCol = Qt::NoBrush);
	//设置值 后缀 如℃,KG, S
	void SetValueSuffix(const QString & suffix);
	//设置数字的最小显示位数
	void setShowNum(uint8_t num);

protected:
	virtual bool event(QEvent *event);
	virtual void ProcMousePress(QMouseEvent * ev);
	virtual void ProcMouseMove(QMouseEvent * ev);
	virtual void ProcMouseRelease(QMouseEvent * ev);
	virtual void paintEvent(QPaintEvent * ev);

protected:
	//绘制背景
	virtual void PainterBackgorund(QPainter &painter);
	//绘制选中背景
	virtual void PainterSelectBackgorund(QPainter &painter);

private:
	//绘制值
	void PainterVal(QPainter &painter, int32_t num, int32_t deviation);
	//更正动画开始
	void CorrectionAnimationStart();
	//读取偏移量
	int32_t ReadDeviation();
	//设置偏移量
	void SetDeviation(int32_t n);
	//获取当前值索引的文字
	const QString GetCurrentValText(int32_t num);

signals:
	//值更新信号
	void ValueChanged(int32_t value);

private:
	Qt::Orientation m_orientation;		//水平 / 垂直
	QPalette m_palette;					//调色板
	QPropertyAnimation * m_pAnimation;
	uint8_t m_valCount;
	uint8_t m_showNum;      //显示位数
	int32_t m_minVal;		//最小值
	int32_t m_maxVal;		//最大值
	int32_t m_value;		//当前值
	int32_t m_valueBak;		//当前值备份
	bool m_bDragValid;		//拖拽有效
	int32_t m_pressPos;		//鼠标按下POS
	int32_t m_deviation;	//移动偏移量
	uint8_t m_fontSize;		//字体大小
	QStringList m_textList;	//值对应的文字  不设置默认为数字
	QString m_valSuffix;	//值后缀
};
#include "valueSelector.h"
#include <QDebug>

#define MAX_DISP_VAL_NUM	5	//显示几个数值 默认

//数值选择器实现
CValueSelector::CValueSelector(QWidget *parent, Qt::Orientation ori)
	: QWidget(parent), m_orientation(ori), m_palette(), m_pAnimation(nullptr), m_valCount(MAX_DISP_VAL_NUM), m_minVal(0), m_maxVal(100), m_value(0),
	m_valueBak(5), m_bDragValid(false), m_pressPos(0), m_deviation(0), m_fontSize(24), m_textList(), m_showNum(0) {
	Init();
}

CValueSelector::~CValueSelector() {
}

//初始化
bool CValueSelector::Init() {
	setContentsMargins(0, 0, 0, 0);
	setWindowFlags(Qt::FramelessWindowHint);
	//setAttribute(Qt::WA_TranslucentBackground);
	m_pAnimation = new(std::nothrow) QPropertyAnimation(this, "deviation");
	if (nullptr == m_pAnimation)
		return false;
	m_pAnimation->setDuration(250);
	m_pAnimation->setEasingCurve(QEasingCurve::OutQuad);

	m_palette.setBrush(QPalette::Window, QColor(0x1B1C1E));			//背景默认无
	m_palette.setColor(QPalette::Highlight, QColor(0xEA5200));		//高亮背景
	m_palette.setColor(QPalette::Text, Qt::white);					//文字颜色
	m_palette.setColor(QPalette::HighlightedText, Qt::white);		//高亮文字白色 (当前值)
	return true;
}

//设置值个数 显示个数
void CValueSelector::SetValueCount(uint8_t valNum) {
	if (0 != valNum)
		m_valCount = valNum;
}

//设置范围
void CValueSelector::SetRange(int32_t min, int32_t max) {
	m_minVal = min <= max ? min : max;
	m_maxVal = min <= max ? max : min;
	if (m_value < m_minVal)
		m_value = m_minVal;
	if (m_value > m_maxVal)
		m_value = m_maxVal;
	update();
}

//设置值
void CValueSelector::SetValue(int32_t val) {
	m_value = val;
	if (m_value < m_minVal)
		m_value = m_minVal;
	if (m_value > m_maxVal)
		m_value = m_maxVal;
	update();
}

//获取当前值
int32_t CValueSelector::Value() {
	return m_value;
}

//设置字体大小  
void CValueSelector::SetFontSize(uint8_t fontPix) {
	if (fontPix < 10)
		fontPix = 10;
	m_fontSize = fontPix;
	update();
}

//设置文字   字体最小10
void CValueSelector::SetTextList(const QStringList & tests) {
	m_textList = tests;
	update();
}

//设置Color
void CValueSelector::SetColors(const QColor & textCol, const QColor & textHCol, const QColor & bkgCol, const QColor & selectCol) {
	m_palette.setBrush(QPalette::Window, bkgCol);					//背景默认无
	m_palette.setColor(QPalette::Highlight, selectCol);				//高亮背景
	m_palette.setColor(QPalette::Text, textCol);					//文字颜色
	m_palette.setColor(QPalette::HighlightedText, textHCol);		//高亮文字 (当前值)
}

//设置值 后缀 如℃,KG, S
void CValueSelector::SetValueSuffix(const QString & suffix) {
	m_valSuffix = suffix;
}

void CValueSelector::setShowNum(uint8_t num) {
	m_showNum = num;
}

bool CValueSelector::event(QEvent *event) {
	if (event->type() == QEvent::MouseButtonPress) {
		QMouseEvent * mouseEnv = static_cast<QMouseEvent *>(event);
		if (Qt::LeftButton == mouseEnv->button()) {
			ProcMousePress(mouseEnv);
			//return true;
		}
	} else if (event->type() == QEvent::MouseMove) {
		QMouseEvent * mouseEnv = static_cast<QMouseEvent *>(event);
		ProcMouseMove(mouseEnv);
		//return true;
	} else if (event->type() == QEvent::MouseButtonRelease) {
		QMouseEvent * mouseEnv = static_cast<QMouseEvent *>(event);
		if (Qt::LeftButton == mouseEnv->button()) {
			//QPoint point = mouseEnv->pos();
			//if (-65535 >= point.x() || -65535 >= point.y())
			//	return true;
			ProcMouseRelease(mouseEnv);
			//return true;
		}
	}
	return QWidget::event(event);
}

void CValueSelector::ProcMousePress(QMouseEvent * e) {
	m_pAnimation->stop();
	m_bDragValid = true;
	if (Qt::Horizontal == m_orientation)
		m_pressPos = e->pos().x();
	else
		m_pressPos = e->pos().y();
}
void CValueSelector::ProcMouseMove(QMouseEvent * e) {
	if (!m_bDragValid)
		return;
	if (Qt::Horizontal == m_orientation) {
		//数值到边界时,阻止继续往对应方向移动
		if ((m_value == m_minVal && e->pos().x() >= m_pressPos) ||
			(m_value == m_maxVal && e->pos().x() <= m_pressPos))
			return;

		m_deviation = e->pos().x() - m_pressPos;
		//限制一次最多一格
		if (m_deviation > width() / m_valCount)
			m_deviation = width() / m_valCount;
		else if (m_deviation < -width() / m_valCount)
			m_deviation = -(width()) / m_valCount;
	} else {
		//数值到边界时,阻止继续往对应方向移动
		if ((m_value == m_minVal && e->pos().y() >= m_pressPos) ||
			(m_value == m_maxVal && e->pos().y() <= m_pressPos))
			return;

		m_deviation = e->pos().y() - m_pressPos;
		//限制一次最多一格
		if (m_deviation > height() / m_valCount)
			m_deviation = height() / m_valCount;
		else if (m_deviation < -height() / m_valCount)
			m_deviation = -(height()) / m_valCount;
	}
	update();
}
void CValueSelector::ProcMouseRelease(QMouseEvent * e) {
	if (m_bDragValid) {
		m_bDragValid = false;
		if (m_deviation)	//有偏移才启动动画纠正
			CorrectionAnimationStart();
	}

	if (m_valueBak != m_value) {	//值更改了 发信号
		emit ValueChanged(m_value);
		m_valueBak = m_value;
	}
}

//重绘事件
void CValueSelector::paintEvent(QPaintEvent *) {
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing, true);

	PainterBackgorund(painter);			//绘制背景
	PainterSelectBackgorund(painter);	//绘制高亮背景

	int32_t lenth = width();
	if (Qt::Vertical == m_orientation)
		lenth = height();

	if (m_deviation >= lenth / m_valCount && m_value > m_minVal) {
		m_pressPos += lenth / m_valCount;
		m_deviation -= lenth / m_valCount;
		--m_value;
	}

	if (m_deviation <= -lenth / m_valCount && m_value < m_maxVal) {
		m_pressPos -= lenth / m_valCount;
		m_deviation += lenth / m_valCount;
		++m_value;
	}
	//绘制数值
	for (int16_t i = -(m_valCount / 2); i <= m_valCount / 2; ++i) {
		if (m_value + i < m_minVal || m_value + i > m_maxVal)
			continue;
		PainterVal(painter, m_value + i, m_deviation + lenth / m_valCount * i);
	}
}

//绘制值
void CValueSelector::PainterVal(QPainter &painter, int32_t num, int32_t deviation) {
	int32_t lenth = width();
	if (Qt::Vertical == m_orientation)
		lenth = height();

	//qreal scale = qreal(lenth * 2 - qAbs(deviation)) / (lenth * 2);
	double size = (qAbs(deviation) / (lenth / 2.0) * 0.5);
	if (size > 0.5)
		size = 0.5;
	QColor col;
	QString text = GetCurrentValText(num);
	if (m_value == num) {
		text += m_valSuffix;
		col = m_palette.color(QPalette::HighlightedText);
	} else
		col = m_palette.color(QPalette::Text);
	col.setAlpha(col.alpha() - col.alpha() * size);
	QFont font;
	font.setPixelSize(m_fontSize - m_fontSize * size);
	painter.setFont(font);
	painter.setPen(col);
	int32_t offset = lenth / 2 + deviation - lenth / m_valCount / 2;
	if (Qt::Vertical == m_orientation)
		painter.drawText(QRectF(0, offset, width(), height() / m_valCount), Qt::AlignCenter, text);
	else
		painter.drawText(QRectF(offset, 0, width() / m_valCount, height()), Qt::AlignCenter, text);

}

//更正动画开始
void CValueSelector::CorrectionAnimationStart() {
	int32_t lenth = width();
	if (Qt::Vertical == m_orientation)
		lenth = height();
	//将文字矫正到中心
	if (m_deviation > lenth / m_valCount / 2) {
		m_pAnimation->setStartValue(-(lenth / m_valCount - m_deviation));
		m_pAnimation->setEndValue(0);
		m_value--;
	} else if (m_deviation < -lenth / m_valCount / 2) {
		m_pAnimation->setStartValue(lenth / m_valCount + m_deviation);
		m_pAnimation->setEndValue(0);
		m_value++;
	} else {
		m_pAnimation->setStartValue(m_deviation);
		m_pAnimation->setEndValue(0);
	}
	m_pAnimation->start();
}

//获取偏移量
int32_t CValueSelector::ReadDeviation() {
	return m_deviation;
}

//设置偏移量
void CValueSelector::SetDeviation(int32_t n) {
	m_deviation = n;
	update();
}

//获取当前值索引的文字
const QString CValueSelector::GetCurrentValText(int32_t num) {
	int32_t valIdx = num - m_minVal;
	if (valIdx >= m_textList.size())
		return m_showNum != 0 ? QString("%1").arg(valIdx, m_showNum, 10, QLatin1Char('0')) : QString("%1").arg(num);
	return m_textList.at(valIdx);
}

//绘制背景
void CValueSelector::PainterBackgorund(QPainter & painter) {
	const QColor & bkgCol = m_palette.color(QPalette::Window);
	if (bkgCol == Qt::NoBrush)
		return;
	painter.save();
	painter.setPen(Qt::NoPen);
	painter.setBrush(bkgCol);
	painter.drawRect(rect());
	painter.restore();
}

//绘制选中背景
void CValueSelector::PainterSelectBackgorund(QPainter & painter) {
	const QColor & bkgCol = m_palette.color(QPalette::Highlight);
	if (bkgCol == Qt::NoBrush)
		return;
	painter.save();
	painter.setPen(Qt::NoPen);
	QRect selectRect;
	//QLinearGradient linearGradient;	//渐变支持
	if (Qt::Horizontal == m_orientation) {
		selectRect.setRect(width() / m_valCount * (m_valCount / 2), 0, width() / m_valCount, height());
		//linearGradient = QLinearGradient(selectRect.topLeft(), selectRect.bottomLeft());
	} else {
		selectRect.setRect(0, height() / m_valCount * (m_valCount / 2), width(), height() / m_valCount);
		//linearGradient = QLinearGradient(selectRect.topLeft(), selectRect.topRight());
	}
	/*QColor col = bkgCol;
	col.setAlpha(0);
	linearGradient.setColorAt(0.0, col);
	linearGradient.setColorAt(0.3, bkgCol);
	linearGradient.setColorAt(0.7, bkgCol);
	linearGradient.setColorAt(1.0, col);
	painter.setBrush(linearGradient);*/
	painter.setBrush(bkgCol);
	painter.drawRect(selectRect);
	painter.restore();
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值