当前位置: 代码迷 >> 综合 >> Python3 PyQt5 窗口(国际化/QMainWindow/QWidget/QDialog)
  详细解决方案

Python3 PyQt5 窗口(国际化/QMainWindow/QWidget/QDialog)

热度:56   发布时间:2023-12-20 21:34:36.0

Python3 PyQt5 窗口(国际化/QMainWindow/QWidget/QDialog)


本文由 Luzhuo 编写,转发请保留该信息.
原文: https://blog.csdn.net/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__ = '2019/2/19'
# QMainWindow 创建主窗口import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from 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 sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from 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 sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp, QMenu
from 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 设置 widget
dock.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

Constant Description
QDockWidget.DockWidgetClosable 可关闭
QDockWidget.DockWidgetMovable 可移动
QDockWidget.DockWidgetFloatable 可漂浮
QDockWidget.DockWidgetVerticalTitleBar 垂直标题栏
QDockWidget.AllDockWidgetFeatures 所有特性
QDockWidget.NoDockWidgetFeatures 没有特性

QtCore.Qt.DockWidgetArea

Constant Description
Qt.LeftDockWidgetArea 主窗口左侧
Qt.RightDockWidgetArea 主窗口右侧
Qt.TopDockWidgetArea 主窗口顶部
Qt.BottomDockWidgetArea 主窗口底部
Qt.AllDockWidgetAreas 任意位置
Qt.NoDockWidgetArea 不知道

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 2019")# 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()  # 得到父窗口

窗口样式:

默认窗口样式 是使用 当前操作系统的原生窗口样式, 在不同的操作系统下原生窗口样式显示的效果不一样.

我们可以定制窗口样式.

窗口类型 (|组合):

Qt.WindowType 枚举 Description
Qt.Widget 默认(最小化 + 最大化 + 关闭)
Qt.Window 普通窗口(最小化 + 最大化 + 关闭)
Qt.Dialog 对话框(?号 + 关闭)
Qt.Sheet macOS 表单
Qt.Drawer macOS 抽屉。
Qt.Popup 泡泡(无边框)
Qt.Tool 工具窗口
Qt.ToolTip 提示泡泡 (无边框 + 无任务栏)
Qt.SplashScreen 启动屏(无边框 + 无任务栏)
Qt.Desktop 桌面
Qt.SubWindow 子窗口(无按钮 + 有标题)
Qt.ForeignWindow 窗口句柄
Qt.CoverWindow 封面窗口 (最小化时显示)

窗口外观标志:

Qt.WindowFlags 枚举 Description
Qt.MSWindowsFixedSizeDialogHint 窗口无法调整大小
Qt.MSWindowsOwnDC 添加上下文菜单
Qt.BypassWindowManagerHint 禁用所有窗口管理器
Qt.X11BypassWindowManagerHint 忽视窗口管理器
Qt.FramelessWindowHint 没有边框的窗口
Qt.NoDropShadowWindowHint 禁用窗口阴影

自定义窗口:

Qt.WindowFlags 枚举 Description
Qt.CustomizeWindowHint 自定义窗口标题栏 (以下标志与此标志一起用, 否则有默认标题栏)
Qt.WindowTitleHint 显示窗口标题栏
Qt.WindowSystemMenuHint 显示系统菜单
Qt.WindowMinimizeButtonHint 显示最小化按钮
Qt.WindowMaximizeButtonHint 显示最大化按钮
Qt.WindowMinMaxbuttonHint 显示最小化按钮和最大化按钮
Qt.WindowCloseButtonHint 显示关闭按钮
Qt.WindowContextHelpButtonHint 显示?按钮
Qt.MacWindowToolBarButtonHint 在macOS添加工具栏按钮
Qt.WindowFullscreenButtonHint 在macOS添加全屏按钮
Qt.BypassGraphicsProxyWidget 阻止窗口自动嵌入场景
Qt.WindowShadeButtonHint 用阴影按钮来代替最小化按钮
Qt.WindowStaysOnTopHint 总是最顶层的窗口
Qt.WindowStaysOnBottomHint 总是最底层的窗口

其他高大上的标志:

Qt.WindowFlags 枚举 Description
Qt.WindowTransparentForInput 窗口仅输入, 不接受输入
Qt.WindowOverridesSystemGestures 窗口有自己的手势, 并禁用系统级手势
Qt.WindowDoesNotAcceptFocus 不接受输入焦点
Qt.MaximizeUsingFullscreenGeometryHint 最大化窗口时, 尽可能多的占用屏幕 (取决于平台是否支持, 且可能放置在系统UI下)
Qt.WindowType_Mask 提取窗口类型掩码
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的风格

窗口最大化:

Slots & Func Description
showMinimized 最小化方式显示窗口
showMaximized 最大化方式显示窗口
showFullScreen 全屏方式显示窗口
showNormal 正常方式显示窗口

上面4个既是函数, 又是槽

