关于在UI界⾯(QT,PyQT)中去除标题栏,实现⾃定义最⼤
化,最⼩化,关闭等功能按钮
为什么要⾃⼰设计实现标题栏
⽆论是使⽤qtdesigner,还是直接在程序中创建⼀个Qwidget,qt程序⽣成的界⾯都会⽣成⼀个默认的标题栏。
该标题栏实质上应当是⼀个边框,只不过这个边框上可以显⽰ico,标题,可以进⾏最⼤化最⼩化等操作。
标题栏的颜⾊随计算机系统的主题变化,且形式固定,如果为界⾯设置统⼀的背景和风格,这个标题栏就会⾮常的突兀,丑陋。因此,如果想要获得⼀个和谐的统⼀的UI界⾯,我们最好把系统⽣成的默认标题栏去掉,⾃⼰重现默认标题栏附带的功能。
--默认标题栏,在统⼀背景下显得很突兀
--⾃定义标题栏,可以⾃⼰设计按键的⼤⼩,图标,位置,能够和背景更加统⼀
想要⽤⾃⼰的就要先去掉别⼈的
-
-QT编程中使⽤以下语句可以去除系统⾃动⽣成的默认边框。
MainWindow::setWindowFlags(Qt::FramelessWindowHint);//隐藏边框
通过修改setWindowFlags的输⼊,我们还可以将边框修改成特殊的样式,⽐如只带⼀个关闭按钮。
--python中该语句的写法为:
self.setWindowFlags(Qt.FramelessWindowHint) # 隐藏边框
去掉标题栏后我们会失去什么
前⽂说过,标题栏的本质是⼀个边框,或者说⼀个group,这个边框作为限制,UI内容嵌套在边框⾥,⽽边框则“悬浮”在桌⾯上。
1. 因此,去除边框后,⾸当其冲,UI界⾯会因为失去边框丢失调整⼤⼩的能⼒,表现出来的就是⿏标⽆法选中界⾯的边缘,达到拖动边
缘改变⼤⼩的⽬的。
2. 同时,因为改变界⾯在桌⾯上的位置原本由边框实现,去除边框后,UI与桌⾯不存在明确的布局关系,
界⾯内容将⽆法移动。
3. 原本程序的最⼤化(还原),最⼩化,关闭等功能由标题栏的按钮实现,去除标题栏后,该类操作界⾯的⽅式就会消失,不过我们仍
可以通过底部状态栏右键操作界⾯。
4. 总结⽽⾔,去除标题栏后,我们将⽆法通过按钮对界⾯进⾏最⼤化(还原),最⼩化,关闭等操作,⽆法拖动界⾯,也⽆法改变界⾯
的⼤⼩,⽽这些也将是我们后续亟待实现的功能。
如何在程序中实现最⼤化(还原),最⼩化,关闭等操作
QT是⼀个⽐较傻⽠化的界⾯绘制⽅式,针对界⾯中常备的绘制,关闭等操作,QT架构中有⼀系列的事件可供调⽤和修改来帮助编写者较简单的实现这些功能。因此在去除标题栏后,我们仅需要在界⾯中添加上想要的按钮,命名后放好想要的位置。通过设置风格等⽅式修改好按钮的样式和标签,我们就能通过调⽤上⽂中描述的事件来替代默认标题栏。
1. 放置按钮,调整位置,并修改成⾃⼰想要的风格。
--这⾥给出⼀段我常⽤的按钮样式表,该样式表分别定义了按钮的背景⾊,⿏标悬浮效果和按下的效果。
QPushButton{background-color:rgba(0,0,0,0);}
QPushButton:hover{background-color:rgba(255,255,255,0.5);}
QPushButton:pressed{background-color: rgba(100,100,100,1);};
2. 准备好符合⾃⼰界⾯风格的各按钮标志,并提前添加到QT的素材⽂件(.qrc)⾥。
--标志应符合界⾯风格,且应和背景颜⾊不同,因为我做的暗⾊界⾯较多所以这⾥是纯⽩⾊的,没有特殊设计的话这些按钮的背景应当是透明的,我们可以在ps⾥⾯很简单的⾃⼰绘制⼀个想要的标志,然后保存为png格式后,再在⽹上⼀个转换的⽹站转换为ico格式3. 关闭按钮实现。
如果不涉及对关闭界⾯事件的修改,我们仅需在想要的按钮clicked槽函数下调⽤QT默认的close事件即可。
--QT中其调⽤格式为:
void MainWindow::on_pushButton_close_clicked()
{
MainWindow::close();//关闭事件
}
--python中,其调⽤格式更接近信号与槽的格式:
登录按钮图片素材self.pushButton_t(self.close)
如果需要修改关闭事件,⽐如在python多进程编程中需要保证主进程关闭带动⼦进程⼀起关闭,则需要对closeevent中内容进⾏修改。
--其在QT中调⽤格式如下:
void MainWindow::closeEvent(QCloseEvent *event)
{
}
--在python中调⽤如下:
# 关闭主窗⼝时清理资源
def closeEvent(self, event):
data = "---Visual shield tail clearance measurement system off."
ms = Measurement_data_sava(cctv_par.address, data, forma=4, save_lev=1, log_lev=0)
kill_name(uwb_par.name_pid)
4. 最⼤化(还原)按钮实现,最⼩化按钮实现。
--最⼤化(还原)按钮QT中实现⽅式如下:
void MainWindow::on_pushButton_maximize_clicked()
{
if (MainWindow::isMaximized())
{
MainWindow::showNormal();//还原事件
ui->pushButton_maximize->setIcon(QIcon(QPixmap(":/new/new/max.png")));
}
else
{
MainWindow::showMaximized();//最⼤化事件
ui->pushButton_maximize->setIcon(QIcon(QPixmap(":/new/new/back.png")));
}
}
利⽤MainWindow::isMaximized()可以判断UI界⾯当前的状态,以分别实现最⼤化和还原的功能。
功能切换时注意更换按钮上显⽰的标志,以显⽰其当前真正的功能。
-
-python中最⼤化(还原)按钮实现⽅式如下:
# 调⽤
self.pushButton_max .t(self.maxornormale)
# 最⼤化按钮功能
def maxornormale(self):
if self.isMaximized():
self.flgs_max_normal=0
self.showNormal()
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap(":/newPrefix/resource/icon/max.png"), QtGui.QIcon.Normal,
QtGui.QIcon.Off)
self.pushButton_max.setIcon(icon7)
else:
self.flgs_max_normal = 1
self.showMaximized()
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap(":/newPrefix/resource/icon/back.png"), QtGui.QIcon.Normal,
QtGui.QIcon.Off)
self.pushButton_max.setIcon(icon6)
--最⼩化按钮QT中实现⽅式如下:
void MainWindow::on_pushButton_minimize_clicked()
{
MainWindow::showMinimized();
}
--最⼩化按钮python中实现⽅式如下:
self.pushButton_min .t(self.showMinimized)
实现界⾯移动
联想⼀下,正常情况下界⾯移动的操作过程是什么?⿏标左键长按标题栏中的⾮按钮位置,然后拖动⿏标,界⾯从起始位置移动到⿏标停留的位置。在此过程中,起到定位作⽤的参数分别有,界⾯当前的位置,⿏标光标的起始位置,⿏标光标终⽌位置,起到触发作⽤则是⿏标左键的长按动作。
⽤QT编程的思路解析该过程,可以表述为:⿏标左键长按作为信号,该信号触发的槽函数为计算操作过程中⿏标位置的变化,再将界⾯按⿏标位置的变化移动,达成⿏标拖动界⾯的效果。
因此,根据上述分析,⿏标拖动界⾯移动的实现⾄少需要两个部分:
1. 识别⿏标的长按动作及落点,长按动作⽤于触发移动操作,落点则⽤于判断当前位置应不应该移动界⾯。
2. 根据记录的⿏标位置,计算出⿏标在桌⾯坐标系中的变化,再将界⾯按照变化调整位置。
这些动作都可以通过⿏标事件解决。
1. 通过⿏标点击事件,识别⿏标左键按下操作,并记录当前位置:
--QT中该操作的实现⽅式为:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
whereismouse=event->pos();
}
}
-
-python中该操作的实现⽅式为:
# ⿏标事件,按下按键
def mousePressEvent(self, e):
if e.buttons() == QtCore.Qt.LeftButton:
try:
except:
pass
2. 通过⿏标移动事件,计算⿏标光标的坐标变化,并借助move事件使界⾯进⾏相同的移动。
--QT中该操作的实现⽅式为:
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() == Qt::LeftButton)
{
if(MainWindow::isMaximized() || MainWindow::isMinimized())
{
return;
}
else
{
if (ui->groupBox_top->underMouse())
{
if(ui->groupBox_2->underMouse())
{
}
else
{
MainWindow::move(MainWindow::mapToGlobal(event->pos()-whereismouse));
}
}
}
}
event->accept();
}
--python中该操作的实现⽅式为:
# ⿏标移动事件
def mouseMoveEvent(self, event):
if self.pushButton_tip.underMouse():
pass
elif self.pushButton_4.underMouse():
pass
elif self.pushButton_5.underMouse():
pass
else:
try:
if event.buttons() == Qt.LeftButton s:
event.accept()
except:
pass
underMouse()语句可以获取⿏标当前是否悬浮在相应控件上,通过该语句可以控制界⾯拖动的⽣效范围,使其不在按钮之类需要⿏标操作的地⽅误触发。