Python3 PyQt5 窗口(国际化/QMainWindow/QWidget/QDialog)
本文由 Luzhuo 编写,转发请保留该信息.
原文:/Rozol/article/details/87904498
PyQt5基本介绍见: PyQt5 Qt Designer (Qt设计师)
简介
窗口主要分为:QMainWindow(主窗口) / QWidget(基本窗口) / QDialog(对话框)这三种.
QWidget: 最基本的窗口QMainWindow: 在 QWidget 的基础上多了 菜单栏 / 工具栏 / 状态栏 / 标题栏 等QDialog: 对话框窗口
使用的话:
1.如果是主窗口, 需要菜单栏之类的, 就用QMainWindow.
2.如果是对话框, 就用QDialog.
3.其他不确定的窗口, 都可以用QWidget.
文本国际化
这里先讲下文本国际化, 如果不进行国际化, 那么你运行之后, 发现控件都是英文的.
自带的国际化
PyQt5自带的翻译文件在C:\Code\Python_Vir\python1\Lib\site-packages\PyQt5\Qt\\translations\
目录下,不过翻译并不完全, 由于已经被编译成.qm
文件, 你也改不了它.
from PyQt5.Qt import QTranslator, QLocale, QLibraryInfotranslator = QTranslator(app)if translator.load("qt_" + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath)):app.installTranslator(translator)
效果:
自定义的国际化
编写文本时, 有原来的"content"
变成现在的self.tr("content")
, 其他除了要先加载翻译者之外, 均不变.
def initUI(self):# 加载翻译文件translator = QTranslator(app)if translator.load('qt_zh_CN'):app.installTranslator(translator)btn = QPushButton(self.tr("Color"), self)btn.clicked.connect(self.click)self.setGeometry(300, 300, 550, 350)self.setWindowTitle('Dialog')self.show()btn = QPushButton(self.tr("Color"), self)btn.clicked.connect(self.click)def click(self):QColorDialog.getColor()
1.生成.ts文件
# 创建.ts文件, 存在则更新pylupdate5 international.py -ts qt_zh_CN.ts
2.打开Linguist进行手动翻译, 翻译完点保存
linguist qt_zh_CN.ts
3.生成.qm文件
lrelease qt_zh_CN.ts
效果:
自己写的是实现了国际化, 原生的英文界面你也拿它没辙.
另外翻译出现问题可以通过修改.ts来修正.
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE TS><TS version="2.1" language="zh_CN"><context><name>Widget</name><message><location filename="international.py" line="24"/><source>Color</source><translatorcomment>颜色</translatorcomment><translation>颜色</translation></message></context></TS>
比如代码位置变了, 会给你打个过时的标签, 如
<translation type="obsolete">取消</translation>
这时只需要把type="obsolete"
删掉, 然后把line="24"
改成正确的行就行了.
另外, 其实翻译只需要<translation>颜色</translation>
标签就够了,<translatorcomment>颜色</translatorcomment>
可有可无.
自带的国际化 + 自定义的国际化
只需要同时加载两个翻译者就好了.
def initUI(self):# 加载翻译文件translator_sys = QTranslator(app)translator_my = QTranslator(app)if translator_sys.load("qt_" + QLocale.system().name(), QLibraryInfo.location(QLibraryInfo.TranslationsPath)) and translator_my.load('qt_zh_CN'):app.installTranslator(translator_sys)app.installTranslator(translator_my)btn = QPushButton(self.tr("Color"), self)btn.clicked.connect(self.click)self.setGeometry(300, 300, 550, 350)self.setWindowTitle('Dialog')self.show()def click(self):QColorDialog.getColor()
效果:
如果需要切换语言
app.removeTranslator(translator_my)app.installTranslator(translator_sys)
注: 为了敲代码效率, 我的所有案例代码都不会用self.tr("xxx")
这种方式来写, 而是直接写"xxx"
, 包括这篇文章的以下代码.
QMainWindow 主窗口
QMainWindow 是一个顶层窗口(没有父窗口), 包含了 MenuBar(菜单栏) / ToolBars(工具栏) / Dock Widgets(停靠控件区) / Status Bar(状态栏), 中心窗口区被一个 QWidget 占着, 可通过setCentralWidget()
来设置(不能通过 setLayout() 设置).
创建主窗口
我们有两种方式创建, 第一种是创建对象, 第二种是继承类, 一般我们会采用第二种, 包括博客文章的案例代码采用这种方式.
第一种: 创建对象方式
#!/usr/bin/env python# coding=utf-8__author__ = 'Luzhuo'__date__ = '/2/19'# QMainWindow 创建主窗口import sysfrom PyQt5.QtWidgets import QApplication, QMainWindowfrom PyQt5.QtGui import QIcondef mainwindow1():'''方式一: 通过创建对象方式创建主窗口'''# 每个PyQt5应用都要创建一个应用对象 (sys.argv是一组命令行参数列表)app = QApplication(sys.argv)# 主窗口w = QMainWindow()w.setGeometry(300, 300, 550, 350)w.setWindowTitle('我是窗口标题')w.setWindowIcon(QIcon('icon.png')) # 设置图标w.show() # 展示该控件# 退出主程序sys.exit(app.exec_())if __name__ == '__main__':mainwindow1()
第二种: 继承类方式
class MainWindow(QMainWindow):'''方式二: 通过继承类方式创建主窗口'''def __init__(self):super().__init__()self.initUI()def initUI(self):self.setGeometry(300, 300, 550, 350)self.setWindowTitle('我是窗口标题')self.setWindowIcon(QIcon('icon.png')) # 设置图标self.show() # 展示该控件if __name__ == '__main__':app = QApplication(sys.argv)ex = MainWindow()sys.exit(app.exec_())
效果:
窗口位置与大小
我们有三种方式设置窗口的位置与大小:
第一种:
self.resize(550, 350) # 改变窗口大小(px)self.move(300, 300) # 移动控件位置(px)
第二种 (是第一种两方法的结合):
self.setGeometry(300, 300, 550, 350) # 放在屏幕上并设置大小
第三种 (居中显示):
qr = self.frameGeometry() # 得到应用主窗体大小cp = QDesktopWidget().availableGeometry().center() # QDesktopWidget 得到桌面大小, availableGeometry 得到屏幕分辨率, center 得到中间点坐标qr.moveCenter(cp) # 将 应用中间点 移到 屏幕中间点self.resize(550, 350)self.move(qr.topLeft()) # 将 应用左上标 设为 矩形左上标
窗口的几何结构:
窗口分为 不含外边框的几何结构 和 含外边框的几何结构.
# --- 无边框几何结构 ---# 修改客户区的大小(鼠标可修改)self.resize(550, 350)self.resize(QSize(550, 350))self.setGeometry(300, 300, 550, 350)self.setGeometry(QRect(300, 300, 550, 350))# 修改客户区的大小(鼠标不可修改)self.setFixedWidth(550) # 宽度固定 (高度可变)self.setFixedHeight(350) # 高度固定self.setFixedSize(550, 350) # 宽度与高度都固定self.setFixedSize(QSize(550, 350))# 获取客户区大小qsize = self.size()qrect = self.geometry()width = self.width()height = self.height()print("QSize - width:{w} height:{h}".format(w=qsize.width(), h=qsize.height()))print("QRect - x:{x} y:{y} width:{w} height:{h}".format(x=qrect.x(), y=qrect.y(), w=qrect.width(), h=qrect.height()))print("width:{w} height:{h}".format(w=width, h=height))# --- 有边框几何结构 ---# 设置窗口位置self.move(300, 300)self.move(QPoint(300, 300))# 获取窗口位置与大小qrect = self.frameGeometry() # 位置和大小qpoint = self.pos() # 左上角坐标print("QRect - x:{x} y:{y} width:{w} height:{h}".format(x=qrect.x(), y=qrect.y(), w=qrect.width(), h=qrect.height()))print("QRect - x:{x} y:{y}".format(x=qpoint.x(), y=qpoint.y()))
关闭窗口
关闭窗口, 除了点击右上角的红×退出外, 还有自己写退出的逻辑(与退出槽连接).
退出应用的信号槽连接:
qbtn.clicked.connect(QCoreApplication.instance().quit)
完整代码:
import sysfrom PyQt5.QtWidgets import QApplication, QMainWindow, QPushButtonfrom PyQt5.QtCore import QCoreApplicationclass MainWindow(QMainWindow):'''退出窗口'''def __init__(self):super().__init__()self.initUI()def initUI(self):qbtn = QPushButton('Quit', self)qbtn.resize(qbtn.sizeHint())qbtn.move(50, 50)# 按钮的点击信号 与 应用退出槽 进行连接qbtn.clicked.connect(QCoreApplication.instance().quit)self.setGeometry(300, 300, 550, 350)self.setWindowTitle('窗口的关闭')self.show()if __name__ == '__main__':app = QApplication(sys.argv)ex = MainWindow()sys.exit(app.exec_())
应用退出事件:
如果你想在应用退出时做点操作, 比如弹出个对话框之类的. 那么就需要重写def closeEvent(self, event):
方法
def closeEvent(self, event):if True:event.accept() # 执行事件else:event.ignore() # 忽略事件
MenuBar 菜单栏
菜单栏由 菜单栏 / 菜单 / 子菜单 / 动作 组成.
创建动作:
jumpAct = QAction(QIcon('icon.png'), '&Jump to Source', self) # 图标 / exit标签jumpAct.setShortcut('F4') # 快捷键jumpAct.setStatusTip('这是 Jump to Source 的提示信息') # 状态栏提示信息jumpAct.triggered.connect(qApp.quit) # 触发 quit 事件
创建子菜单:
impMenu = QMenu('Tool Windows', self)impMenu.addAction(strucAct) # 往子菜单添加一个动作
创建菜单:
viewMenu = menubar.addMenu('&View') # 添加View菜单viewMenu.addMenu(impMenu) # 添加子菜单viewMenu.addSeparator() # 添加分隔线viewMenu.addAction(jumpAct) # 添加 动作
创建菜单栏:
menubar = self.menuBar()
完整代码:
import sysfrom PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp, QMenufrom PyQt5.QtGui import QIconclass MainWindow(QMainWindow):'''菜单栏'''def __init__(self):super().__init__()self.initUI()def initUI(self):# 创建动作jumpAct = QAction(QIcon('icon.png'), '&Jump to Source', self) # 图标 / exit标签jumpAct.setShortcut('F4') # 快捷键jumpAct.setStatusTip('这是 Jump to Source 的提示信息') # 状态栏提示信息jumpAct.triggered.connect(qApp.quit) # 触发 quit 事件strucAct = QAction(QIcon('icon.png'), '&Structure', self)strucAct.setShortcut("Alt+7")# 创建子菜单impMenu = QMenu('Tool Windows', self)impMenu.addAction(strucAct) # 往子菜单添加一个动作# 创建菜单栏menubar = self.menuBar()# 创建菜单viewMenu = menubar.addMenu('&View') # 添加View菜单viewMenu.addMenu(impMenu) # 添加子菜单viewMenu.addSeparator() # 添加分隔线viewMenu.addAction(jumpAct) # 添加 动作self.setGeometry(300, 300, 550, 350)self.setWindowTitle('菜单栏')self.show()if __name__ == '__main__':app = QApplication(sys.argv)ex = MainWindow()sys.exit(app.exec_())
效果:
勾选动作:
当然, 菜单里的动作除了上述比较常见的外, 还有一种动作, 叫勾选动作
statusbarAct = QAction('View statusbar', self, checkable=True)statusbarAct.setStatusTip('View statusbar')statusbarAct.setChecked(True) # True为默认选中状态statusbarAct.triggered.connect(self.toggleMenu)
效果:
右键上下菜单:
菜单除了出现在菜单栏, 它还有一种形式, 就是我们采用的右键菜单.
有实现右键菜单, 就要重写 上下文菜单事件 (def contextMenuEvent(self, event):
)
1.创建子菜单, 并添加动作
cmenu = QMenu(self)quitAct = cmenu.addAction("Quit")
2.获取用户选择的动作, 然后就动作进行判断是哪个动作
action = cmenu.exec_(self.mapToGlobal(event.pos())) # mapToGlobal 将组件相对坐标转为窗口绝对坐标, exec_ 显示菜单# 如果触发的动作为 quitAct 则退出应用if action == quitAct:qApp.quit()
完整代码
def contextMenuEvent(self, event):'''右键上下文菜单'''# 创建子菜单, 并添加动作cmenu = QMenu(self)newAct = cmenu.addAction("New")opnAct = cmenu.addAction("Open")quitAct = cmenu.addAction("Quit")action = cmenu.exec_(self.mapToGlobal(event.pos())) # mapToGlobal 将组件相对坐标转为窗口绝对坐标, exec_ 显示菜单# 如果触发的动作为 quitAct 则退出应用if action == quitAct:qApp.quit()
效果:
ToolBars 工具栏
工具栏主要是为了方便用户使用而存在的, 其功能都应该能够在菜单栏找到(大学设计书上是这么说的, 不过菜单栏没这功能又能把我咋地 _)
创建一个动作
# 创建一个动作exitAct = QAction(QIcon('icon.png'), 'Exit', self)exitAct.setShortcut('Ctrl+Q')exitAct.triggered.connect(qApp.quit)
把这个动作添加到工具栏
# 将(Exit)动作添加到工具栏self.toolbar = self.addToolBar('Exit') # 添加Exit工具栏self.toolbar.addAction(exitAct)
效果
添加控件:
ToolBar除了能添加动作外, 还能添加任意控件.
lineEdit = QLineEdit()self.toolbar.addSeparator() # 分隔线self.toolbar.addWidget(lineEdit)
Dock Widgets 停靠控件区
停靠空间区的布局嵌套是有QDockWidget来完成的.
需要创建一个Widget设置到DockWidget上.
1.创建Widget
w = QWidget()
2.创建DockWidget
dock = QDockWidget("窗口1")dock.setWidget(w) # 为 dockwidget 设置 widgetdock.setFeatures(dock.DockWidgetFloatable | dock.DockWidgetMovable) # 设置特征(DockWidgetFeature)self.addDockWidget(Qt.LeftDockWidgetArea, dock) # 添加 dockwidget 到主窗口
效果:
嵌套布局:
当你添加多个 DockWidget 到主窗口时, 你会发现这些窗口只能往左右放, 若要实现往两 DockWidget 中间放, 则要开启嵌套.
self.setDockNestingEnabled(True)
排列组合:
若要将这些小窗口按水平(或垂直 或水平+垂直)排列, 将其水平分隔成同样的宽度.
self.splitDockWidget(win1Dock, win2Dock, Qt.Horizontal)self.splitDockWidget(win2Dock, win3Dock, Qt.Horizontal)self.splitDockWidget(win1Dock, win4Dock, Qt.Vertical)
tab页:
多个窗口合成一个窗口, 窗口通过tab标签切换.
self.tabifyDockWidget(win1Dock, win2Dock)
综合代码
def getDock(self, name):w = QWidget()dock = QDockWidget(name)dock.setWidget(w)dock.setFeatures(dock.DockWidgetFloatable | dock.DockWidgetMovable)return dockdef initUI(self):win1Dock = self.getDock("win1")win2Dock = self.getDock("win2")win3Dock = self.getDock("win3")win4Dock = self.getDock("win4")self.addDockWidget(Qt.LeftDockWidgetArea, win1Dock)self.addDockWidget(Qt.RightDockWidgetArea, win2Dock)self.addDockWidget(Qt.BottomDockWidgetArea, win3Dock)self.addDockWidget(Qt.BottomDockWidgetArea, win4Dock)# 实现任意嵌套self.setDockNestingEnabled(True)# 实现分隔 (可水平 / 垂直 / 垂直+水平 从而实现任意效果)self.splitDockWidget(win1Dock, win2Dock, Qt.Horizontal)self.splitDockWidget(win2Dock, win3Dock, Qt.Horizontal)self.splitDockWidget(win1Dock, win4Dock, Qt.Vertical)# tab页self.tabifyDockWidget(win1Dock, win2Dock)
综合效果
QtWidgets.QDockWidget.DockWidgetFeature
QtCore.Qt.DockWidgetArea
Status Bar 状态栏
状态栏一般显示一些提示信息, 可以是临时的, 也可以是永久的.
一般在 状态栏的左侧 显示 实时信息, 而在其右侧显示 永久信息.
显示实时信息:
self.statusbar = self.statusBar()self.statusbar.showMessage('这是状态栏信息')self.statusbar.showMessage('这是状态栏信息', 5 * 1000) # 提示5s消失
添加控件:
label1 = QLabel("This is a Label")label2 = QLabel("CopyRight @ Luzhuo.me ")# addWidget 在左侧添加临时控件self.statusbar.addWidget(label1)# addWidget 在右侧添加永久控件self.statusbar.addPermanentWidget(label2)
效果:
QWidget 基本窗口
QWidget 是所有用户界面对象的基类. 准确的说它并不属于窗口类型, 而是属于控件类型.
注: 只有Slots的表格, 注释与实际执行一致; 有Func & Slots的表格, ()内为Slots的执行效果, 没有()的为两者实际执行一致
窗口:
方法:
bool_isW = self.isWindow() # 是否为独立窗口widget = self.window() # 当前部件所在的独立窗口widget_parent = self.parentWidget() # 得到父窗口
窗口样式:
默认窗口样式 是使用 当前操作系统的原生窗口样式, 在不同的操作系统下原生窗口样式显示的效果不一样.
我们可以定制窗口样式.
窗口类型 (|组合):
窗口外观标志:
自定义窗口:
其他高大上的标志:
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.MSWindowsFixedSizeDialogHint | Qt.Dialog)
窗口风格:
方法:
list_style = QStyleFactory.keys() # 当前平台支持的 QStyle 窗口风格样式self.setStyle(QStyleFactory.create(list_style[1])) # 设置窗口风格QApplication.setStyle(QStyleFactory.create("WindowsXP")) # 给 App 设置窗口风格, 其他Widget默认(无设置)使用App的风格
窗口最大化:
上面4个既是函数, 又是槽
self.showMaximized() # 是函数, 也是槽
窗口的最大化, 还有这种方式可以调用
self.setWindowState(Qt.WindowMaximized)
方法:
windowStates = self.windowState() # 获取状态ismin = self.isMinimized() # 判断窗口是否为最小化ismax = self.isMaximized() # 判断窗口是否为最大化isfull = self.isFullScreen() # 判断窗口是否为全屏
禁用窗口:
禁用该窗口, 会使该窗口里所有控件处于不能被使用状态.
没错, 这是一个槽
上面2个方法既是函数, 也是槽, 但是效果缺是相反的, 尴尬…
self.setDisabled(True) # 启用该窗口 (与槽效果相反)
方法:
isenable = self.isEnabled() # 该窗口是否启用isaction = self.isActiveWindow() # 判断该窗口是否激活self.activateWindow() # 设置窗口为激活状态
窗口的可见
self.setVisible(True) # 设置可见 (与槽效果相反)
方法:
isVisible = self.isVisible() # 窗口是否可见isHidden = self.isHidden() # 窗口是否隐藏self.setVisible(True) # 设置可见self.setHidden(True) # 设置隐藏
还有几个可以复写的事件:
def closeEvent(self, QCloseEvent):'''关闭'''passdef showEvent(self, QShowEvent):'''显示'''passdef hideEvent(self, QHideEvent):'''隐藏'''passdef mouseMoveEvent(self, QMouseEvent):'''移动'''point_old = QMouseEvent.oldPos() # 旧坐标point_new = QMouseEvent.newPos() # 新坐标def resizeEvent(self, QResizeEvent):'''大小改变'''size_old = QResizeEvent.oldSize() # 旧大小size_new = QResizeEvent.newSize() # 新大小
焦点:
self.setFocus() # 使窗口获得焦点
方法
hashFocus = self.hasFocus() # 判断窗口是否获得焦点self.clearFocus() # 使窗口失去焦点widget = self.focusWidget() # 得到窗口内获得焦点的子窗口
他还有两个可以复写的方法
def focusInEvent(self, QFocusEvent):'''获得焦点'''passdef focusOutEvent(self, QFocusEvent):'''失去焦点'''pass
鼠标与键盘:
方法:
self.grabKeyboard() # 捕获键盘事件self.releaseKeyboard() # 释放键盘事件self.grabMouse() # 捕获鼠标事件self.releaseMouse() # 释放鼠标事件widget = self.keyboardGrabber() # 得到正在捕获键盘事件的窗口widget = self.mouseGrabber() # 得到正在捕获鼠标事件的窗口
几个可复写的键盘事件
def keyPressEvent(self, QKeyEvent):'''键盘按下'''int_key = QKeyEvent.key() # 得到键值if int_key == Qt.Key_Escape:passdef keyReleaseEvent(self, QKeyEvent):'''键盘松开'''pass
几个可复写的鼠标事件:
def mousePressEvent(self, QMouseEvent):'''鼠标按下'''passpoint = QMouseEvent.pos() # 鼠标(相对)坐标int_x = QMouseEvent.x() # 鼠标(相对)x坐标int_y = QMouseEvent.y() # 鼠标(相对)y坐标point_g = QMouseEvent.globalPos() # 鼠标(全局)坐标int_gx = QMouseEvent.globalX() # 鼠标(全局)x坐标int_gy = QMouseEvent.globalY() # 鼠标(全局)y坐标mouseButton = QMouseEvent.button() # 引起事件的鼠标键mouseButtons = QMouseEvent.buttons() # 事件发生时的鼠标键状态 (|组合)'''Qt.MouseButton 的枚举 | Description--- | ---Qt.NoButton | 无键Qt.LeftButton | 左键Qt.RightButton | 右键Qt.MidButton | 中键'''if mouseButton == Qt.LeftButton:passdef mouseReleaseEvent(self, QMouseEvent):'''鼠标松开'''passdef mouseDoubleClickEvent(self, QMouseEvent):'''鼠标双击'''passdef mouseMoveEvent(self, QMouseEvent):'''鼠标移动 (默认需要按下)# 开启鼠标追踪(不需要按下)self.setMouseTracking(True)'''mouseButton = QMouseEvent.button() # Move事件 总是返回 Qt.NoButtondef enterEvent(self, QEvent):'''鼠标进入窗体'''passdef leaveEvent(self, QEvent):'''鼠标离开窗体'''passdef wheelEvent(self, QWheelEvent):'''鼠标滚轮滚动'''int_delta = QWheelEvent.delta() # 滚轮转动的角度orientation = QWheelEvent.orientationI() # 滚轮转动的方向'''Qt.Orientation 的枚举 | Description--- | ---Qt.Horizontal | 横向Qt.Vertical | 纵向'''if orientation == Qt.Horizontal:pass
上述的鼠标移动事件只有按下时才追踪, 如果想不按下就追踪, 则要加上下面这段代码
# 开启鼠标追踪(不需要按下)self.setMouseTracking(True)
布局:
方法
self.setLayout(QLayout()) # 设置顶级布局layout = self.layout() # 获得顶级布局
字体:
方法
self.setFont(QFont()) # 设置字体font = self.font() # 获得字体
关于事件的处理:
def enterEvent(self, QEvent):# 事件的处理if True:QEvent.accept() # 接受事件else:QEvent.ignore() # 忽略事件# 事件被忽略后: 关闭事件 - 窗口将不会被关闭; 键盘、鼠标等输入事件 - 向上传播到父窗口pass
QToolTip 提示泡泡
设置泡泡字体
QToolTip.setFont(QFont('SansSerif', 10))
在需要提示的Widget上使用
self.setToolTip('This is a <b>QWidget</b> widget')
案例: 在Widget 和 PushButton 上添加提示泡泡
def initUI(self):# 设置字体QToolTip.setFont(QFont('SansSerif', 10))self.setToolTip('This is a <b>QWidget</b> widget')btn = QPushButton('Button', self)btn.setToolTip('This is a <b>QPushButton</b> widget')btn.resize(btn.sizeHint()) # sizeHint 为默认大小btn.move(50, 50)
效果:
QDialog 对话框
QDialog中还有几个与打印相关的对话框(QAbstractPrintDialog / QPageSetupDialog / QPrintDialog / QPrintPreviewDialog)全部放到打印里讲
QDialog
该Dialog是可以自己放控件来设计它的样子和作用, 当然系统也内置很多设计好的Dialog, 如: QColorDialog / QFileDialog / QMessageBox 等等.
案例
import sysfrom PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QDialogfrom PyQt5.Qt import Qtclass MyDialog(QDialog):def __init__(self):super().__init__()self.initUI()def initUI(self):self.setWindowTitle("My Dialog")self.resize(200, 100)self.btn = QPushButton("ok", self)self.btn.clicked.connect(self.close)'''Qt.WindowModality | Description--- | ---Qt.NonModal | 非模态, 可与其他窗口交互Qt.WindowModal | 窗口模态, 未处理完当前对话框, 将阻止与对话框父窗口交互Qt.ApplicationModal | 应用程序模态, 阻止和任何其他窗口交互'''self.setWindowModality(Qt.ApplicationModal)# self.exec_()def text(self):return self.btn.text()@staticmethoddef getText():dialog = MyDialog()dialog.exec_()text = dialog.text()return text
使用的话也很简单:
text = MyDialog.getText()print(text)
QMessageBox 消息盒子
消息盒子主要弹出: 提示 / 警告 / 错误 / 询问 / 关于 等等对话框, 不过仅仅是体现在显示的图标不同
主要方法:
主要方法:msgBox.setWindowTitle("默认1") # 设置标题msgBox.setText("The document has been modified.") # 主文本msgBox.setInformativeText("Do you want to save your changes?") # 副文本msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) # 按钮smsgBox.setDefaultButton(QMessageBox.Save) # 默认(选中)按钮msgBox.setDetailedText("If the detailed text property is set...") # 详情按钮msgBox.setIcon(QMessageBox.Question) # 图标msgBox.setIconPixmap(QPixmap('icon.png'))ret = msgBox.exec_()# 上述的综合体ret = QMessageBox.question(self, 'Question', "The document has been modified...", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
分别设置:
# 默认1msgBox = QMessageBox()msgBox.setWindowTitle("默认1")msgBox.setText("The document has been modified.")msgBox.exec_()# 默认2 (+按钮)msgBox = QMessageBox()msgBox.setWindowTitle("默认2")msgBox.setText("The document has been modified.") # 主文本msgBox.setInformativeText("Do you want to save your changes?") # 副文本msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) # 按钮smsgBox.setDefaultButton(QMessageBox.Save) # 默认(选中)按钮ret = msgBox.exec_()if ret == QMessageBox.Save:passelif ret == QMessageBox.Discard:passelif ret == QMessageBox.Cancel:passelse:pass# 默认3 (+DetailedText)msgBox = QMessageBox()msgBox.setWindowTitle("默认3")msgBox.setText("The document has been modified.")# 增加详情按钮msgBox.setDetailedText("If the detailed text property is set, the Show Details… button will be shown.")msgBox.exec_()# 默认4 (+icon)msgBox = QMessageBox()msgBox.setWindowTitle("默认4")msgBox.setText("The document has been modified.")msgBox.setIcon(QMessageBox.Question)msgBox.exec_()
效果:
综合体:
对话框类型与图标
支持的带类型的对话框, 除了NoIcon没有之外, 其余4个都有, 其效果与代码都是效果的, 就是改变图标而已.
外加一个 about, 显示没有图标, 代码没有按钮.
# 创建消息盒子 (父窗口 / 标题 / 内容 / 按钮s / 默认(选中)按钮)ret = QMessageBox.question(self, 'Question', "The document has been modified.\nDo you want to save your changes?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)# 除了上述4种外(除NoIcon), 还有个 aboutret = QMessageBox.about(self, 'About', "The document has been modified.")
效果:
按钮:
中文按钮名:
默认的按钮名都是英文的, 若要中文显示则需要处理.
# 如果要中文按钮名, 则要自己添加按钮msgBox = QMessageBox(self)disconnectbtn = msgBox.addButton("中文按钮", QMessageBox.ActionRole)abortbtn = msgBox.addButton(QMessageBox.Abort)msgBox.exec_()if msgBox.clickedButton() == disconnectbtn:passelif msgBox.clickedButton() == abortbtn:pass
效果:
案例:
举个栗子, 我们在关闭窗口时弹出消息盒子.
def closeEvent(self, event):'''举个栗子, 我们在关闭窗口时弹出消息盒子.'''msgBox = QMessageBox(self)msgBox.setWindowTitle('关闭')msgBox.setText('是否保存?')msgBox.setIcon(QMessageBox.Question)btn_dontsave = msgBox.addButton('不保存', QMessageBox.AcceptRole)btn_cancel = msgBox.addButton('取消', QMessageBox.RejectRole)btn_save = msgBox.addButton('保存', QMessageBox.AcceptRole)msgBox.setDefaultButton(btn_save)msgBox.exec_()if msgBox.clickedButton() == btn_dontsave:print('不保存')event.accept()elif msgBox.clickedButton() == btn_cancel:event.ignore()elif msgBox.clickedButton() == btn_save:print('保存')event.accept()
效果:
QInputDialog 可输入对话框
输入对话框由 一个文本框 和 两个按钮组成, 用户点击ok(或 Enter 键), Dialog收集输入数据返回.
text, ok = QInputDialog.getText(self, 'getText', '请输入文本')if ok and text:print(text)text, ok = QInputDialog.getMultiLineText(self, 'getMultiLineText', '请输入文本', "默认文本")if ok and text:print(text)# 父控件 / 标题 / 文本 / 默认值 / 最小值 / 最大值 / 小数位数double, ok = QInputDialog.getDouble(self, 'getDouble', '请输入浮点数', 37.56, -10000, 10000, 2)if ok:print(double)# 父控件 / 标题 / 文本 / 默认值 / 最小值 / 最大值 / 步进int, ok = QInputDialog.getInt(self, 'getInteger', '请输入整数', 25, 0, 100, 1)if ok:print(int)items = ["Spring", "Summer", "Fall", "Winter"]# 父控件 / 标题 / 文本 / list of strings 数据 / 默认值 / 可编辑item, ok = QInputDialog.getItem(self, 'getItem', '请选择条目', items, 0, False)if ok and item:print(item)
效果:
中文按钮名:
dialog = QInputDialog(self)dialog.setWindowTitle('getText')dialog.setLabelText('请输入文本')dialog.setOkButtonText('确定')dialog.setCancelButtonText('取消')ok = dialog.exec_()text = dialog.textValue()if ok and text:print(text)
效果
QFontDialog 字体选择对话框
用户可以选择文本的字号大小 / 样式 / 格式 等.
def initUI(self):btn = QPushButton('打开字体选择对话框', self)btn.clicked.connect(self.showDialog)self.lbl = QLabel('Knowledge only matters', self)self.lbl.move(0, 50)self.setGeometry(300, 300, 550, 350)self.setWindowTitle('Dialog')self.show()def showDialog(self):font, ok = QFontDialog.getFont()if ok:self.lbl.setFont(font)self.lbl.adjustSize()
效果:
中文按钮及汉化:
使用系统翻译库吧
QFileDialog 文件对话框
用于文件的打开和保存, 可以打开指定扩展名的文件, 也可以设置起始目录.
# (标题 / 默认路径['/home' | 'C:\我的电脑'] / 过滤文件类型)# 路径: "."代表程序运行路径(默认) / "/"代表根目录(win+linux)fname = QFileDialog.getOpenFileName(self, 'Open file', 'C:\我的电脑', 'Image files (*.jpg *.png *.gif)')# ('C:/5560WIA.txt', 'All Files (*)')# ('C:/我的电脑/xxx.png', 'Image files (*.jpg *.png *.gif)')print(fname)files = QFileDialog.getOpenFileNames(self, "Select one or more files to open", ".", "Images (*.png *.xpm *.jpg)")dir = QFileDialog.getExistingDirectory(self, "Open Directory", ".", QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)fileName = QFileDialog.getSaveFileName(self, "Save File", "C:\我的电脑\\untitled.png", "Images (*.png *.xpm *.jpg)")
当然也可以分别设置:
dialog = QFileDialog()dialog.setFileMode(QFileDialog.AnyFile)if dialog.exec_():filename = dialog.selectedFiles()print(filename) # ['C:/Code/Python/PyQt5Demo2/icon.png']
效果:
窗口显示模式, 不过在win10上没效果
dialog.setViewMode(QFileDialog.Detail) # 设置视图模式 (win10没效果)
必选文件模式:
dialog.setFileMode(QFileDialog.AnyFile) # 指定必选文件模式
过滤写法:
'''过滤单个:Images (*.png *.xpm *.jpg)过滤多个:"Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"'''dialog.setNameFilter("Images (*.png *.xpm *.jpg)") # 设置过滤文件名类型
中文按钮及汉化
不存在该问题, 调用的是系统控件
QColorDialog 颜色选择对话框
self.frm = QFrame(self)self.frm.setGeometry(10, 10, 100, 100)# 默认颜色 / 父控件 / 标题col = QColorDialog.getColor(Qt.blue, self, '选择颜色')if col.isValid():self.frm.setStyleSheet("QWidget { background-color: %s }" % col.name())
效果:
直接创建颜色:
col = QColor(0, 0, 0)
中文按钮及汉化:
使用系统翻译库吧
QProgressDialog 进度对话框
def initUI(self):self.min = 0self.max = 100self.progress = QProgressDialog("Copying files...", "Abort Copy", self.min, self.max, self)self.progress.setWindowModality(Qt.WindowModal)self.progress.canceled.connect(self.cancel)self.timer = QBasicTimer()self.step = 0if self.timer.isActive():self.timer.stop()else:self.timer.start(100, self)self.setGeometry(300, 300, 550, 350)self.setWindowTitle('Dialog')self.show()def timerEvent(self, e):if self.step >= self.max:self.timer.stop()return# ... copy one fileself.step = self.step + 1self.progress.setValue(self.step)def cancel(self):print("你Y的, 竟然取消了")self.timer.stop()
效果:
中文按钮及汉化:
全换成中文就好了
QErrorMessage 错误提示
# 方式一err = QErrorMessage(self)err.showMessage("这是显示的错误信息")# 方式二 默认输出错误信息, 没有则创建, 推荐该方法QErrorMessage.qtHandler().showMessage("这里显示的错误信息")
show this message again
√去掉, 下次显示将不执行(不显示)
效果:
中文按钮及汉化:
使用系统翻译库吧
QWizard 向导窗
一般用在安装应用时, 或者第一次启动应用时.
向导窗由多个向导页(QWizardPage)组成, 通过以下addPage()
方法添加向导页到向导窗(QWizard)
class MyWizard(QWizard):def __init__(self):super().__init__()self.initUI()def initUI(self):self.addPage(WizardPage())self.setWizardStyle(QWizard.ClassicStyle)self.setWindowTitle("Trivial Wizard")# self.show()
QWizardPage向导页:
class WizardPage(QWizardPage):def __init__(self):super().__init__()self.initUI()def initUI(self):'''向导页'''self.setTitle("Introduction")label = QLabel("This wizard will help you register your copy of Super Product Two.")label.setWordWrap(True)layout = QVBoxLayout()layout.addWidget(label)self.setLayout(layout)
内容显示位置:
样式:
self.wizard.setWizardStyle(QWizard.ClassicStyle)
虽然官方给的样式图是这样的, 但是实际显示效果则未必.
按条件调整展示向导页顺序
默认情况下是按id递增显示的, 我们可以重写QWizardPage.nextId()
提供动态的顺序.
设置id (使用.setPage()
来代替.addPage()
):
self.setPage(1, IntroPage())self.setPage(2, EvaluatePage())self.setStartId(1) # 开始页
重写QWizardPage.nextId()
:
def nextId(self):'''返回下一页的id'''if self.upgradeKeyLineEdit.text().isEmpty():return 1 # 没有下一页返回 -1else:return 2
按钮
按钮布局:
设置按钮水平的位置, 会与其他位置配置(如: .setOption())发生冲突, 而使其他位置配置失效.
layout = [QWizard.Stretch, QWizard.BackButton, QWizard.CancelButton, QWizard.NextButton, QWizard.FinishButton]self.setButtonLayout(layout)
使用与不是QWizard.Stretch
的区别:
选择权:
self.setOption(QWizard.NoBackButtonOnStartPage, True)
自定义按钮:
def initUI(self):...self.setButtonText(QWizard.CustomButton1, "猜猜我是谁")self.setOption(QWizard.HaveCustomButton1, True)self.customButtonClicked.connect(self.printButtonClicked)def printButtonClicked(self, which):text = self.button(which).text()print(text)
中文按钮及汉化:
self.setButtonText(QWizard.FinishButton, '大功告成')
直接使用系统翻译即可
图片
设置图片:
使用时需结合样式才有效果
self.setPixmap(QWizard.WatermarkPixmap, QPixmap('background.png'))
设置控件:
将控件设置在向导的左侧, 有使用WatermarkPixmap (ClassicStyle / ModernStyle)时设置在水印上方, 其他样式或没有使用水印时, 设置在向导左侧.
btn = QPushButton()btn.setText("按钮")layout = QVBoxLayout()layout.addWidget(btn)widget = QWidget()widget.setLayout(layout)self.setSideWidget(widget)