前言(界面编写)
有关于界面UI的设置,我没有使用qt默认的有边框的样式,而是选择了自定义的方式,也就是无边框样式,由于失去了标题栏,无法拖动窗口和最小化,最大化,关闭,因此需要重写qt相关的内置函数。由界面效果可以看到,展现的控件的边角都是有一定的弧度的,相比生硬的直角更加美观一些,本文主要介绍的是界面布局以及一些Qss样式表的内容,其他的在后面几篇文章中。
串口助手的专栏:Qt串口助手_rqtz的博客-CSDN博客
ui界面效果展示
日间模式
夜间模式
无边框设置
//设置无边框
setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint);
在类的构造函数中添加后,显示出的窗口会失去边框,且无法拖动和其他操作,只能右键图标关闭程序。
重写内置函数,实现窗口拖动
窗口的拖动是在qt中的内置函数中实现的,这些函数是受保护的,因此,要实现窗口拖动的功能,需重写这些函数。
protected:
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
在类的头文件中添加上述函数,分别是鼠标移动事件,鼠标按压事件,鼠标释放事件。
鼠标按压事件
void MainWindow::mousePressEvent(QMouseEvent *e)
{
if(e->button() == Qt::LeftButton)
{
mouseflag = true;
mousepose = e->globalPos();
windowpose = this->geometry().topLeft();
}
}
代码解释:
- 首先是判断鼠标是左键按下,因为我们移动窗口的习惯通常是按左键。
- mouseflag = true; 左键按下的标志位,后面会用到。
- mousepose = e->globalPos(); 获取到当前的鼠标坐标,类型是QPoint.
- windowpose = this->geometry().topLeft(); 获取当前窗口左上角的坐标,类型同样是QPoint。
鼠标移动事件
void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
if(mouseflag)
{
QPoint dis = e->globalPos()-mousepose;
this->move(windowpose+dis);
}
}
代码解释:
- 首先是判断鼠标是左键按下的状态下,mouseflag为真时。
- QPoint dis = e->globalPos()-mousepose; 当前的鼠标坐标相对于鼠标按压时的鼠标坐标mousepos的差值,该差值为距离坐标。
- mousepose = e->globalPos(); 获取到当前的鼠标坐标,类型是QPoint.
- this->move(windowpose+dis); 当前窗口this移动到的坐标位置,windowpose(移动前窗口位置坐标)+dis。
鼠标释放事件
void MainWindow::mouseReleaseEvent(QMouseEvent *e)
{
if(e->button() == Qt::LeftButton)
mouseflag = false;
}
代码解释:
当鼠标有按下到松开时,我们将mouseflag置为假,保证在只有左键按下时才进行移动
最终效果
重写事件过滤器函数,实现窗口控件悬停切换图片效果
最小化与最大化和关闭这些功能的实现是通过获取label控件的点击事件,通过添加事件过滤器的方法,
安装事件过滤器
由于label控件并没有点击事件,所以我们只能使用 setAttribute和installEventFilter 来添加事件过滤器使其具有相关事件。
void MainWindow::sethoverevent()
{
ui->close->setAttribute(Qt::WA_Hover,true);
ui->close->installEventFilter(this);
ui->little->setAttribute(Qt::WA_Hover,true);
ui->little->installEventFilter(this);
ui->large->setAttribute(Qt::WA_Hover,true);
ui->large->installEventFilter(this);
ui->switch_2->installEventFilter(this);
}
上述代码中的ui控件分别指的下面的label控件,本质是照片。
setAttribute(Qt::WA_Hover,true) 是指让label控件具有悬停事件
installEventFilter(this) 为控件安装事件过滤器,使其可以接受并处理所有的事件,包括悬停事件。
重写事件过滤器函数
在.h文件中添加
protected:
bool eventFilter(QObject*obj,QEvent *e) override;
在.cpp函数中添加
bool MainWindow::eventFilter(QObject *obj, QEvent *e)
{
if(e->type() == QEvent::HoverEnter)
{
emit hoverval(obj,obj->objectName());
return true;
}
else if(e->type() == QEvent::HoverLeave)
{
emit hoverval(obj,"mouseout");
return true;
}
}
其中
- QObject *obj, QEvent *e :obj 表示一个当前控件的一个指针,可以通过访问objectname来获取他的名字,e表示当前事件的一个指针,可以通过type()来获取事件类型。
- 信号singal : 当鼠标悬浮在控件上时,我们 发送信号 emit hoverval(obj,obj->objectName()); 当鼠标离开控件时,我们 发送信号 hoverval(obj,"mouseout")
绑定信号和槽
connect(this,&MainWindow::hoverval,this,&MainWindow::hoveraction);
编写悬浮事件槽函数
void MainWindow::hoveraction(QObject *obj, QString name)
{
if(name=="close") {
ui->close->setPixmap(QPixmap(rclose).scaled(16,16));
}
else if (name=="little") {
ui->little->setPixmap(QPixmap(rmostlittle).scaled(16,16));
}
else if (name=="large") {
ui->large->setPixmap(QPixmap(rmostlarge).scaled(16,16));
}
else if (name=="mouseout") {
ui->little->setPixmap(QPixmap(bmostlittle).scaled(16,16));
ui->large->setPixmap(QPixmap(bmostlarge).scaled(16,16));
ui->close->setPixmap(QPixmap(bclose).scaled(16,16));
}
}
我们通过得到不同的控件名称,来去设置不同的图片,达到视觉效果。
最终效果
重写事件过滤器函数,实现窗口最大化,最小化和关闭
获取label的点击事件
在上述的evenfliter函数中添加
else if(e->type() == QEvent::MouseButtonPress)
{
theammode_count++;
emit clickval(obj,obj->objectName());
return true;
}
完整函数为
bool MainWindow::eventFilter(QObject *obj, QEvent *e)
{
if(e->type() == QEvent::HoverEnter)
{
emit hoverval(obj,obj->objectName());
return true;
}
else if(e->type() == QEvent::HoverLeave)
{
emit hoverval(obj,"mouseout");
return true;
}
else if(e->type() == QEvent::MouseButtonPress)
{
theammode_count++;
emit clickval(obj,obj->objectName());
return true;
}
}
绑定信号和槽
connect(this,&MainWindow::hoverval,this,&MainWindow::clickaction);
编写点击事件槽函数
void MainWindow::clickaction(QObject *obj, QString name)
{
if(name=="close") {
this->close();
}
else if (name=="little") {
this->showMinimized();
}
else if (name=="large") {
static int num = 0;
num++;
if((num+1)%2==0)
this->showFullScreen();
else
this->showNormal();
}
- 控件名称为close时: 调用close方法来关闭窗口
- 控件名称为littel时: 调用showMinimized方法来最小化窗口
- 控件名称为llarge时: 当点击次数和为奇数时,调用showFullScreen方法来最大化窗口,偶数时,调用showNormal方法还原窗口。
最终效果
最后夜间模式的实现方法,只需要获取控件的点击事件,在该函数中更新样式表即可。
重写paintevent事件,使窗口由四角的方形显示圆角形
void MainWindow::paintEvent(QPaintEvent *e)
{
QBitmap bmp(this->size());
bmp.fill();
QPainter p(&bmp);
p.setPen(Qt::NoPen);
p.setBrush(Qt::black);
p.drawRoundedRect(bmp.rect(),20,20);//像素为20的圆角
setMask(bmp);
}
按钮圆角
这个是界面中的一个按钮的圆角设置的样式表,大家参考一下
QPushButton{
font: 9pt "微软雅黑";
color: #080808;
background-color:#ffffff;
border-color:#c3c3c3;
border-radius: 14px;
border-style: solid;
border-width: 1px;
padding: 4px;
}
QPushButton::hover {
background-color:rgb(224,238,249);
border-color: rgb(0,120,212);
}
注意:如果没有显示出来圆角,可能是你的圆角半径值border-radius过大或过小,结合border-width和padding多试试几个不同的值,直到有效果为止。