self.showMaximized()  # 是函数, 也是槽

窗口的最大化, 还有这种方式可以调用

self.setWindowState(Qt.WindowMaximized)
Constant Description
Qt.WindowNoState 正常状态
Qt.WindowMinimized 最小化状态
Qt.WindowMaxmized 最大化状态
Qt.WindowFullScreen 全屏状态
Qt.WindowActive 激活状态

方法:

windowStates = self.windowState()  # 获取状态
ismin = self.isMinimized()  # 判断窗口是否为最小化
ismax = self.isMaximized()  # 判断窗口是否为最大化
isfull = self.isFullScreen()  # 判断窗口是否为全屏

禁用窗口:

禁用该窗口, 会使该窗口里所有控件处于不能被使用状态.
没错, 这是一个槽

Func & Slots Description
setEnabled 启用窗口(禁用)
setDisabled 禁用窗口(启用)

上面2个方法既是函数, 也是槽, 但是效果缺是相反的, 尴尬…

self.setDisabled(True)  # 启用该窗口 (与槽效果相反)

方法:

isenable = self.isEnabled()  # 该窗口是否启用
isaction = self.isActiveWindow()  # 判断该窗口是否激活
self.activateWindow()  # 设置窗口为激活状态

窗口的可见

Func & Slots Description
setVisible 显示(隐藏)
setHidden 隐藏(显示)
self.setVisible(True)  # 设置可见 (与槽效果相反)
Slots Description
show 显示
hide 隐藏
close 关闭(返回 bool)
lower 降低窗口到最下面
raise 提升窗口到最上面

方法:

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()  # 新大小

焦点:

Func & Slots Description
setFocus 获得焦点
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
Qt.MouseButton 的枚举 Description
Qt.NoButton 无键
Qt.LeftButton 左键
Qt.RightButton 右键
Qt.MidButton 中键
Qt.Orientation 的枚举 Description
Qt.Horizontal 横向
Qt.Vertical 纵向

上述的鼠标移动事件只有按下时才追踪, 如果想不按下就追踪, 则要加上下面这段代码

# 开启鼠标追踪(不需要按下)
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 等等.

Qt.WindowModality Description
Qt.NonModal 非模态, 可与其他窗口交互
Qt.WindowModal 窗口模态, 未处理完当前对话框, 将阻止与对话框父窗口交互
Qt.ApplicationModal 应用程序模态, 阻止和任何其他窗口交互

案例

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QDialog
from 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)  # 按钮s
msgBox.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)

分别设置:

# 默认1
msgBox = 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)  # 按钮s
msgBox.setDefaultButton(QMessageBox.Save)  # 默认(选中)按钮
ret = msgBox.exec_()if ret == QMessageBox.Save:pass
elif ret == QMessageBox.Discard:pass
elif ret == QMessageBox.Cancel:pass
else: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_()

效果:
在这里插入图片描述

综合体:

对话框类型与图标

QMessageBox.Icon icon
QMessageBox.NoIcon -
QMessageBox.Question 在这里插入图片描述
QMessageBox.Information 在这里插入图片描述
QMessageBox.Warning 在这里插入图片描述
QMessageBox.Critical 在这里插入图片描述

支持的带类型的对话框, 除了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), 还有个 about
ret = QMessageBox.about(self, 'About', "The document has been modified.")

效果:
在这里插入图片描述

按钮:

QMessageBox.StandardButton button name Role
QMessageBox.Ok “OK” AcceptRole
QMessageBox.Open “Open” AcceptRole
QMessageBox.Save “Save” AcceptRole
QMessageBox.Cancel “Cancel” RejectRole
QMessageBox.Close “Close” RejectRole
QMessageBox.Discard “Discard” or “Don’t Save” DestructiveRole
QMessageBox.Apply “Apply” ApplyRole
QMessageBox.Reset “Reset” ResetRole
QMessageBox.RestoreDefaults “Restore Defaults” ResetRole
QMessageBox.Help “Help” HelpRole
QMessageBox.SaveAll “Save All” AcceptRole
QMessageBox.Yes “Yes” YesRole
QMessageBox.YesToAll “Yes to All” YesRole
QMessageBox.No “No” NoRole
QMessageBox.NoToAll “No to All” NoRole
QMessageBox.Abort “Abort” RejectRole
QMessageBox.Retry “Retry” AcceptRole
QMessageBox.Ignore “Ignore” AcceptRole
QMessageBox.NoButton - -

中文按钮名:

默认的按钮名都是英文的, 若要中文显示则需要处理.

# 如果要中文按钮名, 则要自己添加按钮
msgBox = QMessageBox(self)
disconnectbtn = msgBox.addButton("中文按钮", QMessageBox.ActionRole)
abortbtn = msgBox.addButton(QMessageBox.Abort)
msgBox.exec_()
if msgBox.clickedButton() == disconnectbtn:pass
elif msgBox.clickedButton() == abortbtn:pass

