QT的自绘制按钮

结束了研二的实习,现在返回了学校,准备毕业论文了。毕业论文导师叫我弄人工智能图像识别方向的,但我自己在公司实习的相关Qt经验,我还是把它放到CSDN上,免得我之后又忘了。

话不多说,今天带来的是Qt中使用绘制工具来自定义按钮形状。由于是自己通过QPainter的绘制方法来绘制的,所以需要实现响应的事件,如果有必要还得实现对应的信号和槽。结果如下:

QT的自绘制按钮_第1张图片

 如上图所示,实现了由5个按钮组成的圆形按钮。当把鼠标移动到按钮上,按钮就会变成白色,鼠标离开按钮时,按钮就会恢复到原来的颜色。点击按钮,按钮会变成灰色同时会出QMessageBox通知,通知你按下了哪个部分的按钮,如下图:

QT的自绘制按钮_第2张图片

 首先,定义一个类CustomButton,继承于QWidget,在CustomButton这个类中,添加我们自己的方法,如下:

#ifndef MyCustomButton_h__
#define MyCustomButton_h__

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include


/*
	自绘制按钮
*/
namespace DX {
	class CustomButton :public QWidget
	{
		Q_OBJECT
	public:
		CustomButton(QWidget* parent = NULL);
	private:
		//初始化按钮
		void initButton();
		//绘制按钮
		void paintEvent(QPaintEvent *event) override;
		//添加圆弧
		void addArc(qreal startAngle, qreal angleLegth, QRgb color);
		//鼠标事件
		void mouseMoveEvent(QMouseEvent *event) override;
		void mousePressEvent(QMouseEvent *event) override;
		void mouseReleaseEvent(QMouseEvent* event) override;

		//鼠标离开事件
		void leaveEvent(QEvent * event) override;
	public:
		//设置弧长和半径
		void setRadiusValue(int radius);
		void setArcLength(int arcLength);

	signals:
		//鼠标点击
		void singnalButtonClicked(int buttonId);
		//鼠标松开
	signals:
		void singnalButtonReleased(int buttonId);
	private:
		//弧长及半径
		int m_radius, m_arcLength;
		//圆弧路径
		QList m_arcPathList;
		QList m_textPathList;
		//圆弧颜色
		QList m_colorList;
		//当前鼠标按钮/进入按钮的索引
		int m_pressIndex, m_enterIndex;
		//鼠标事件标志位;
		bool m_isMousePressed;
		bool m_isMouseEntered;
		QPoint m_mousePt;
	};

}


#endif // CustomButton_h__

CustomButton这个类中,除了绘制函数,我还增加了两个信号,一个用于向外界发出鼠标点击的信号,里面的int型参数用于辨别时哪个按钮被按下了。一个用于向外界发出鼠标弹起的信号,里面的int型参数也是用于辨别哪个按钮。

CustomButton这个类对应的cpp如下:

#include "MyCustomButton.h"

#include 

DX::CustomButton::CustomButton(QWidget* parent /*= NULL*/) :QWidget(parent), m_isMousePressed(false), m_enterIndex(-1)
{
	this->m_radius = 0;
	this->m_arcLength = 90;
	initButton();
	this->setMouseTracking(true);

}

void DX::CustomButton::initButton()
{
	//初始化路径
	QRect rect(this->width() / 2 - 50, this->height() / 2 - 50, 100, 100);
	QPainterPath path1;
	path1.moveTo(this->width() / 2, this->height() / 2);
	path1.arcTo(rect, m_radius, m_arcLength);
	QPainterPath path2;
	path2.moveTo(this->width() / 2, this->height() / 2);
	path2.arcTo(rect, m_radius + 90, m_arcLength);
	QPainterPath path3;
	path3.moveTo(this->width() / 2, this->height() / 2);
	path3.arcTo(rect, m_radius + 180, m_arcLength);
	QPainterPath path4;
	path4.moveTo(this->width() / 2, this->height() / 2);
	path4.arcTo(rect, m_radius + 270, m_arcLength);

	QPainterPath path5;  //绘制中心圆
	QRect rect2(this->width() / 2 - 25, this->height() / 2 - 25, 50, 50);
	path5.moveTo(this->width() / 2, this->height() / 2);
	path5.addEllipse(rect2);
	path1 -= path5;
	path2 -= path5;
	path3 -= path5;
	path4 -= path5;
	this->m_arcPathList << path1 << path2 << path3 << path4;
	this->m_arcPathList.append(path5);
	//初始颜色
	this->m_colorList << Qt::blue << Qt::yellow << Qt::black << Qt::red << Qt::green;

	//设置文字
	QFont times("Times", 16);
	times.setStyleStrategy(QFont::ForceOutline);
	QPainterPath textPath1;
	textPath1.addText(this->width() / 2 - 25 + 50, this->height() / 2 - 25, times, QStringLiteral("右上"));
	QPainterPath textPath2;
	textPath2.addText(this->width() / 2 - 25, this->height() / 2 - 25, times, QStringLiteral("左上"));
	QPainterPath textPath3;
	textPath3.addText(this->width() / 2 - 60, this->height() / 2 - 25 + 50, times, QStringLiteral("左下"));
	QPainterPath textPath4;
	textPath4.addText(this->width() / 2 - 25 + 50, this->height() / 2 - 25 + 50, times, QStringLiteral("右下"));
	QPainterPath textPath5;
	textPath5.addText(this->width() / 2 - 20, this->height() / 2, times, QStringLiteral("中间"));
	m_textPathList << textPath1 << textPath2 << textPath3 << textPath4 << textPath5;
}

