1. 简述
这几天给老师做项目用到了PyQt5,说一些自己的想法,用python写qt界面我觉得如果懂C++和Qt是最好的,因为PyQt5没有相应的官方文档,我做项目时都是对照着Qt的C++文档做的,而且二者基本差别不大,只是一些小细节有略微不同而已,当然不懂Qt直接做也可以,但是这难免很费劲。
废话就说这些,下面就稍微说下Qt界面美化,后面附有C++和python的代码链接,下面是效果图:
2.代码说明
做这个自定义的标题栏,主要实现以下几个功能:
- 关闭,最小化,复原三个按钮的基本功能;
- 双击标题栏窗口最大化或者缩小;
- 鼠标点击拖动窗口;
- 显示标题和图标
(1)主窗口
先说一下主界面的代码,主要就是两行:
self.setWindowFlags(Qt.FramelessWindowHint) #隐藏主窗口边界
self.lay.setSpacing(0); #去除控件间的距离
self.lay.setContentsMargins(0, 0, 0, 0)
这里的self就是主窗口QMainWindow,lay就是一个QVBoxLayout的布局,使用参数Qt.FramelessWindowHint可以让主窗口不现实边框,只显示客户区,我们就可以自己绘制标题栏的内容。
下面两行设为0是为了取消控件之间的间距,不这样的话很难设置空间的布局,会使得窗口很丑。
主窗口还有一个就是SetStyleSheet就是设置界面的样式,这个后面再说。
(2)标题栏
标题栏主要包含五个空间两个label:图标label、标题label,三个按钮:最小化按钮、复原按钮和关闭按钮。三个按钮分别通过connect链接下面几个槽即可。另外代码中的self.win是主窗口的引用,如果使用self.window()获取的有些时候无法准确的获取到对应的值而使得功能失效,我这里选择用一个变量保存来进行操作,当然也可以通过另外两种方式:
- 通过信号槽将鼠标事件发送出去
- 通过实践过滤器eventFliter在主窗口中为标题栏Widget安装事件进一步处理。
我这里有个小问题,因为self.win是用来存放主界面的,因此标题栏窗口不能独立的存在,如果强行将主窗口设为None创建的话,窗口能显示但是最大化等功能不能执行,这个可以自行修改,这到不难,判断下win是否为None,是的话对本窗口操作即可。
#最小化窗口
def ShowMininizedWindow(self):
self.win.showMinimized()
#最大化窗口
def ShowMaximizedWindow(self):
self.win.showMaximized()
#复原窗口
def ShowRestoreWindow(self):
if self.win.isMaximized():
self.win.showNormal()
else:
self.win.showMaximized()
#关闭窗口
def CloseWindow(self):
self.win.close()
事件触发,鼠标单击、双击和移动的事件。
def mouseDoubleClickEvent(self, event):
self.ShowRestoreWindow()
return QWidget().mouseDoubleClickEvent(event)
def mousePressEvent(self, event):
self.isPressed = True
self.startPos = event.globalPos() #记录鼠标点击的位置
return QWidget().mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.isPressed = False
return QWidget().mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
#计算窗口应该移动的距离
movePos = event.globalPos() - self.startPos
self.startPos = event.globalPos()
self.win.move(self.win.pos() + movePos)
return QWidget().mouseMoveEvent(event)
(3)完整代码
代码中的图标,等一下参数是我自己定义的,可以在最后的源代码中查看。
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from default import *
class TitleBar(QWidget):
def __init__(self, parent):
super(TitleBar, self).__init__()
self.win = parent
self.InitializeWindow()
def InitializeWindow(self):
self.isPressed = False
self.setFixedHeight(TITLE_BAR_HEIGHT)
self.InitializeViews()
pass
def InitializeViews(self):
self.iconLabel = QLabel(self)
self.titleLabel = QLabel(self)
self.minButton = QPushButton(self)
self.restoreButton = QPushButton(self)
self.closeButton = QPushButton(self)
self.minButton.setFixedSize(TITLE_BUTTON_SIZE, TITLE_BUTTON_SIZE);
self.restoreButton.setFixedSize(TITLE_BUTTON_SIZE, TITLE_BUTTON_SIZE);
self.closeButton.setFixedSize(TITLE_BUTTON_SIZE, TITLE_BUTTON_SIZE);
self.iconLabel.setFixedSize(TITLE_LABEL_SIZE, TITLE_LABEL_SIZE);
self.titleLabel.setFixedHeight(TITLE_LABEL_SIZE);
self.iconLabel.setAlignment(Qt.AlignCenter);
self.titleLabel.setAlignment(Qt.AlignCenter);
self.minButton.setIcon(QIcon(TITLE_MIN_ICON));
self.restoreButton.setIcon(QIcon(TITLE_RESTORE_ICON));
self.closeButton.setIcon(QIcon(TITLE_CLS_ICON));
self.minButton.clicked.connect(self.ShowMininizedWindow)
self.restoreButton.clicked.connect(self.ShowRestoreWindow)
self.closeButton.clicked.connect(self.CloseWindow)
self.lay = QHBoxLayout(self)
self.setLayout(self.lay)
self.lay.setSpacing(0)
self.lay.setContentsMargins(0, 0, 0, 0)
self.lay.addWidget(self.iconLabel)
self.lay.addWidget(self.titleLabel)
self.lay.addWidget(self.minButton)
self.lay.addWidget(self.restoreButton)
self.lay.addWidget(self.closeButton)
def ShowMininizedWindow(self):
self.win.showMinimized()
def ShowMaximizedWindow(self):
self.window.showMaximized()
def ShowRestoreWindow(self):
if self.win.isMaximized():
self.win.showNormal()
else:
self.win.showMaximized()
def CloseWindow(self):
self.win.close()
def SetTitle(self, str):
self.titleLabel.setText(str)
def SetIcon(self, pix):
self.iconLabel.setPixmap(pix.scaled(self.iconLabel.size() - QSize(TITLE_ICON_MAG, TITLE_ICON_MAG)))
def mouseDoubleClickEvent(self, event):
self.ShowRestoreWindow()
return QWidget().mouseDoubleClickEvent(event)
def mousePressEvent(self, event):
self.isPressed = True
self.startPos = event.globalPos()
return QWidget().mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.isPressed = False
return QWidget().mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.isPressed:
if self.win.isMaximized:
self.win.showNormal()
movePos = event.globalPos() - self.startPos
self.startPos = event.globalPos()
self.win.move(self.win.pos() + movePos)
return QWidget().mouseMoveEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = TitleBar(None)
win.show()
sys.exit(app.exec_())
pass
(4)美化(QSS)
Qss是Qt的界面样式,直接挪用Qt的就可以,官方参考地址:
QSS Help
颜色是从Visual Studio中取的。
QWidget
{
background-color:#313034;
color:#f1f1f1;
font-size:12px;
border:2px solid #423f48;
font: "Tlwg Typo";
margin:0px;
}
QMainWindow
{
}
QPushButton
{
border:none;
width:35px;
}
QPushButton:hover
{
background-color:#423f48;
}
QPushButton:pressed
{
background-color:#444444;
}
QLabel
{
background-color:#2A292B;
border:none;
}
3.源代码链接
里面有C++的和Python的代码,C++的使用Visual Studio+Qt写的。
源代码链接