效果:
在这里插入图片描述

Role Description
QMessageBox.InvalidRole 无效
QMessageBox.AcceptRole 接受
QMessageBox.RejectRole 拒绝
QMessageBox.DestructiveRole 破坏性更改(如:放弃更改)
QMessageBox.ActionRole 更改对话框里的元素
QMessageBox.HelpRole help
QMessageBox.YesRole Yes
QMessageBox.NoRole No
QMessageBox.ApplyRole 应用改变
QMessageBox.ResetRole 重设

案例:

举个栗子, 我们在关闭窗口时弹出消息盒子.

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收集输入数据返回.

Constant Description
QInputDialog.getText 一行文本
QInputDialog.getMultiLineText 多行文本
QInputDialog.getDouble 浮点数
QInputDialog.getInt 整数
QInputDialog.getItem 条目选择
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 文件对话框

用于文件的打开和保存, 可以打开指定扩展名的文件, 也可以设置起始目录.

Constant Description
getOpenFileName() 打开选择文件对话框
getOpenFileNames() 打开选择多个文件对话框
getExistingDirectory() 打开选择文件夹对话框
getSaveFileName() 打开保存文件对话框
# (标题 / 默认路径['/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上没效果

ViewMode Description
QFileDialog.Detail 详情(列表+其他信息)
QFileDialog.List 列表(文件名+列表)
dialog.setViewMode(QFileDialog.Detail)  # 设置视图模式 (win10没效果)

必选文件模式:

QFileDialog.FileMode Description
QFileDialog.AnyFile 不管是否存在 (适合保存)
QFileDialog.ExistingFile 单个文件名(适合打开)
QFileDialog.Directory 单个目录 (适合选择目录)
QFileDialog.ExistingFiles 1个或多个存在文件 (适合多个打开)
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)

内容显示位置:

在这里插入图片描述
在这里插入图片描述

样式:

WizardStyle Description
ClassicStyle 在这里插入图片描述 在这里插入图片描述
ModernStyle 在这里插入图片描述 在这里插入图片描述
MacStyle 在这里插入图片描述 在这里插入图片描述
AeroStyle 在这里插入图片描述 在这里插入图片描述
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
按钮
QWizard.WizardButton Description
QWizard.BackButton 上一步
QWizard.NextButton 下一步
QWizard.CommitButton 提交
QWizard.FinishButton 完成
QWizard.CancelButton 取消
QWizard.HelpButton 帮助
QWizard.CustomButton1 第1个自定义按钮
QWizard.CustomButton2 第2个自定义按钮
QWizard.CustomButton3 第3个自定义按钮
QWizard.Stretch 在ButtonLayout中使用, 水平拉伸

按钮布局:

设置按钮水平的位置, 会与其他位置配置(如: .setOption())发生冲突, 而使其他位置配置失效.

layout = [QWizard.Stretch, QWizard.BackButton, QWizard.CancelButton, QWizard.NextButton, QWizard.FinishButton]
self.setButtonLayout(layout)

使用与不是QWizard.Stretch的区别:

在这里插入图片描述

选择权:

QWizard.WizardOption Description
QWizard.IndependentPages 独立页面
QWizard.IgnoreSubTitles 不显示任何子标题
QWizard.ExtendedWatermarkPixmap 将任何WatermarkPixmap延伸到屏幕边缘
QWizard.NoDefaultButton 不将Next和Finish设为默认按钮
QWizard.NoBackButtonOnStartPage 不要在开始页显示Back按钮
QWizard.NoBackButtonOnLastPage 不要在结束页显示Back按钮
QWizard.DisabledBackButtonOnLastPage 禁用最后页Back按钮
QWizard.HaveNextButtonOnLastPage 显示最后页Next(禁用)按钮
QWizard.HaveFinishButtonOnEarlyPages 显示非最后页Finish(禁用)按钮
QWizard.NoCancelButton 不显示Cancel按钮
QWizard.CancelButtonOnLeft 将Cancel放在Back左侧
QWizard.HaveHelpButton 显示Help按钮
QWizard.HelpButtonOnRight 将Help放在按钮布局最右侧
QWizard.HaveCustomButton1 显示第1个自定义按钮
QWizard.HaveCustomButton2 显示第2个自定义按钮
QWizard.HaveCustomButton3 显示第3个自定义按钮
QWizard.NoCancelButtonOnLastPage 不显示在最后页的Cancel按钮
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, '大功告成')

直接使用系统翻译即可

图片

设置图片:

QWizard.WizardPixmap Description
QWizard.WatermarkPixmap 显示在 ClassicStyle/ModernStyle 的左侧
QWizard.LogoPixmap 显示在 ClassicStyle or ModernStyle 的页头右侧
QWizard.BannerPixmap 显示在 ModernStyle 页头标题栏背景
QWizard.BackgroundPixmap 显示在 MacStyle 的背景

使用时需结合样式才有效果

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)
  相关解决方案