void DX::CustomButton::paintEvent(QPaintEvent *event)
{
	QPainter painter(this);


	painter.setPen(Qt::NoPen);
	for (int index = 0; index < m_colorList.size(); index++)
	{
		if (m_enterIndex != -1 && m_enterIndex == index && m_isMousePressed == false && m_isMouseEntered == true)
		{
			painter.setBrush(Qt::white);
			painter.drawPath(m_arcPathList.at(index));
			/*	painter.setBrush(Qt::lightGray);
				painter.drawPath(m_textPathList.at(index));*/
			continue;
		}
		if (m_enterIndex != -1 && m_enterIndex == index && m_isMousePressed == true)
		{
			painter.setBrush(Qt::gray);
			painter.drawPath(m_arcPathList.at(index));
			/*	painter.setBrush(Qt::lightGray);
				painter.drawPath(m_textPathList.at(index));*/
			continue;
		}
		painter.setBrush(m_colorList.at(index));
		painter.drawPath(m_arcPathList.at(index));
		/*painter.setBrush(Qt::red);
		painter.drawPath(m_textPathList.at(index));*/
	}

}

void DX::CustomButton::addArc(qreal startAngle, qreal angleLegth, QRgb color)
{

}

void DX::CustomButton::mouseMoveEvent(QMouseEvent *event)
{

	if (m_arcPathList.at(0).contains(event->pos()))
	{
		m_enterIndex = 0;//设置鼠标进入的是哪个位置
		m_isMouseEntered = true;
		update();

		//QMessageBox::information(NULL, "Tip", QStringLiteral("右上按钮"));
		return;
	}

	if (m_arcPathList.at(1).contains(event->pos()))
	{
		m_enterIndex = 1;
		m_isMouseEntered = true;
		update();
		//QMessageBox::information(NULL, "Tip", QStringLiteral("左上按钮"));
		return;
	}
	else
	{
		m_isMouseEntered = false;
		update();
	}

	if (m_arcPathList.at(2).contains(event->pos()))
	{
		m_enterIndex = 2;
		m_isMouseEntered = true;
		update();
		//QMessageBox::information(NULL, "Tip", QStringLiteral("左下按钮"));
		return;
	}
	else
	{
		m_isMouseEntered = false;
		update();
	}

	if (m_arcPathList.at(3).contains(event->pos()))
	{
		m_isMouseEntered = true;
		m_enterIndex = 3;
		update();
		//QMessageBox::information(NULL, "Tip", QStringLiteral("右下按钮"));
		return;
	}
	else
	{
		m_isMouseEntered = false;
		update();
	}

	if (m_arcPathList.at(4).contains(event->pos()))
	{
		m_enterIndex = 4;
		m_isMouseEntered = true;
		update();
		//QMessageBox::information(NULL, "Tip", QStringLiteral("中间按钮"));
	}
	else
	{
		m_isMouseEntered = false;
		update();
	}

}

void DX::CustomButton::mousePressEvent(QMouseEvent *event)
{
	if (event->button()&Qt::LeftButton)
	{
		if (m_arcPathList.at(0).contains(event->pos()))
		{
			m_enterIndex = 0;//设置鼠标进入的是哪个位置
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(0); //一旦信号发出,m_isMousePressed和	m_isMouseEntered 都为false
			m_isMousePressed = false;
			m_isMouseEntered = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("右上按钮"));
			return;
		}

		if (m_arcPathList.at(1).contains(event->pos()))
		{
			m_enterIndex = 1;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(1);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("左上按钮"));
			return;
		}

		if (m_arcPathList.at(2).contains(event->pos()))
		{
			m_enterIndex = 2;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(2);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("左下按钮"));
			return;
		}

		if (m_arcPathList.at(3).contains(event->pos()))
		{
			m_enterIndex = 3;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(3);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("右下按钮"));
			return;
		}

		if (m_arcPathList.at(4).contains(event->pos()))
		{
			m_enterIndex = 4;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(4);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("中间按钮"));
		}
	}



}

