结束了研二的实习,现在返回了学校,准备毕业论文了。毕业论文导师叫我弄人工智能图像识别方向的,但我自己在公司实习的相关Qt经验,我还是把它放到CSDN上,免得我之后又忘了。
话不多说,今天带来的是Qt中使用绘制工具来自定义按钮形状。由于是自己通过QPainter的绘制方法来绘制的,所以需要实现响应的事件,如果有必要还得实现对应的信号和槽。结果如下:
如上图所示,实现了由5个按钮组成的圆形按钮。当把鼠标移动到按钮上,按钮就会变成白色,鼠标离开按钮时,按钮就会恢复到原来的颜色。点击按钮,按钮会变成灰色同时会出QMessageBox通知,通知你按下了哪个部分的按钮,如下图:
首先,定义一个类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实验,我之后会陆续的贴出来的,今天先这样吧,我还得去学深度学习。