void DX::CustomButton::mouseReleaseEvent(QMouseEvent* event)
{
	m_isMousePressed = false;
	update();
}

void DX::CustomButton::leaveEvent(QEvent * event)
{

}

void DX::CustomButton::setRadiusValue(int radius)
{
	this->m_radius = radius;
}

void DX::CustomButton::setArcLength(int arcLength)
{
	this->m_arcLength = arcLength;
}

由于是使用Qpainter和QPainterpath进行绘制,没有现成的按钮效果,这就需要我自己去实现了。比如判断鼠标点击的位置是在哪个按钮上,还好类QPainterPath中有一个方法:contains,这个方法是判断点是否在多边形里面,这样就可以将鼠标点击时的按钮放进去来判断鼠标点击了哪个按钮。如下:

void DX::CustomButton::mousePressEvent(QMouseEvent *event)
{
	if (event->button()&Qt::LeftButton)
	{
		if (m_arcPathList.at(0).contains(event->pos()))
		{
			m_enterIndex = 0;//设置鼠标进入的是哪个位置
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(0); //一旦信号发出,m_isMousePressed和	m_isMouseEntered 都为false
			m_isMousePressed = false;
			m_isMouseEntered = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("右上按钮"));
			return;
		}

		if (m_arcPathList.at(1).contains(event->pos()))
		{
			m_enterIndex = 1;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(1);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("左上按钮"));
			return;
		}

		if (m_arcPathList.at(2).contains(event->pos()))
		{
			m_enterIndex = 2;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(2);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("左下按钮"));
			return;
		}

		if (m_arcPathList.at(3).contains(event->pos()))
		{
			m_enterIndex = 3;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(3);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("右下按钮"));
			return;
		}

		if (m_arcPathList.at(4).contains(event->pos()))
		{
			m_enterIndex = 4;
			m_isMousePressed = true;
			update();
			emit singnalButtonClicked(4);
			m_isMousePressed = false;
			//QMessageBox::information(NULL, "Tip", QStringLiteral("中间按钮"));
		}
	}



}

我在鼠标按下的事件中去判断鼠标点击的位置,如果鼠标的位置是在5个按钮中的任意一个内,就发出信号。其他的效果,比如鼠标移动到按钮上,离开,都是在鼠标移动事件中写的。思路是一样的。上面就是核心的代码了,接下来就只用将自己写的控件(由于是继承QWidget)加到主窗口去了。如下(.h和.cpp我放在一起了):

#pragma once

#include 
#include "ui_CustomButton.h"

#include "MyCustomButton.h"
#include 

class CustomButton : public QMainWindow
{
    Q_OBJECT

public:
    CustomButton(QWidget *parent = nullptr);
    ~CustomButton();
private slots:
	void open(int buttonId);
private:
    Ui::CustomButtonClass ui;
	DX::CustomButton *customButton;
};

#include "CustomButton.h"

#include 
#include 
#include 


CustomButton::CustomButton(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

	QVBoxLayout* layout = new QVBoxLayout;
	customButton = new DX::CustomButton;
	this->setCentralWidget(customButton);

	connect(customButton, SIGNAL(singnalButtonClicked(int)), this, SLOT(open(int)));

}

void CustomButton::open(int buttonId)
{
	switch (buttonId)
	{
	case 0:
	{
		QMessageBox::information(NULL, "Tip", QStringLiteral("这是右上的按钮传递过来的信号"));
	}
	break;
	case 1:
	{
		QMessageBox::information(NULL, "Tip", QStringLiteral("这是左上的按钮传递过来的信号"));
	}
	break;
	case 2:
	{
		QMessageBox::information(NULL, "Tip", QStringLiteral("这是左下的按钮传递过来的信号"));
	}
	break;
	case 3:
	{
		QMessageBox::information(NULL, "Tip", QStringLiteral("这是右下的按钮传递过来的信号"));
	}
	break;
	case 4:
	{
		QMessageBox::information(NULL, "Tip", QStringLiteral("这是中间的按钮传递过来的信号"));
	}
	break;
	default:
		break;
	}
}

CustomButton::~CustomButton()
{}

我是将源码原原本本的放上来了,如果想要使用,直接copy下去就行了。我还有其他的QT实验,我之后会陆续的贴出来的,今天先这样吧,我还得去学深度学习。

你可能感兴趣的:(QT,qt5,c++)