diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..6dddafe --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# 贡献指南 + +非常感谢你愿意为 PySide6-Code-Tutorial 项目提供贡献,请阅读以下内容,遵守一些基本规则,以便项目保持良好状态快速发展。 + +## 开始编码之前 + +如果你准备对代码进行超过数十行的修改或新增,我强烈建议你先提交一个 issue,谈谈你想实现的东西。在投入很多精力之前,我们应该先讨论一下是否要这样做,也可以确保我们不重复工作。 + +## 编写代码 + +### 准备开发环境 + +开发环境相较于使用环境较为复杂,确保已经安装 Python 3.11+ 和 [Poetry](https://python-poetry.org/docs/#installation),然后通过 Poetry 创建和安装开发环境: + +```shell +cd PySide6-Code-Tutorial +poetry init +poetry install +``` + +还需要通过 [pre-commit](https://pre-commit.com/) 安装 git 钩子: + +```shell +pre-commit install +``` + +### 代码风格 + +- 总体来讲,新增和修改的代码应接近原有代码的风格。尽量使代码有良好的可读性。 +- 请使用 [Black](https://black.readthedocs.io/en/stable/) 格式化代码,确保所有代码风格与项目一致。开发环境中已经安装了 Black,配置使用方法可以参考[这篇文章](https://muzing.top/posts/a29e4743/)。 +- 请为代码添加充分的[类型注解](https://muzing.top/posts/84a8da1c/),并能通过 [mypy](https://mypy.readthedocs.io/en/stable/) 检查不报错。 +- 请为模块、类、函数/方法、属性等添加 docstring 或注释,确保含义清晰易读。 + +## 拉取请求 + +新建一个指向 [muziing/PySide6-Code-Tutorial](https://github.com/muziing/PySide6-Code-Tutorial) 的 `main` 分支的拉取请求,我将尽快 review 代码并给出反馈。 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..41549df --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,22 @@ +fail_fast: false + +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-toml + - id: check-yaml + - id: trailing-whitespace + - id: end-of-file-fixer + +- repo: https://github.com/psf/black + rev: 24.2.0 + hooks: + - id: black + args: [--config, "./pyproject.toml"] + +- repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + args: [--settings-path, "./pyproject.toml"] diff --git "a/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/01-HelloWorld-\347\254\254\344\270\200\344\270\252PySide6\347\250\213\345\272\217.py" "b/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/01-HelloWorld-\347\254\254\344\270\200\344\270\252PySide6\347\250\213\345\272\217.py" index ce51959..c5ac625 100644 --- "a/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/01-HelloWorld-\347\254\254\344\270\200\344\270\252PySide6\347\250\213\345\272\217.py" +++ "b/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/01-HelloWorld-\347\254\254\344\270\200\344\270\252PySide6\347\250\213\345\272\217.py" @@ -37,7 +37,9 @@ def magic(self) -> None: if __name__ == "__main__": - app = QtWidgets.QApplication(sys.argv) # 创建APP,将运行脚本时(可能的)的其他参数传给Qt以初始化 + app = QtWidgets.QApplication( + sys.argv + ) # 创建APP,将运行脚本时(可能的)的其他参数传给Qt以初始化 widget = MyWidget() # 实例化一个MyWidget类对象 widget.show() # 显示窗口 sys.exit(app.exec()) # 正常退出APP:app.exec()关闭app,sys.exit()退出进程 diff --git "a/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/03-\347\261\273\347\232\204\347\273\247\346\211\277\345\205\263\347\263\273.py" "b/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/03-\347\261\273\347\232\204\347\273\247\346\211\277\345\205\263\347\263\273.py" index 9002f28..46669f2 100644 --- "a/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/03-\347\261\273\347\232\204\347\273\247\346\211\277\345\205\263\347\263\273.py" +++ "b/01-HelloWorld-\345\237\272\346\234\254\347\273\223\346\236\204/03-\347\261\273\347\232\204\347\273\247\346\211\277\345\205\263\347\263\273.py" @@ -5,7 +5,7 @@ def get_sub_classes(class_): """递归地显示某一类的所有子类""" for subclass in class_.__subclasses__(): print(subclass) - if len(class_.__subclasses__()) > 0: + if len(subclass.__subclasses__()) > 0: get_sub_classes(subclass) diff --git "a/02-QtCore-\351\235\236GUI\347\232\204\346\240\270\345\277\203\345\212\237\350\203\275/01-The_Meta-Object_System-\345\205\203\345\257\271\350\261\241\347\263\273\347\273\237.md" "b/02-QtCore-\351\235\236GUI\347\232\204\346\240\270\345\277\203\345\212\237\350\203\275/01-The_Meta-Object_System-\345\205\203\345\257\271\350\261\241\347\263\273\347\273\237.md" index ef2a6f0..f3d24e8 100644 --- "a/02-QtCore-\351\235\236GUI\347\232\204\346\240\270\345\277\203\345\212\237\350\203\275/01-The_Meta-Object_System-\345\205\203\345\257\271\350\261\241\347\263\273\347\273\237.md" +++ "b/02-QtCore-\351\235\236GUI\347\232\204\346\240\270\345\277\203\345\212\237\350\203\275/01-The_Meta-Object_System-\345\205\203\345\257\271\350\261\241\347\263\273\347\273\237.md" @@ -74,6 +74,6 @@ if (QLabel label = QLabel (obj)) { label.setText(tr("Ping")) ------ -© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the [GNU Free Documentation License version 1.3](https://www.gnu.org/licenses/fdl-1.3.html) as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners. +© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the [GNU Free Documentation License version 1.3](https://www.gnu.org/licenses/fdl-1.3.html) as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners. © 2022 zh_CN Translation by muzing\. diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/09-QWidget-\351\224\256\347\233\230\350\276\223\345\205\245\347\204\246\347\202\271-2.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/09-QWidget-\351\224\256\347\233\230\350\276\223\345\205\245\347\204\246\347\202\271-2.py" index 7d0e4f3..991b21b 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/09-QWidget-\351\224\256\347\233\230\350\276\223\345\205\245\347\204\246\347\202\271-2.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/09-QWidget-\351\224\256\347\233\230\350\276\223\345\205\245\347\204\246\347\202\271-2.py" @@ -1,8 +1,3 @@ -import sys - -from PySide6 import QtWidgets -from PySide6.QtCore import Qt - """ QWidget 键盘输入焦点控制 @@ -14,7 +9,7 @@ https://doc.qt.io/qt-6/qwidget.html#setFocusProxy .setFocusPolicy(policy: Qt.FocusPolicy) 设置焦点策略,详见下方Qt.FocusPolicy -.focusPolicy() -> Qt.FocusPolicy 返回该控件的焦点策略 +.focusPolicy() -> Qt.FocusPolicy 返回该控件的焦点策略 Qt.FocusPolicy 具体分为如下数种: https://doc.qt.io/qt-6/qt.html#FocusPolicy-enum @@ -32,6 +27,11 @@ """ +import sys + +from PySide6 import QtWidgets +from PySide6.QtCore import Qt + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/10-QWidget-\345\205\211\346\240\207.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/10-QWidget-\345\205\211\346\240\207.py" index 9c286a6..8e84f4d 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/10-QWidget-\345\205\211\346\240\207.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/01-QWidget-\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/10-QWidget-\345\205\211\346\240\207.py" @@ -57,7 +57,9 @@ def test_01(self) -> None: # 设置为自定义图案光标 pixmap = QtGui.QPixmap("../../Resources/Icons/snowflake_128px.ico").scaled(52, 52) - my_cursor = QtGui.QCursor(pixmap, 26, 26) # 以图片像素点位置26,26为热点(光标实际所在位置坐标) + my_cursor = QtGui.QCursor( + pixmap, 26, 26 + ) # 以图片像素点位置26,26为热点(光标实际所在位置坐标) self.setCursor(my_cursor) # 设置label中的光标为Qt内置的其他光标 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/02-QPushButton-\346\211\201\345\271\263\345\214\226.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/02-QPushButton-\346\211\201\345\271\263\345\214\226.py" index 48d1d59..1797faa 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/02-QPushButton-\346\211\201\345\271\263\345\214\226.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/02-QPushButton-\346\211\201\345\271\263\345\214\226.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtGui, QtWidgets - """ QPushButton 扁平化 设置扁平化后,除非按钮被按下,大部分样式不会绘制按钮背景,实现视觉上的扁平化 @@ -10,6 +6,10 @@ .isFlat() -> bool 是否为扁平化 """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/04-QPushButton-\351\273\230\350\256\244\344\270\216\350\207\252\345\212\250\351\273\230\350\256\244.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/04-QPushButton-\351\273\230\350\256\244\344\270\216\350\207\252\345\212\250\351\273\230\350\256\244.py" new file mode 100644 index 0000000..c3a6765 --- /dev/null +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/02-QPushButton-\346\231\256\351\200\232\346\214\211\351\222\256/04-QPushButton-\351\273\230\350\256\244\344\270\216\350\207\252\345\212\250\351\273\230\350\256\244.py" @@ -0,0 +1,88 @@ +""" +QPushButton 默认按钮与自动默认 + +建议参考:https://doc.qt.io/qt-6/qpushbutton.html#default-prop +因为涉及对话框相关内容,首次学习时可略过此节,待学习对话框章节之后再回顾本节 + +===================================default属性============================= +默认和自动默认按钮决定当用户在对话框中按下 Enter 时会发生什么。 + +default 属性设置为 true 的按钮(即对话框的默认按钮)将在用户按下 Enter 时自动被按下, +但有一个例外:如果 autoDefault 按钮当前具有焦点,则按下 autoDefault 按钮。 +当对话框有 autoDefault 按钮但没有默认按钮时,按 Enter 将按下当前具有焦点的 autoDefault 按钮,或者如果没有按钮具有焦点, +则按下焦点链中的下一个 autoDefault 按钮。 + +在对话框中,一次只能有一个按钮作为默认按钮。此按钮会显示一个额外边框(取决于 GUI 样式)。 + +默认按钮行为仅在对话框中提供。当按钮具有焦点时,始终可以通过按空格键从键盘单击按钮。 + +当对话框可见时,将当前默认按钮的默认属性设置为 False,则在对话框中的按钮下次获得焦点时,将自动分配一个新的默认 + +该属性的默认值为 False + +===================================auto-default属性============================= +此属性用于保持按钮是否为自动默认按钮 + +如果这个属性被设置为 True,那么这个按钮就是一个自动默认按钮。 + +在一些 GUI 风格中,默认按钮的周围会有一个额外的框架,最多可达3个像素或更多。Qt会自动在自动默认按钮周围保留这个空间,也就是说,自动默认按钮可能有一个稍大的尺寸提示。 + +对于有 QDialog 父级的按钮,这个属性的默认值是真,否则默认为假。 + +关于 default 和 auto-default 如何交互的细节,请参见 default 属性。 + +===================================代码============================= +.isDefault() -> bool 设置为默认/非默认 +.setDefault(bool) 获取默认状态 +.setAutoDefault(bool) 设置为自动默认/非自动默认 +.autoDefault() -> bool 获取自动默认状态 +""" + +import sys + +from PySide6 import QtWidgets + + +class MyWidget(QtWidgets.QWidget): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setWindowTitle("QPushButton-默认按钮") + self.resize(800, 600) + self.setup_ui() + + def setup_ui(self) -> None: + """设置界面""" + # 创建信息提示框(一种可以包含按钮的对话框)并配置 + message_box = QtWidgets.QMessageBox(self) + message_box.setIcon(QtWidgets.QMessageBox.Icon.Warning) + message_box.setWindowTitle("这是一个消息提示框") + message_box.setText("测试默认按钮功能") + self.cancel_btn = message_box.addButton( + QtWidgets.QMessageBox.StandardButton.Cancel + ) # 添加标准按钮,返回值为按钮实例 + self.ok_btn = message_box.addButton( + QtWidgets.QMessageBox.StandardButton.Ok + ) # 添加标准按钮,返回值为按钮实例 + # 如果有按钮被按下,则将该按钮的文本打印到终端。 + message_box.buttonClicked.connect(lambda btn: print(btn.text())) # type: ignore + + # 在主界面上添加一个弹出对话框的按钮,本节功能演示在对话框窗口中而非主窗口中呈现 + pop_btn = QtWidgets.QPushButton("弹出对话框", self) + pop_btn.move(200, 200) + pop_btn.clicked.connect(message_box.open) # type: ignore + + self.test() + + def test(self): + """测试按钮默认与自动默认功能""" + self.ok_btn.setDefault(True) + self.ok_btn.setAutoDefault(True) + print(f"ok_btn.isDefault({self.ok_btn.isDefault()})") + print(f"cancel_btn.isDefault({self.cancel_btn.isDefault()})") + + +if __name__ == "__main__": + app = QtWidgets.QApplication(sys.argv) + window = MyWidget() + window.show() + sys.exit(app.exec()) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/04-QCheckBox-\345\244\215\351\200\211\346\241\206/03-QCheckBox-\344\277\241\345\217\267.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/04-QCheckBox-\345\244\215\351\200\211\346\241\206/03-QCheckBox-\344\277\241\345\217\267.py" index 45fde21..eefe0d3 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/04-QCheckBox-\345\244\215\351\200\211\346\241\206/03-QCheckBox-\344\277\241\345\217\267.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/02-Button-\346\214\211\351\222\256\346\216\247\344\273\266/04-QCheckBox-\345\244\215\351\200\211\346\241\206/03-QCheckBox-\344\277\241\345\217\267.py" @@ -1,6 +1,6 @@ import sys -from PySide6 import QtCore, QtGui, QtWidgets +from PySide6 import QtCore, QtWidgets from PySide6.QtCore import Qt """ @@ -30,11 +30,11 @@ def test_01(self) -> None: @QtCore.Slot(int) def test_slot(state: int) -> None: - if state == Qt.Checked: + if state == Qt.Checked.value: print("复选框被选中了!") - elif state == Qt.Unchecked: + elif state == Qt.Unchecked.value: print("复选框被取消选中了!") - elif state == Qt.PartiallyChecked: + elif state == Qt.PartiallyChecked.value: print("复选框被部分选中!") self.cb.stateChanged.connect(test_slot) # type: ignore diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QLineEdit-\346\230\276\347\244\272\346\250\241\345\274\217.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QLineEdit-\346\230\276\347\244\272\346\250\241\345\274\217.py" index 828d6d2..3f964e7 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QLineEdit-\346\230\276\347\244\272\346\250\241\345\274\217.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QLineEdit-\346\230\276\347\244\272\346\250\241\345\274\217.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtWidgets - """ QLineEdit 显示模式 默认显示模式为正常,即用户输入什么就显示什么 @@ -20,9 +16,12 @@ .text() -> str 返回LineEdit内的文本,与显示模式无关 .displayText() -> str 返回LineEdit中显示的文本。例如Password模式下可能会获得"*******" - """ +import sys + +from PySide6 import QtCore, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -63,10 +62,10 @@ def setup_ui(self) -> None: def test_echo_mode(self) -> None: """测试显示模式功能""" - self.line_edit_1.setEchoMode(QtWidgets.QLineEdit.Normal) - self.line_edit_2.setEchoMode(QtWidgets.QLineEdit.Password) - self.line_edit_3.setEchoMode(QtWidgets.QLineEdit.PasswordEchoOnEdit) - self.line_edit_4.setEchoMode(QtWidgets.QLineEdit.NoEcho) + self.line_edit_1.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal) + self.line_edit_2.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password) + self.line_edit_3.setEchoMode(QtWidgets.QLineEdit.EchoMode.PasswordEchoOnEdit) + self.line_edit_4.setEchoMode(QtWidgets.QLineEdit.EchoMode.NoEcho) @QtCore.Slot() def test_slot(): diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/05-QLineEdit-\347\274\226\350\276\221\346\223\215\344\275\234.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/05-QLineEdit-\347\274\226\350\276\221\346\223\215\344\275\234.py" index 12ef114..38ff0a1 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/05-QLineEdit-\347\274\226\350\276\221\346\223\215\344\275\234.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/05-QLineEdit-\347\274\226\350\276\221\346\223\215\344\275\234.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtWidgets - """ QLineEdit 编辑操作 @@ -42,9 +38,12 @@ 当用户对单行编辑器的内容有修改后,Modified属性会从默认的False变成True .setModified(yes: bool) 手动设置Modified状态 .isModified() -> bool 获取用户是否对编辑器有修改 - """ +import sys + +from PySide6 import QtCore, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -66,7 +65,7 @@ def setup_ui(self) -> None: self.clear_button = QtWidgets.QPushButton("清空") self.select_all_button = QtWidgets.QPushButton("全选") self.copy_button = QtWidgets.QPushButton("复制") - self.cut_buton = QtWidgets.QPushButton("剪切") + self.cut_button = QtWidgets.QPushButton("剪切") self.paste_button = QtWidgets.QPushButton("粘贴") self.undo_button = QtWidgets.QPushButton("撤销") self.redo_button = QtWidgets.QPushButton("重做") @@ -78,7 +77,7 @@ def setup_ui(self) -> None: layout = QtWidgets.QHBoxLayout() layout.addWidget(self.clear_button) layout.addWidget(self.select_all_button) - layout.addWidget(self.cut_buton) + layout.addWidget(self.cut_button) layout.addWidget(self.copy_button) layout.addWidget(self.paste_button) layout.addWidget(self.undo_button) @@ -98,7 +97,7 @@ def test_01(self) -> None: self.clear_button.clicked.connect(self.line_edit_1.clear) # type: ignore self.select_all_button.clicked.connect(self.line_edit_1.selectAll) # type: ignore - self.cut_buton.clicked.connect(self.line_edit_1.cut) # type: ignore + self.cut_button.clicked.connect(self.line_edit_1.cut) # type: ignore self.copy_button.clicked.connect(self.line_edit_1.copy) # type: ignore self.paste_button.clicked.connect(self.line_edit_1.paste) # type: ignore self.undo_button.clicked.connect(self.line_edit_1.undo) # type: ignore diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QLineEdit-\345\205\211\346\240\207.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QLineEdit-\345\205\211\346\240\207.py" index 375a794..8347a1a 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QLineEdit-\345\205\211\346\240\207.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QLineEdit-\345\205\211\346\240\207.py" @@ -74,7 +74,9 @@ def setup_ui(self) -> None: pos_layout = QtWidgets.QFormLayout() pos_layout.addRow(QtWidgets.QLabel("光标当前位于:"), self.pos_line_edit) pos_layout.addRow(QtWidgets.QLabel("将光标设置到:"), self.set_pos_spinbox) - pos_layout.addRow(QtWidgets.QLabel(f"{self.point.toTuple()}处的光标位于"), self.pos_at_label) + pos_layout.addRow( + QtWidgets.QLabel(f"{self.point.toTuple()}处的光标位于"), self.pos_at_label + ) pos_groupbox.setLayout(pos_layout) # ================ 光标移动风格 ======================= diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/10-QLineEdit-\350\207\252\345\256\232\344\271\211\350\241\214\344\270\272-\346\230\216\345\257\206\346\226\207\345\210\207\346\215\242\346\241\210\344\276\213.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/10-QLineEdit-\350\207\252\345\256\232\344\271\211\350\241\214\344\270\272-\346\230\216\345\257\206\346\226\207\345\210\207\346\215\242\346\241\210\344\276\213.py" index e743ea0..9f80dd7 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/10-QLineEdit-\350\207\252\345\256\232\344\271\211\350\241\214\344\270\272-\346\230\216\345\257\206\346\226\207\345\210\207\346\215\242\346\241\210\344\276\213.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/03-QLineEdit-\345\215\225\350\241\214\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/10-QLineEdit-\350\207\252\345\256\232\344\271\211\350\241\214\344\270\272-\346\230\216\345\257\206\346\226\207\345\210\207\346\215\242\346\241\210\344\276\213.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtGui, QtWidgets - """ QLineEdit Action 案例 单行文本编辑器可以在行首或行尾添加自定义的行为 @@ -13,9 +9,12 @@ QLineEdit.ActionPosition枚举值具体有以下两种取值: QLineEdit.LeadingPosition 若布局从左至右则将行为添加至最左侧,反之则添加至最右侧 QLineEdit.TrailingPosition 若布局从左至右则将行为添加至最右侧,反之则添加至最左侧 - """ +import sys + +from PySide6 import QtCore, QtGui, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -30,7 +29,7 @@ def setup(self) -> None: line_edit = QtWidgets.QLineEdit(self) line_edit.resize(300, 30) line_edit.move(100, 50) - line_edit.setEchoMode(QtWidgets.QLineEdit.Password) + line_edit.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password) eye_icon = QtGui.QIcon("../../Resources/Icons/FlatIcon-regular-rounded/eye.png") eye_crossed_icon = QtGui.QIcon( @@ -44,17 +43,17 @@ def setup(self) -> None: @QtCore.Slot() def switch(): """切换明文/密码的槽函数""" - if line_edit.echoMode() == QtWidgets.QLineEdit.Password: - line_edit.setEchoMode(QtWidgets.QLineEdit.Normal) + if line_edit.echoMode() == QtWidgets.QLineEdit.EchoMode.Password: + line_edit.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal) action.setIcon(eye_icon) else: - line_edit.setEchoMode(QtWidgets.QLineEdit.Password) + line_edit.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password) action.setIcon(eye_crossed_icon) action.triggered.connect(switch) # type: ignore # 添加行为 - line_edit.addAction(action, QtWidgets.QLineEdit.TrailingPosition) + line_edit.addAction(action, QtWidgets.QLineEdit.ActionPosition.TrailingPosition) if __name__ == "__main__": diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/01-QFrame-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/01-QFrame-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" index abaf6aa..f25e4b9 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/01-QFrame-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/01-QFrame-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ QFrame 是具有边框的控件的基类 官方文档:https://doc.qt.io/qtforpython/PySide6/QtWidgets/QFrame.html @@ -12,14 +8,17 @@ 构造函数中可以传入父控件与WindowFlags(见本项目05-03-01) .__init__(self, parent: Optional[QWidget] = None, f: Qt.WindowFlags = Default(Qt.WindowFlags)) - """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.setWindowTitle("空白测试模板") + self.setWindowTitle("QFrame") self.resize(800, 600) self.setup_ui() @@ -30,7 +29,7 @@ def setup_ui(self) -> None: frame.move(200, 200) # 设置风格与线宽 - frame.setFrameStyle(QtWidgets.QFrame.StyledPanel | QtWidgets.QFrame.Sunken) + frame.setFrameStyle(QtWidgets.QFrame.Shape.StyledPanel | QtWidgets.QFrame.Shadow.Sunken) frame.setLineWidth(3) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/02-QFrame-\351\243\216\346\240\274.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/02-QFrame-\351\243\216\346\240\274.py" index dfd4817..0437a62 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/02-QFrame-\351\243\216\346\240\274.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/04-QFrame-\345\205\267\350\276\271\346\241\206\346\216\247\344\273\266\347\232\204\345\237\272\347\261\273/02-QFrame-\351\243\216\346\240\274.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ QFrame 风格:形状、阴影、线宽 所有组合的视觉效果:https://doc.qt.io/qt-6/images/frames.png @@ -35,14 +31,17 @@ QFrame.Plain 边框与内容与周围处于同水平,没有任何3D效果 QFrame.Raised 边框与内容浮起,使用当前的颜色组绘制亮处与阴影以实现3D效果 QFrame.Sunken 边框与内容下沉,使用当前的颜色组绘制亮处与阴影以实现3D效果 - """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.setWindowTitle("空白测试模板") + self.setWindowTitle("QFrame-风格") self.resize(800, 600) self.setup_ui() @@ -52,9 +51,9 @@ def setup_ui(self) -> None: frame.resize(200, 200) frame.move(200, 200) - # frame.setFrameStyle(QtWidgets.QFrame.Box | QtWidgets.QFrame.Raised) - frame.setFrameShape(QtWidgets.QFrame.Panel) - frame.setFrameShadow(QtWidgets.QFrame.Sunken) + # frame.setFrameStyle(QtWidgets.QFrame.Shape.Box | QtWidgets.QFrame.Shadow.Raised) + frame.setFrameShape(QtWidgets.QFrame.Shape.Panel) + frame.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) frame.setLineWidth(3) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/06-QAbstractScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237\347\232\204\345\237\272\347\261\273/05-QAbstractScrollArea-\345\260\272\345\257\270\350\260\203\346\225\264\347\255\226\347\225\245.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/06-QAbstractScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237\347\232\204\345\237\272\347\261\273/05-QAbstractScrollArea-\345\260\272\345\257\270\350\260\203\346\225\264\347\255\226\347\225\245.py" index 7b615a7..2f52512 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/06-QAbstractScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237\347\232\204\345\237\272\347\261\273/05-QAbstractScrollArea-\345\260\272\345\257\270\350\260\203\346\225\264\347\255\226\347\225\245.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/06-QAbstractScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237\347\232\204\345\237\272\347\261\273/05-QAbstractScrollArea-\345\260\272\345\257\270\350\260\203\346\225\264\347\255\226\347\225\245.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtGui, QtWidgets - """ QAbstractScrollArea 尺寸调整策略 可以控制当视口尺寸改变时,滚动区域的尺寸如何调整的策略 @@ -14,9 +10,12 @@ QAbstractScrollArea.AdjustIgnored 滚动区域行为与之前相同,不做任何调整(默认值) QAbstractScrollArea.AdjustToContents 滚动区域总是根据视口调整尺寸 QAbstractScrollArea.AdjustToContentsOnFirstShow 滚动区域首次出现时根据视口调整尺寸 - """ +import sys + +from PySide6 import QtGui, QtWidgets + class MyWidget(QtWidgets.QScrollArea): def __init__(self, *args, **kwargs): @@ -34,10 +33,10 @@ def setup_ui(self) -> None: def test_01(self) -> None: """测试尺寸调整策略功能""" - self.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) - # self.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + # self.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored) + self.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) # self.setSizeAdjustPolicy( - # QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow + # QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContentsOnFirstShow # ) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/07-QScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237/02-QScrollArea-\350\247\206\345\233\276\346\216\247\344\273\266.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/07-QScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237/02-QScrollArea-\350\247\206\345\233\276\346\216\247\344\273\266.py" index 1fc69ba..cc14d1c 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/07-QScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237/02-QScrollArea-\350\247\206\345\233\276\346\216\247\344\273\266.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/07-QScrollArea-\346\273\232\345\212\250\345\214\272\345\237\237/02-QScrollArea-\350\247\206\345\233\276\346\216\247\344\273\266.py" @@ -77,7 +77,9 @@ def test_01(self) -> None: self.scroll_area.widget().resize(200, 400) # 尺寸小于滚动区域尺寸 # 设置对齐方式 - self.scroll_area.setAlignment(Qt.AlignHCenter | Qt.AlignBottom) # 设置为水平居中、垂直靠底部对齐 + self.scroll_area.setAlignment( + Qt.AlignHCenter | Qt.AlignBottom + ) # 设置为水平居中、垂直靠底部对齐 def test_02(self) -> None: """测试尺寸控制、确保可见功能""" diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QPlainTextEdit-\346\215\242\350\241\214\346\226\271\345\274\217\343\200\201\345\217\252\350\257\273.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QPlainTextEdit-\346\215\242\350\241\214\346\226\271\345\274\217\343\200\201\345\217\252\350\257\273.py" index 69cd631..8bef759 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QPlainTextEdit-\346\215\242\350\241\214\346\226\271\345\274\217\343\200\201\345\217\252\350\257\273.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/02-QPlainTextEdit-\346\215\242\350\241\214\346\226\271\345\274\217\343\200\201\345\217\252\350\257\273.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtGui, QtWidgets - """ QPlainTextEdit 换行方式、只读 @@ -40,11 +36,15 @@ .setReadOnly(ro: bool) 设置只读状态 .isReadOnly() -> bool 返回是否开启了只读 - """ +import sys + +from PySide6 import QtWidgets +from PySide6.QtGui import QTextOption + long_text = """Gatsby believed in the green light, the orgastic future that year by year recedes before us. \ -It eluded us then, but that's no matter--tomorrow we will run faster, stretch out our arms farther. . . . \ +It eluded us then, but that's no matter--tomorrow we will run faster, stretch out our arms farther... \ And one fine morning----\nSo we beat on, boats against the current, borne back ceaselessly into the past.""" @@ -66,21 +66,27 @@ def setup_ui(self) -> None: def test_01(self) -> None: """测试自动换行功能""" + # 设置换行模式 - self.pte.setLineWrapMode(QtWidgets.QPlainTextEdit.WidgetWidth) # 自动换行(默认值) - # self.pte.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap) # 关闭自动换行 + self.pte.setLineWrapMode( + QtWidgets.QPlainTextEdit.LineWrapMode.WidgetWidth + ) # 自动换行(默认值) + # self.pte.setLineWrapMode(QtWidgets.QPlainTextEdit.LineWrapMode.NoWrap) # 关闭自动换行 print(self.pte.lineWrapMode()) # 获取换行模式 # 设置单词换行方式 - # self.pte.setWordWrapMode(QtGui.QTextOption.NoWrap) # 永不换行 - # self.pte.setWordWrapMode(QtGui.QTextOption.WordWrap) # 在单词间换行 - # self.pte.setWordWrapMode(QtGui.QTextOption.ManualWrap) # 同NoWrap - # self.pte.setWordWrapMode(QtGui.QTextOption.WrapAnywhere) # 在任意位置换行,可能打断单词 - self.pte.setWordWrapMode(QtGui.QTextOption.WrapAtWordBoundaryOrAnywhere) # 尽可能单词间换行,否则任意换行 + # self.pte.setWordWrapMode(QTextOption.WrapMode.NoWrap) # 永不换行 + # self.pte.setWordWrapMode(QTextOption.WrapMode.WordWrap) # 在单词间换行 + # self.pte.setWordWrapMode(QTextOption.WrapMode.ManualWrap) # 同NoWrap + # self.pte.setWordWrapMode(QTextOption.WrapMode.WrapAnywhere) # 在任意位置换行,可能打断单词 + self.pte.setWordWrapMode( + QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere + ) # 尽可能单词间换行,否则任意换行 print(self.pte.wordWrapMode()) # 获取单词换行方式 def test_02(self) -> None: """测试只读模式功能""" + self.pte.setReadOnly(True) # 启用只读模式 # self.pte.setReadOnly(False) # 关闭只读模式 print(self.pte.isReadOnly()) # 获取只读状态 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QPlainTextEdit-\344\277\241\345\217\267.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QPlainTextEdit-\344\277\241\345\217\267.py" index a949db3..fde3350 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QPlainTextEdit-\344\277\241\345\217\267.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/07-QPlainTextEdit-\344\277\241\345\217\267.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtGui, QtWidgets - """ QPlainTextEdit 信号 纯文本编辑器提供了许多可用信号 @@ -15,9 +11,12 @@ .redoAvailable(available: bool) 当重做功能可用状态发生变化时发射此信号,可用状态作为参数传出 .updateRequest(rect: QRect, dy: int) 当文本文档需要更新指定的矩形时发射此信号。详情见下一节的案例 .modificationChanged(changed: bool) 当文档的内容以影响修改状态的方式发生变化时发射此信号,文档是否已被修改作为参数传出 - """ +import sys + +from PySide6 import QtCore, QtGui, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -70,7 +69,6 @@ def undo_redo_enable_test(enable: bool): self.setLayout(main_layout) def signal_test(self) -> None: - # 测试信号时为避免干扰,每次只测试一个,注释掉其他 self.pte.textChanged.connect(lambda: self.info_label.setText("文本改变了!")) # type: ignore # self.pte.selectionChanged.connect(lambda: self.info_label.setText("选中内容改变了!")) # type: ignore diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/08-QPlainText-\346\241\210\344\276\213-\346\230\276\347\244\272\350\241\214\345\217\267.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/08-QPlainText-\346\241\210\344\276\213-\346\230\276\347\244\272\350\241\214\345\217\267.py" index 94f54af..76811b1 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/08-QPlainText-\346\241\210\344\276\213-\346\230\276\347\244\272\350\241\214\345\217\267.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/08-TextEdit-\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250\344\270\216\351\230\205\350\257\273\345\231\250/01-QPlainTextEdit-\347\272\257\346\226\207\346\234\254\347\274\226\350\276\221\345\231\250/08-QPlainText-\346\241\210\344\276\213-\346\230\276\347\244\272\350\241\214\345\217\267.py" @@ -1,14 +1,13 @@ -import sys - -from PySide6 import QtCore, QtWidgets - """ QPlainText 案例:显示行号 每当文本文档需要更新显示矩形时,会发射updateRequest信号,垂直滚动量作为参数传出 利用这个信号,可以编写行号、断点等功能 - """ +import sys + +from PySide6 import QtCore, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -24,7 +23,9 @@ def setup_ui(self) -> None: self.pte = QtWidgets.QPlainTextEdit(self) self.pte.resize(350, 400) self.pte.move(150, 80) - self.pte.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) # 始终显示滚动条 + self.pte.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn + ) # 始终显示滚动条 # 用于限制line_num_label位置尺寸的父控件 line_num_widget = QtWidgets.QWidget(self) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/01-QSlider-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/01-QSlider-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" index adfa050..85c51f7 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/01-QSlider-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/01-QSlider-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ QSlider 滑块控件 水平或垂直的滑块 @@ -11,6 +7,10 @@ 相比于其抽象父类QAbstractSlider,主要是添加了刻度线功能 """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -27,7 +27,7 @@ def setup_ui(self) -> None: slider.resize(40, 200) # 在两侧绘制刻度线 - slider.setTickPosition(QtWidgets.QSlider.TicksBothSides) + slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksBothSides) if __name__ == "__main__": diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\345\210\273\345\272\246.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\345\210\273\345\272\246.py" index 6ef26d6..d30734c 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\345\210\273\345\272\246.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/09-Slider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\346\273\221\345\235\227\346\216\247\344\273\266/02-QSlider-\345\210\273\345\272\246.py" @@ -1,8 +1,3 @@ -import sys - -from PySide6 import QtWidgets -from PySide6.QtCore import Qt - """ QSlider 刻度 @@ -13,17 +8,21 @@ .tickInterval() -> int 获取刻度线间隔 -QSlider.TickPosition枚举值具体有如下数种: +QSlider.TickPosition 枚举值具体有如下数种: https://doc.qt.io/qt-6/qslider.html#TickPosition-enum -QSlider.NoTicks 不绘制任何刻度线,默认值 -QSlider.TicksBothSides 在滑块两侧都绘制刻度 -QSlider.TicksAbove 在水平滑块上方绘制 -QSlider.TicksBelow 在水平滑块下方绘制 -QSlider.TicksLeft 在垂直滑块左侧绘制 -QSlider.TicksRight 在垂直滑块右侧绘制 - +QSlider.TickPosition.NoTicks 不绘制任何刻度线,默认值 +QSlider.TickPosition.TicksBothSides 在滑块两侧都绘制刻度 +QSlider.TickPosition.TicksAbove 在水平滑块上方绘制 +QSlider.TickPosition.TicksBelow 在水平滑块下方绘制 +QSlider.TickPosition.TicksLeft 在垂直滑块左侧绘制 +QSlider.TickPosition.TicksRight 在垂直滑块右侧绘制 """ +import sys + +from PySide6 import QtWidgets +from PySide6.QtCore import Qt + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -40,14 +39,15 @@ def setup_ui(self) -> None: slider.resize(40, 200) # 设置滑块刻度线位置 - slider.setTickPosition(QtWidgets.QSlider.TicksBothSides) - # slider.setTickPosition(QtWidgets.QSlider.TicksAbove) - # slider.setTickPosition(QtWidgets.QSlider.TicksBelow) + slider.setOrientation(Qt.Orientation.Vertical) # 将滑块方向设置为垂直 + slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksBothSides) + # slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksAbove) + # slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksBelow) - # slider.setOrientation(Qt.Horizontal) # 将滑块方向设置为水平 + # slider.setOrientation(Qt.Orientation.Horizontal) # 将滑块方向设置为水平 # slider.resize(200, 40) - # slider.setTickPosition(QtWidgets.QSlider.TicksLeft) - # slider.setTickPosition(QtWidgets.QSlider.TicksRight) + # slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksLeft) + # slider.setTickPosition(QtWidgets.QSlider.TickPosition.TicksRight) # 设置刻度线间距,默认等于PageStep slider.setTickInterval(25) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/02-QAbstractSpinBox-\350\216\267\345\217\226\346\226\207\346\234\254\343\200\201\345\257\271\351\275\220\346\226\271\345\274\217\343\200\201\345\215\203\345\210\206\347\254\246\343\200\201\347\211\271\346\225\260\345\200\274\346\226\207\346\234\254.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/02-QAbstractSpinBox-\350\216\267\345\217\226\346\226\207\346\234\254\343\200\201\345\257\271\351\275\220\346\226\271\345\274\217\343\200\201\345\215\203\345\210\206\347\254\246\343\200\201\347\211\271\346\225\260\345\200\274\346\226\207\346\234\254.py" index f879d57..edb88da 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/02-QAbstractSpinBox-\350\216\267\345\217\226\346\226\207\346\234\254\343\200\201\345\257\271\351\275\220\346\226\271\345\274\217\343\200\201\345\215\203\345\210\206\347\254\246\343\200\201\347\211\271\346\225\260\345\200\274\346\226\207\346\234\254.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/02-QAbstractSpinBox-\350\216\267\345\217\226\346\226\207\346\234\254\343\200\201\345\257\271\351\275\220\346\226\271\345\274\217\343\200\201\345\215\203\345\210\206\347\254\246\343\200\201\347\211\271\346\225\260\345\200\274\346\226\207\346\234\254.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtWidgets - """ QAbstractSpinBox 文本相关功能 @@ -27,9 +23,12 @@ .setSpecialValueText(text: str) 设置特数值文本 .specialValueText() -> str 获取当前特数值文本,若未设置则返回空字符串 - """ +import sys + +from PySide6 import QtCore, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -51,7 +50,9 @@ def setup_ui(self) -> None: btn.clicked.connect(lambda: print(spin_box.text())) # type: ignore # =================================== 文本对齐方式 =================================== - spin_box.setAlignment(QtCore.Qt.AlignHCenter) # 更改为水平居中对齐,默认为左对齐 + spin_box.setAlignment( + QtCore.Qt.AlignmentFlag.AlignHCenter + ) # 更改为水平居中对齐,默认为左对齐 # ==================================== 千分符 =================================== spin_box.setGroupSeparatorShown(True) # 显示千分符 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/03-QAbstractSpinBox-\346\214\211\351\222\256\346\240\207\345\277\227\343\200\201\350\276\271\346\241\206\343\200\201\345\217\252\350\257\273.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/03-QAbstractSpinBox-\346\214\211\351\222\256\346\240\207\345\277\227\343\200\201\350\276\271\346\241\206\343\200\201\345\217\252\350\257\273.py" index 3433076..546c38a 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/03-QAbstractSpinBox-\346\214\211\351\222\256\346\240\207\345\277\227\343\200\201\350\276\271\346\241\206\343\200\201\345\217\252\350\257\273.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/01-QAbstractSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206\346\212\275\350\261\241\345\237\272\347\261\273/03-QAbstractSpinBox-\346\214\211\351\222\256\346\240\207\345\277\227\343\200\201\350\276\271\346\241\206\343\200\201\345\217\252\350\257\273.py" @@ -1,11 +1,6 @@ -import sys - -from PySide6 import QtWidgets - """ QAbstractSpinBox 按钮标志、边框、只读 - =================================== 按钮标志 =================================== 可以控制数值设定框右侧的按钮的图标,默认为上下箭头 如果需要精细美化界面,可以使用QSS控制用自定义图标替换默认图标 @@ -15,9 +10,9 @@ QAbstractSpinBox.ButtonSymbols枚举值具体有如下数种: https://doc.qt.io/qt-6/qabstractspinbox.html#ButtonSymbols-enum -QAbstractSpinBox.UpDownArrows 经典风格中的向上/向下小箭头 -QAbstractSpinBox.PlusMinus 加号+与减号- -QAbstractSpinBox.NoButtons 不显示任何按钮 +QAbstractSpinBox.ButtonSymbols.UpDownArrows 经典风格中的向上/向下小箭头 +QAbstractSpinBox.ButtonSymbols.PlusMinus 加号+与减号- +QAbstractSpinBox.ButtonSymbols.NoButtons 不显示任何按钮 =================================== 边框 =================================== 可以调整SpinBox外观是否具有边框,默认为具有边框 @@ -33,6 +28,10 @@ .isReadOnly() -> bool """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -48,8 +47,8 @@ def setup_ui(self) -> None: spin_box.move(200, 200) # 设置按钮标志 - spin_box.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus) - # spin_box.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) + spin_box.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.PlusMinus) + # spin_box.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.NoButtons) # 设置边框 spin_box.setFrame(False) # 不显示外边框 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\214\203\345\233\264\343\200\201\345\215\225\346\255\245\343\200\201\346\255\245\347\261\273\345\236\213.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\214\203\345\233\264\343\200\201\345\215\225\346\255\245\343\200\201\346\255\245\347\261\273\345\236\213.py" index 49469d1..ec68fb4 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\214\203\345\233\264\343\200\201\345\215\225\346\255\245\343\200\201\346\255\245\347\261\273\345\236\213.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\214\203\345\233\264\343\200\201\345\215\225\346\255\245\343\200\201\346\255\245\347\261\273\345\236\213.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ QSpinBox @@ -33,11 +29,13 @@ QAbstractSpinBox.StepType枚举值有如下两种类型: https://doc.qt.io/qt-6/qabstractspinbox.html#StepType-enum -QAbstractSpinBox.DefaultStepType -QAbstractSpinBox.AdaptiveDecimalStepType +QAbstractSpinBox.StepType.DefaultStepType +QAbstractSpinBox.StepType.AdaptiveDecimalStepType +""" +import sys -""" +from PySide6 import QtWidgets class MyWidget(QtWidgets.QWidget): @@ -65,7 +63,7 @@ def setup_ui(self) -> None: # 设置步类型 # 注意启用自适应小数步后,之前设置的单步步长失效 - spinbox.setStepType(QtWidgets.QAbstractSpinBox.AdaptiveDecimalStepType) + spinbox.setStepType(QtWidgets.QAbstractSpinBox.StepType.AdaptiveDecimalStepType) if __name__ == "__main__": diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/03-QSpinBox-\346\225\260\345\200\274\343\200\201\346\225\260\345\200\274\346\230\276\347\244\272\350\277\233\345\210\266\343\200\201\345\211\215\345\220\216\347\274\200.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/03-QSpinBox-\346\225\260\345\200\274\343\200\201\346\225\260\345\200\274\346\230\276\347\244\272\350\277\233\345\210\266\343\200\201\345\211\215\345\220\216\347\274\200.py" index 3c272fd..474cd96 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/03-QSpinBox-\346\225\260\345\200\274\343\200\201\346\225\260\345\200\274\346\230\276\347\244\272\350\277\233\345\210\266\343\200\201\345\211\215\345\220\216\347\274\200.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/02-QSpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/03-QSpinBox-\346\225\260\345\200\274\343\200\201\346\225\260\345\200\274\346\230\276\347\244\272\350\277\233\345\210\266\343\200\201\345\211\215\345\220\216\347\274\200.py" @@ -58,7 +58,9 @@ def setup_ui(self) -> None: spinbox.setSuffix(" cm") # 设置后缀 # spinbox.setPrefix("$ ") # 设置前缀 print(f"完整文本为{spinbox.text()}") # 获取文本时会获取到包含前后缀的完整文本 - print(f"数值为{spinbox.text().removesuffix(spinbox.suffix())}") # Python3.9提供的移除后缀方法 + print( + f"数值为{spinbox.text().removesuffix(spinbox.suffix())}" + ) # Python3.9提供的移除后缀方法 print(f"数值为{spinbox.cleanText()}") diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/04-QDateTimeEdit-\346\227\245\346\234\237\346\227\266\351\227\264\347\274\226\350\276\221\345\231\250/01-QDateTimeEdit-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/04-QDateTimeEdit-\346\227\245\346\234\237\346\227\266\351\227\264\347\274\226\350\276\221\345\231\250/01-QDateTimeEdit-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" index 94328fe..f733d1f 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/04-QDateTimeEdit-\346\227\245\346\234\237\346\227\266\351\227\264\347\274\226\350\276\221\345\231\250/01-QDateTimeEdit-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/10-SpinBox-\346\225\260\345\200\274\350\256\276\345\256\232\346\241\206/04-QDateTimeEdit-\346\227\245\346\234\237\346\227\266\351\227\264\347\274\226\350\276\221\345\231\250/01-QDateTimeEdit-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" @@ -36,7 +36,9 @@ def setup_ui(self) -> None: # dte = QtWidgets.QDateTimeEdit(self) # 创建空的日期时间编辑器 # dte = QtWidgets.QDateTimeEdit(my_time, self) # 使用QTime初始化 # dte = QtWidgets.QDateTimeEdit(my_date, self) # 使用QDate初始化 - dte = QtWidgets.QDateTimeEdit(QtCore.QDateTime.currentDateTime(), self) # 使用QDateTime初始化 + dte = QtWidgets.QDateTimeEdit( + QtCore.QDateTime.currentDateTime(), self + ) # 使用QDateTime初始化 dte.move(200, 200) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/03-QComboBox-\346\235\241\347\233\256\346\223\215\344\275\234-2.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/03-QComboBox-\346\235\241\347\233\256\346\223\215\344\275\234-2.py" index c03622d..f3d2a8d 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/03-QComboBox-\346\235\241\347\233\256\346\223\215\344\275\234-2.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/03-QComboBox-\346\235\241\347\233\256\346\223\215\344\275\234-2.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ QComboBox 条目操作 可以控制用户是否能够以编辑条目的方式添加新条目,以及添加新条目时的细节 @@ -51,9 +47,12 @@ QComboBox.AdjustToContentsOnFirstShow 仅在首次出现时调整尺寸,默认值 QComboBox.AdjustToMinimumContentsLengthWithIcon 将尺寸调整至最小内容长度加一个图标,出于性能原因,请在大型模型上使用此策略 - """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -76,19 +75,21 @@ def setup_ui(self) -> None: cbb.setDuplicatesEnabled(True) # 设置插入策略 - # cbb.setInsertPolicy(QtWidgets.QComboBox.NoInsert) - # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertAtTop) - # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertAtCurrent) - cbb.setInsertPolicy(QtWidgets.QComboBox.InsertAtBottom) - # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertAfterCurrent) - # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertBeforeCurrent) - # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertAlphabetically) + # cbb.setInsertPolicy(QtWidgets.QComboBoxInsertPolicy..NoInsert) + # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertAtTop) + # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertAtCurrent) + cbb.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertAtBottom) + # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertAfterCurrent) + # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertBeforeCurrent) + # cbb.setInsertPolicy(QtWidgets.QComboBox.InsertPolicy.InsertAlphabetically) # 设置可编辑文本 cbb.setEditText("000") # 将当前文本设置为00,而不影响其他条目 # 设置尺寸调整策略 - cbb.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents) # 总是根据内容调整尺寸 + cbb.setSizeAdjustPolicy( + QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents + ) # 总是根据内容调整尺寸 # 限制最小字符数 cbb.setMinimumContentsLength(3) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/06-QComboBox-\344\277\241\345\217\267.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/06-QComboBox-\344\277\241\345\217\267.py" index 10a9639..1580faa 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/06-QComboBox-\344\277\241\345\217\267.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/01-QComboBox-\347\273\204\345\220\210\344\270\213\346\213\211\346\241\206/06-QComboBox-\344\277\241\345\217\267.py" @@ -1,14 +1,10 @@ -import sys - -from PySide6 import QtCore, QtWidgets - """ QComboBox 信号 提供了多种精细的信号供使用 .activated(index: int) 当用户在组合下拉框中选中一个条目时发射此信号,索引作为参数传递。即使选中项未改变也会发射 - + .currentIndexChanged(index: int) 当当前索引由用户交互或编程方式改变时发射此信号,索引作为参数传递。 若combobox为空或当前索引已重置,则传递条目的 index 或 -1 @@ -18,11 +14,11 @@ .editTextChanged(text: str) 当启用了可编辑模式,且编辑器中的文本发生改变时发射此信号,新的文本作为参数传递 - + .highlighted(index: int) 当用户高亮(光标移入或键盘选择)了弹出菜单中的某一条目时发射此信号 索引值作为参数传递 - + .textActivated(text: str) 当用户选择了条目之一时,发射此信号并将文本作为参数传递 即使选择未发生改变也会发射此信号 @@ -33,6 +29,10 @@ """ +import sys + +from PySide6 import QtCore, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/01-QFontComboBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/01-QFontComboBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" index e1d4f48..31d61e9 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/01-QFontComboBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/01-QFontComboBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" @@ -29,7 +29,9 @@ def setup_ui(self) -> None: fcb = QtWidgets.QFontComboBox() # 创建示例文本并连接信号,当用户选择字体改变时,对应改变示例文本的字体 - text_label = QtWidgets.QLabel("我能吞下玻璃而不伤身体\nThe quick brown fox jumps over the lazy dog.") + text_label = QtWidgets.QLabel( + "我能吞下玻璃而不伤身体\nThe quick brown fox jumps over the lazy dog." + ) fcb.currentFontChanged.connect(text_label.setFont) # type: ignore # 使用布局管理器布局界面 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\212\237\350\203\275\344\275\234\347\224\250.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\212\237\350\203\275\344\275\234\347\224\250.py" index dd642cd..f60acfe 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\212\237\350\203\275\344\275\234\347\224\250.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/11-ComboBox-\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\255\227\344\275\223\344\270\213\346\213\211\346\241\206/02-QFontComboBox-\345\212\237\350\203\275\344\275\234\347\224\250.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtGui, QtWidgets - """ QFontComboBox 功能作用 @@ -39,9 +35,12 @@ QFontComboBox.NonScalableFonts 显示不可缩放字体 QFontComboBox.MonospacedFonts 显示等宽字体 QFontComboBox.ProportionalFonts 显示比例字体 - """ +import sys + +from PySide6 import QtGui, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -57,7 +56,9 @@ def setup_ui(self) -> None: fcb = QtWidgets.QFontComboBox() # 创建示例文本并连接信号,当用户选择字体改变时,对应改变示例文本的字体 - text_label = QtWidgets.QLabel("我能吞下玻璃而不伤身体。\nThe quick brown fox jumps over the lazy dog.") + text_label = QtWidgets.QLabel( + "我能吞下玻璃而不伤身体。\nThe quick brown fox jumps over the lazy dog." + ) fcb.currentFontChanged.connect(text_label.setFont) # type: ignore # 使用布局管理器布局界面 @@ -67,7 +68,9 @@ def setup_ui(self) -> None: self.setLayout(layout) # ======================== 设置显示字体 ======================== - fcb.setDisplayFont("Arial", QtGui.QFont("Arial Black", italic=True)) # 注意在本地测试时使用本机已安装的字体 + fcb.setDisplayFont( + "Arial", QtGui.QFont("Arial Black", italic=True) + ) # 注意在本地测试时使用本机已安装的字体 # 此时在combobox中的"Arial"条目是用黑体斜体显示的,而非原来的Arial字体 # ======================== 设置示例文本、书写系统 ======================== @@ -75,11 +78,15 @@ def setup_ui(self) -> None: # fcb.setWritingSystem(QtGui.QFontDatabase.SimplifiedChinese) # 设置只显示简体中文书写系统的字体 # 为指定文字系统(简体中文、希腊语、拉丁语、阿拉伯语……)添加示例文本 - fcb.setSampleTextForSystem(QtGui.QFontDatabase.SimplifiedChinese, "我能吞下玻璃而不伤身体。") - fcb.setSampleTextForSystem(QtGui.QFontDatabase.TraditionalChinese, "我能吞下玻璃而不傷身體。") + fcb.setSampleTextForSystem( + QtGui.QFontDatabase.WritingSystem.SimplifiedChinese, "我能吞下玻璃而不伤身体。" + ) + fcb.setSampleTextForSystem( + QtGui.QFontDatabase.WritingSystem.TraditionalChinese, "我能吞下玻璃而不傷身體。" + ) # 获取示例文本 - print(fcb.sampleTextForSystem(QtGui.QFontDatabase.SimplifiedChinese)) - print(fcb.sampleTextForSystem(QtGui.QFontDatabase.Arabic)) + print(fcb.sampleTextForSystem(QtGui.QFontDatabase.WritingSystem.SimplifiedChinese)) + print(fcb.sampleTextForSystem(QtGui.QFontDatabase.WritingSystem.Arabic)) # ======================== 设置字体筛选器 ======================== # 筛选出等宽且不可缩放的字体 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/02-QDialog-\346\250\241\346\200\201\344\270\216\351\235\236\346\250\241\346\200\201\345\257\271\350\257\235\346\241\206.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/02-QDialog-\346\250\241\346\200\201\344\270\216\351\235\236\346\250\241\346\200\201\345\257\271\350\257\235\346\241\206.py" index 488cf9a..d4ea252 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/02-QDialog-\346\250\241\346\200\201\344\270\216\351\235\236\346\250\241\346\200\201\345\257\271\350\257\235\346\241\206.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/02-QDialog-\346\250\241\346\200\201\344\270\216\351\235\236\346\250\241\346\200\201\345\257\271\350\257\235\346\241\206.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ 对话框-模态与非模态 @@ -24,9 +20,12 @@ Qt.NonModal 窗口为非模态,不阻塞其他窗口的输入 Qt.WindowModal 窗口对单个窗口结构层次为模态,阻塞对其父窗口(及其的兄弟窗口)、祖父窗口(及其兄弟窗口)的输入 Qt.ApplicationModal 窗口对应用程序为模态,阻塞对所有窗口的输入 - """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -45,7 +44,7 @@ def setup_ui(self) -> None: dialog_window = QtWidgets.QMessageBox(self) # 使用QDialog的子类来测试 dialog_window.setWindowTitle("模态/非模态对话框") dialog_window.setText("模态窗口将阻塞用户对其他窗口的输入") - dialog_window.setIcon(QtWidgets.QMessageBox.Information) + dialog_window.setIcon(QtWidgets.QMessageBox.Icon.Information) # ================测试模态窗口================================= test_button_1 = QtWidgets.QPushButton("打开模态窗口") diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/03-QDialog-\346\247\275\343\200\201\345\260\272\345\257\270\346\213\226\346\213\275.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/03-QDialog-\346\247\275\343\200\201\345\260\272\345\257\270\346\213\226\346\213\275.py" index a70932c..cd9f73c 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/03-QDialog-\346\247\275\343\200\201\345\260\272\345\257\270\346\213\226\346\213\275.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/01-QDialog-\345\257\271\350\257\235\346\241\206\345\237\272\347\261\273/03-QDialog-\346\247\275\343\200\201\345\260\272\345\257\270\346\213\226\346\213\275.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtCore, QtWidgets - """ QDialog 槽、结果、尺寸拖拽控件 @@ -14,7 +10,7 @@ 则done()也将导致局部事件循环结束,且exec()返回r。 .exec() 将对话框作为模态对话框显示。(默认为应用程序级模态)此函数返回QDialog.Accepted或QDialog.Rejected。 尽量避免使用exec()函数,而用open()替代。因为open()是异步的,并且不会增加额外的事件循环 - + QDialog.result中保存了对话框获得的结果,也可以通过代码显式设置结果码: .result() -> int 获取模态对话框的结果码,QDialog.Accepted为1,QDialog.Rejected为0 .setResult(i: int) 将模态对话框的结果码设置为i @@ -30,6 +26,10 @@ """ +import sys + +from PySide6 import QtCore, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/01-QFileDialog-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/01-QFileDialog-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" index 4ffc073..3d2b88b 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/01-QFileDialog-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/01-QFileDialog-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" @@ -9,7 +9,7 @@ 官方文档:https://doc.qt.io/qtforpython/PySide6/QtWidgets/QFileDialog.html 继承自 QDialog -有两种构造函数,简介版只可选地传入父控件与窗口标志,完整版可以在创建时定义更多属性功能: +有两种构造函数,简洁版只可选地传入父控件与窗口标志,完整版可以在创建时定义更多属性功能: .__init__(self, parent: QWidget, f: QtCore.Qt.WindowFlags) .__init__(self, parent: Optional[QWidget] = None, caption: str = '', directory: str = '', filter: str = '') @@ -26,10 +26,14 @@ def __init__(self, *args, **kwargs): def setup_dialog(self) -> None: """配置对话框属性功能""" - self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) # 打开模式 - self.dialog.setFileMode(QtWidgets.QFileDialog.ExistingFiles) # 选择现有文件 - self.dialog.setLabelText(QtWidgets.QFileDialog.Accept, "选择") # 为「接受」按键指定文本 - self.dialog.setLabelText(QtWidgets.QFileDialog.Reject, "取消") # 为「拒绝」按键指定文本 + self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptMode.AcceptOpen) # 打开模式 + self.dialog.setFileMode(QtWidgets.QFileDialog.FileMode.ExistingFiles) # 选择现有文件 + self.dialog.setLabelText( + QtWidgets.QFileDialog.DialogLabel.Accept, "选择" + ) # 为「接受」按键指定文本 + self.dialog.setLabelText( + QtWidgets.QFileDialog.DialogLabel.Reject, "取消" + ) # 为「拒绝」按键指定文本 def setup_ui(self) -> None: """设置界面""" diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/02-QFileDialog-\346\216\245\345\217\227\346\250\241\345\274\217\343\200\201\351\200\211\351\241\271\343\200\201\350\247\206\345\233\276\346\250\241\345\274\217\343\200\201\346\226\207\344\273\266\346\250\241\345\274\217.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/02-QFileDialog-\346\216\245\345\217\227\346\250\241\345\274\217\343\200\201\351\200\211\351\241\271\343\200\201\350\247\206\345\233\276\346\250\241\345\274\217\343\200\201\346\226\207\344\273\266\346\250\241\345\274\217.py" index 2e519be..97f398b 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/02-QFileDialog-\346\216\245\345\217\227\346\250\241\345\274\217\343\200\201\351\200\211\351\241\271\343\200\201\350\247\206\345\233\276\346\250\241\345\274\217\343\200\201\346\226\207\344\273\266\346\250\241\345\274\217.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/02-QFileDialog-\346\216\245\345\217\227\346\250\241\345\274\217\343\200\201\351\200\211\351\241\271\343\200\201\350\247\206\345\233\276\346\250\241\345\274\217\343\200\201\346\226\207\344\273\266\346\250\241\345\274\217.py" @@ -59,20 +59,20 @@ def setup_dialog(self) -> None: """设置文件对话框""" # 接受模式 - self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) # 文件将用于打开 + self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptMode.AcceptOpen) # 文件将用于打开 # 设置选项 self.dialog.setOptions( - QtWidgets.QFileDialog.DontUseCustomDirectoryIcons # 只使用默认目录图标(提高性能) - | QtWidgets.QFileDialog.DontConfirmOverwrite # 当用户选中现有文件时则无需确认 + QtWidgets.QFileDialog.Option.DontUseCustomDirectoryIcons # 只使用默认目录图标(提高性能) + | QtWidgets.QFileDialog.Option.DontConfirmOverwrite # 当用户选中现有文件时则无需确认 ) # 设置视图模式 # self.dialog.setViewMode(QtWidgets.QFileDialog.Detail) # 显示详细信息(默认) - self.dialog.setViewMode(QtWidgets.QFileDialog.List) # 显示列表信息 + self.dialog.setViewMode(QtWidgets.QFileDialog.ViewMode.List) # 显示列表信息 # 文件模式 - self.dialog.setFileMode(QtWidgets.QFileDialog.ExistingFile) # 只能选择单个现有文件 + self.dialog.setFileMode(QtWidgets.QFileDialog.FileMode.ExistingFile) # 只能选择单个现有文件 def setup_ui(self) -> None: """设置界面""" diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/03-QFileDialog-\351\273\230\350\256\244\345\220\216\347\274\200\345\220\215\343\200\201\346\240\207\347\255\276\346\226\207\346\234\254\343\200\201\347\233\256\345\275\225.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/03-QFileDialog-\351\273\230\350\256\244\345\220\216\347\274\200\345\220\215\343\200\201\346\240\207\347\255\276\346\226\207\346\234\254\343\200\201\347\233\256\345\275\225.py" index dbe0460..556c1fc 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/03-QFileDialog-\351\273\230\350\256\244\345\220\216\347\274\200\345\220\215\343\200\201\346\240\207\347\255\276\346\226\207\346\234\254\343\200\201\347\233\256\345\275\225.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/03-QFileDialog-\351\273\230\350\256\244\345\220\216\347\274\200\345\220\215\343\200\201\346\240\207\347\255\276\346\226\207\346\234\254\343\200\201\347\233\256\345\275\225.py" @@ -38,19 +38,25 @@ def __init__(self, *args, **kwargs): def setup_dialog(self) -> None: """设置文件对话框""" - self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave) # 文件对话框用于保存文件 + self.dialog.setAcceptMode( + QtWidgets.QFileDialog.AcceptMode.AcceptSave + ) # 文件对话框用于保存文件 # 默认后缀名 self.dialog.setDefaultSuffix("txt") # 设置默认后缀名 # 标签文本 - self.dialog.setLabelText(QtWidgets.QFileDialog.Accept, "保存") # 将Accept按钮文本设置为保存 - self.dialog.setLabelText(QtWidgets.QFileDialog.Reject, "取消") # 将Reject标签文本设置为取消 + self.dialog.setLabelText( + QtWidgets.QFileDialog.DialogLabel.Accept, "保存" + ) # 将Accept按钮文本设置为保存 + self.dialog.setLabelText( + QtWidgets.QFileDialog.DialogLabel.Reject, "取消" + ) # 将Reject标签文本设置为取消 def setup_ui(self) -> None: """设置界面""" - self.setWindowTitle("QFileDialog-过滤器") + self.setWindowTitle("QFileDialog-功能测试") # 创建其他控件 info_le = QtWidgets.QLineEdit(self) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/06-QFileDialog-\344\277\241\345\217\267.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/06-QFileDialog-\344\277\241\345\217\267.py" index f2bdad8..23b5fe5 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/06-QFileDialog-\344\277\241\345\217\267.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/03-QFileDialog-\346\226\207\344\273\266\345\257\271\350\257\235\346\241\206/06-QFileDialog-\344\277\241\345\217\267.py" @@ -41,8 +41,8 @@ def test_signals(self) -> None: def setup_dialog(self) -> None: """设置文件对话框""" - self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) - self.dialog.setFileMode(QtWidgets.QFileDialog.ExistingFiles) + self.dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptMode.AcceptOpen) + self.dialog.setFileMode(QtWidgets.QFileDialog.FileMode.ExistingFiles) self.dialog.setNameFilters( ("Python files (*.py)", "Markdown files (*.md)", "Any files (*)") ) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/01-QMessageBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/01-QMessageBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" index 90e7c91..4a6f2d8 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/01-QMessageBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/01-QMessageBox-\347\256\200\344\273\213\344\270\216\345\210\233\345\273\272.py" @@ -35,17 +35,17 @@ def setup_ui(self) -> None: # 第一种构造函数 # message_box = QtWidgets.QMessageBox(self) - # message_box.setIcon(QtWidgets.QMessageBox.Warning) + # message_box.setIcon(QtWidgets.QMessageBox.Icon.Warning) # message_box.setWindowTitle("这是一个消息提示框") # message_box.setText("您不能在关闭模态对话框前操作其他窗口!") # message_box.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) # 以上设置等价于第二种构造函数: message_box = QtWidgets.QMessageBox( - QtWidgets.QMessageBox.Warning, + QtWidgets.QMessageBox.Icon.Warning, "这是一个消息提示框", "您不能在关闭模态对话框前操作其他窗口!", - QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, + QtWidgets.QMessageBox.StandardButton.Ok | QtWidgets.QMessageBox.StandardButton.Cancel, self, ) diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/02-QMessageBox-\346\226\207\346\234\254\344\270\216\345\233\276\346\240\207.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/02-QMessageBox-\346\226\207\346\234\254\344\270\216\345\233\276\346\240\207.py" index 4676ec8..b908e07 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/02-QMessageBox-\346\226\207\346\234\254\344\270\216\345\233\276\346\240\207.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/02-QMessageBox-\346\226\207\346\234\254\344\270\216\345\233\276\346\240\207.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtGui, QtWidgets - """ QMessageBox 文本与图标 @@ -37,9 +33,12 @@ 如要设置自定义图标,则应使用setIconPixmap方法: .setIconPixmap(icon: QPixmap) 设置自定义图标,需要为位图形式 .iconPixmap() -> QPixmap 获取设置的图标 - """ +import sys + +from PySide6 import QtGui, QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -60,7 +59,7 @@ def setup_ui(self) -> None: message_box.setInformativeText("这是一段信息文本") # 设置图标 - # message_box.setIcon(QtWidgets.QMessageBox.Information) # 设置标准图标 + # message_box.setIcon(QtWidgets.QMessageBox.Icon.Information) # 设置标准图标 my_icon = QtGui.QPixmap("../../../Resources/Icons/Qt_for_Python_128px.png") message_box.setIconPixmap(my_icon) # 设置自定义图标 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/03-QMessageBox-\346\214\211\351\222\256.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/03-QMessageBox-\346\214\211\351\222\256.py" index 3f41968..8a032d5 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/03-QMessageBox-\346\214\211\351\222\256.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/03-QMessageBox-\346\214\211\351\222\256.py" @@ -1,7 +1,3 @@ -import sys - -from PySide6 import QtWidgets - """ QMessageBox 按钮 @@ -33,6 +29,10 @@ """ +import sys + +from PySide6 import QtWidgets + class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): @@ -58,17 +58,23 @@ def setup_message_box(self) -> None: self.message_box.setText("一段对话框正文文本") # 设置标准按钮 - self.message_box.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel) + self.message_box.setStandardButtons( + QtWidgets.QMessageBox.StandardButton.Ok | QtWidgets.QMessageBox.StandardButton.Cancel + ) # 设置默认按钮、Esc按钮 - self.message_box.setDefaultButton( - self.message_box.button(QtWidgets.QMessageBox.Ok) - ) # 通过.button()方法返回按钮实例 - self.message_box.setEscapeButton(self.message_box.button(QtWidgets.QMessageBox.Cancel)) + self.message_box.setDefaultButton(QtWidgets.QMessageBox.StandardButton.Ok) + self.message_box.setEscapeButton( + self.message_box.button(QtWidgets.QMessageBox.StandardButton.Cancel) + ) # 添加按钮 - self.message_box.addButton("自定义按钮", QtWidgets.QMessageBox.AcceptRole) # 通过自定义文本与按钮角色添加 - discard_btn = self.message_box.addButton(QtWidgets.QMessageBox.Discard) # 添加标准按钮,返回值为按钮实例 + self.message_box.addButton( + "自定义按钮", QtWidgets.QMessageBox.ButtonRole.AcceptRole + ) # 通过自定义文本与按钮角色添加 + discard_btn = self.message_box.addButton( + QtWidgets.QMessageBox.StandardButton.Discard + ) # 添加标准按钮,返回值为按钮实例 # 获取按钮角色 print(self.message_box.buttonRole(discard_btn)) # 将discard_btn按钮的角色打印到终端 diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/04-QMessageBox-\351\235\231\346\200\201\346\226\271\346\263\225.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/04-QMessageBox-\351\235\231\346\200\201\346\226\271\346\263\225.py" index 712bb8f..3b69be4 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/04-QMessageBox-\351\235\231\346\200\201\346\226\271\346\263\225.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/04-QMessageBox-\351\235\231\346\200\201\346\226\271\346\263\225.py" @@ -34,7 +34,6 @@ question()、warning()、critical() 静态方法与 information() 非常相似,类比使用即可,不再赘述。 - """ import sys @@ -71,16 +70,18 @@ def test_static(self): """测试QMessageBox的静态方法""" self.about_btn.clicked.connect( - lambda: QMessageBox.about(self, "关于此程序", "本程序为PySide6 Code Tutorial中的一个案例") + lambda: QMessageBox.about( + self, "关于此程序", "本程序为PySide6 Code Tutorial中的一个案例" + ) ) # type: ignore self.about_qt_btn.clicked.connect(lambda: QMessageBox.aboutQt(self)) # type: ignore user_result_dict = { - QMessageBox.Ok: "OK", - QMessageBox.Cancel: "取消", - QMessageBox.Discard: "不保存", - QMessageBox.Save: "保存", - QMessageBox.Apply: "应用", + QMessageBox.StandardButton.Ok: "OK", + QMessageBox.StandardButton.Cancel: "取消", + QMessageBox.StandardButton.Discard: "不保存", + QMessageBox.StandardButton.Save: "保存", + QMessageBox.StandardButton.Apply: "应用", } @QtCore.Slot() @@ -90,8 +91,8 @@ def show_info_dlg() -> None: self, "静态方法-信息", "这里可以展示一些信息", - QMessageBox.Ok, - QMessageBox.Cancel, + QMessageBox.StandardButton.Ok, + QMessageBox.StandardButton.Cancel, ) # 调用静态函数展示信息,将返回值保存到result变量中 self.label.setText(f"用户选择了:{user_result_dict[result]}") self.label.adjustSize() @@ -99,7 +100,12 @@ def show_info_dlg() -> None: @QtCore.Slot() def show_warn_dlg() -> None: """self.warning_btn对应的槽函数""" - result = QMessageBox.warning(self, "静态方法-警告", "警告:直接退出将不会保存修改", QMessageBox.Discard) + result = QMessageBox.warning( + self, + "静态方法-警告", + "警告:直接退出将不会保存修改", + QMessageBox.StandardButton.Discard, + ) self.label.setText(f"用户选择了:{user_result_dict[result]}") self.label.adjustSize() diff --git "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/05-QMessageBox-\344\277\241\345\217\267.py" "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/05-QMessageBox-\344\277\241\345\217\267.py" index c89b755..f29cf11 100644 --- "a/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/05-QMessageBox-\344\277\241\345\217\267.py" +++ "b/03-QtWidgets-\345\270\270\347\224\250\346\216\247\344\273\266/12-Dialog-\345\257\271\350\257\235\346\241\206/05-QMessageBox-\344\277\241\346\201\257\346\217\220\347\244\272\346\241\206/05-QMessageBox-\344\277\241\345\217\267.py" @@ -24,10 +24,10 @@ def setup_ui(self) -> None: # 创建对话框 message_box = QtWidgets.QMessageBox( - QtWidgets.QMessageBox.Warning, + QtWidgets.QMessageBox.Icon.Warning, "这是一个消息提示框", "您不能在关闭模态对话框前操作其他窗口!", - QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, + QtWidgets.QMessageBox.StandardButton.Ok | QtWidgets.QMessageBox.StandardButton.Cancel, self, ) diff --git "a/05-QtWidgets-\350\277\233\351\230\266\350\257\235\351\242\230/02-QSS-\346\240\267\345\274\217\350\241\250/01-QSS\344\270\273\351\242\230\345\217\212\347\274\226\350\276\221\345\231\250.md" "b/05-QtWidgets-\350\277\233\351\230\266\350\257\235\351\242\230/02-QSS-\346\240\267\345\274\217\350\241\250/01-QSS\344\270\273\351\242\230\345\217\212\347\274\226\350\276\221\345\231\250.md" index 0365495..ba4475b 100644 --- "a/05-QtWidgets-\350\277\233\351\230\266\350\257\235\351\242\230/02-QSS-\346\240\267\345\274\217\350\241\250/01-QSS\344\270\273\351\242\230\345\217\212\347\274\226\350\276\221\345\231\250.md" +++ "b/05-QtWidgets-\350\277\233\351\230\266\350\257\235\351\242\230/02-QSS-\346\240\267\345\274\217\350\241\250/01-QSS\344\270\273\351\242\230\345\217\212\347\274\226\350\276\221\345\231\250.md" @@ -67,7 +67,7 @@ class QSSLoader: ```python app = QApplication(sys.argv) window = MainWindow() - + style_file = './style.qss' style_sheet = QSSLoader.read_qss_file(style_file) window.setStyleSheet(style_sheet) diff --git "a/07-Packaging-\350\265\204\346\272\220\347\256\241\347\220\206\344\270\216\346\211\223\345\214\205/01-\350\265\204\346\272\220\347\256\241\347\220\206/01-\345\234\250PyQt\344\270\255\344\275\277\347\224\250qrc-rcc\350\265\204\346\272\220\347\263\273\347\273\237.md" "b/07-Packaging-\350\265\204\346\272\220\347\256\241\347\220\206\344\270\216\346\211\223\345\214\205/01-\350\265\204\346\272\220\347\256\241\347\220\206/01-\345\234\250PyQt\344\270\255\344\275\277\347\224\250qrc-rcc\350\265\204\346\272\220\347\263\273\347\273\237.md" new file mode 100644 index 0000000..112a676 --- /dev/null +++ "b/07-Packaging-\350\265\204\346\272\220\347\256\241\347\220\206\344\270\216\346\211\223\345\214\205/01-\350\265\204\346\272\220\347\256\241\347\220\206/01-\345\234\250PyQt\344\270\255\344\275\277\347\224\250qrc-rcc\350\265\204\346\272\220\347\263\273\347\273\237.md" @@ -0,0 +1,470 @@ +# 在PyQt中使用qrc/rcc资源系统 + +> 本文摘自[在PyQt中使用qrc/rcc资源系统 - muzing的杂货铺](https://muzing.top/posts/75a2283d/) + +## Qt 资源系统简介 + +Qt 资源系统([The Qt Resource System](https://doc.qt.io/qt-6/resources.html))是一种独立于平台的资源管理器,用于在应用程序的可执行文件中存储二进制文件。对 PyQt 而言,这意味着在 Python 代码中直接以二进制形式存储图标、[QSS](https://muzing.top/posts/28a1d80f/)、长文本翻译等资源文件。使用 Qt 资源管理系统可以有效防止资源文件丢失,对于需要打包发布 的 PyQt 程序尤其实用。 + +在项目中使用 Qt 资源系统,大致分为三个步骤:编写 `.qrc` 文件、使用 rcc 编译资源、导入与使用。下文将一一详细讲解。 + +## qrc 文件 + +### 简介与示例 + +Qt 资源集合文件(Qt Resource Collection File)一般以 `.qrc` 作为扩展名保存,故简称 `.qrc` 文件。其文件格式基于 [XML](https://www.wikiwand.com/en/XML),用于将文件系统(硬盘)中的资源文件与 Qt 应用程序关联起来。`.qrc` 还可以实现为资源分组、设置别名等功能。 + +下面是一个简单的例子: + +`Resources` 目录下包含图标、关于文档等资源文件。 + +```shell +$ tree Resources +Resources +├── Icons +│   ├── Py2exe-GUI_icon_72px.png +│   └── Python_128px.png +├── Texts +│  └── About_zh.md +└── resources.qrc +``` + +在此处新建一个 `resources.qrc` 文件,内容如下: + +```xml + + + + Icons/Py2exe-GUI_icon_72px.png + Icons/Python_icon.ico + Texts/About_zh.md + + +``` + +> 注意文件的相对路径是以 `.qrc` 所在的目录 `Resources\` 为根目录开始计算的。 + +这样便建立了硬盘上文件系统中原文件与 Qt 资源系统中[资源路径](#资源路径)之间的联系。 + +### 使用前缀进行分组 + +在文件系统中,可以通过目录对不同类型的资源进行分组。在上面的例子中,图标文件都在 `Icons/` 目录下,而长文本在 `Texts/` 下。在 `.qrc` 中,也可以通过指定 `` 标签的 `prefix` 属性来对资源进行分组: + +```xml + + + + Icons/Py2exe-GUI_icon_72px.png + Icons/Python_icon.ico + + + Texts/About_zh.md + + +``` + +### 为资源创建别名 + +有些资源的文件名很长,每次使用时都输入完整文件名较为繁琐。可以通过在 `` 标签中添加 `alias` 属性为其创建别名,方便未来在[资源路径](#资源路径)中使用: + +```xml + + + + Icons/Py2exe-GUI_icon_72px.png + Icons/Python_icon.ico + + + Texts/About_zh.md + + +``` + +## 使用 rcc 编译资源 + +### rcc 简介 + +Qt 提供了 [Resource Compiler](https://doc.qt.io/qt-6/rcc.html) 命令行工具(简称 rcc),用于在构建过程中将资源嵌入 Qt 应用程序。对于 PyQt,也有对应版本的 rcc 工具,用于将 `.qrc` 中指定的资源文件数据编译至 Python 对象。 + +### rcc 的安装与基本使用 + +当通过 `pip` 安装 PySide6 或其他 PyQt 时,会同时自动安装对应版本的 rcc 工具。这些工具的调用命令有所不同(详见下表),但使用方式与功能是一致的。激活已安装 PyQt 的 Python 虚拟环境,在命令行(注意不是 Python 交互式解释器)中输入对应的 rcc 命令即可。 + +| 平台 | rcc 命令名称 | +|---------|---------------| +| PySide6 | `pyside6-rcc` | +| PyQt5 | `pyrcc5` | +| PySide2 | `pyside2-rcc` | +| PyQt6 | 不提供 | + +> 使用 PySide6 提供的 `pyside6-rcc` 工具编译出的 `.py` 文件,也可以放入 PyQt6 项目中使用,只需将文件开头的 `from PySide6 import QtCore` 替换为 `from PyQt6 import QtCore` 即可。 + +例如,对于 PySide6,在命令行调用命令 + +```shell +pyside6-rcc -o compiled_resources.py resources.qrc +``` + +即可将 `resources.qrc` 中列出的资源文件编译到输出文件 `compiled_resources.py` 中。 + +### rcc 命令行选项 + +此处以 pyside6-rcc 6.4.1 为例,列出了完整的选项列表(翻译版): + +```shell +$ pyside6-rcc --help +Usage: /path/to/your/python3/site-packages/PySide6/Qt/libexec/rcc [options] inputs +Qt Resource Compiler version 6.4.1 + +Options: + -h, --help 显示关于命令行选项的帮助 + + --help-all 显示包括Qt独有选项在内的所有帮助 + + -v, --version 显示版本信息 + + -o, --output 将输出写入到 中,而不是 stdout 中 + + -t, --temp 为大资源文件使用临时文件 + + --name 创建一个外部初始化函数 + + --root 用根目录 作为资源访问路径的前缀 + + --compress-algo 使用 算法压缩输入文件([zlib], none) + + --compress 级别压缩输入文件 + + --no-compress 禁用所有压缩,等同于 --compress-algo=none + + --no-zstd 禁止使用 zstd 压缩 + + --threshold 衡量是否值得进行压缩的阈值 + + --binary 输出一个作为动态资源使用的二进制文件 + + -g, --generator 选择生成器 + + --pass Pass number for big resources + + --namespace 关闭命名空间宏 + + --verbose 启用 verbose 模式 + + --list 只列出 .qrc 文件条目,不生成代码 + + --list-mapping 只输出 .qrc 中定义的资源路径与文件系统路径的 + 映射,不生成代码 + + -d, --depfile 中写入一个包含 .qrc 依赖项的 depfile + + --project 输出一个包含当前目录下所有文件的资源文件 + + --format-version 写入 RCC 格式的版本 + +Arguments: + inputs 输入文件 (*.qrc) +``` + +### 编译出的 Python 文件 + +运行成功后,在 `.qrc` 中声明的所有资源文件都已经被编译到 `compiled_resources.py` 这个 Python 文件中,不妨打开查看其内容: + +```python +# 以下为 compiled_resources.py 文件中内容 + +# Resource object code (Python 3) +# Created by: object code +# Created by: The Resource Compiler for Qt version 6.4.1 +# WARNING! All changes made in this file will be lost! + +from PySide6 import QtCore + +qt_resource_data = b"......" + +qt_resource_name = b"......" + +qt_resource_struct = b"......" + +def qInitResources(): + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() + +``` + +最上方的注释标明了该文件由与 Qt6.4.1 版本匹配的资源编译器生成。并警告用户不要直接编辑该文件,因为所有修改都会被下一次编译操作覆盖掉。 + +接下来是三段长长的二进制编码字符串,其中正是资源文件: + +- `qt_resource_data` - 资源文件内容数据 +- `qt_resource_name` - 资源文件名称 +- `qt_resource_struct` - 资源结构 + +还有两个函数 `qInitResources()` 与 `qCleanupResources()`,分别对应向 Qt 中注册资源与清理资源。 + +代码的最后一行调用了注册资源函数。 + +## 在主程序中使用 + +对于 PyQt 程序,从「直接加载使用资源文件」切换到「使用 Qt 资源系统读取资源」,还需要如下步骤: + +1. 在主程序中导入编译后的资源 +2. 用「资源路径」替换「文件路径」 +3. 由使用 Python 内置 `open()` 函数改为使用 Qt 中 [QFile](https://doc.qt.io/qt-6/qfile.html) 类或 [QDir](https://doc.qt.io/qt-6/qdir.html) 类提供的 `open()` 方法 + +### 导入编译后的资源 + +在主程序中添加 import 导入语句,将刚才获得的 `compiled_resources.py` 导入: + +```python +import compiled_resources # type: ignore +``` + +因为 import 的过程会执行该模块中的所有代码,也就自动调用了 `qInitResources()` 函数,完成了资源的注册与加载。 + +> PyCharm 等 IDE 可能将此行代码判断为 “未使用的 import 语句” 而提示一个弱警告。可以通过在该行末尾添加特殊的 `# type: ignore` 注释来显式告知静态检查器忽略此行,消除这种不必要的警告。 + +### 资源路径 + +对于直接使用资源原文件,会使用其在文件系统中的路径,例如 + +```python +icon = QPixmap("Icons/Python_icon.ico") +``` + +而在 Qt 资源系统中使用,则需要将文件路径替换为「资源路径」。资源路径由 `.qrc` 文件决定。 + +对于最一般的情况,直接在文件名前添加 `:/` 即可得到其资源路径: + +```xml + + Icons/Python_icon.ico + +``` + +```python +icon = QPixmap(":/Python_icon.ico") +``` + +对于有前缀进行分组的,则需要在文件名前添加 `:/$prefix$/`作为资源路径: + +```xml + + Icons/Python_icon.ico + +``` + +```python +icon = QPixmap(":/icons/Python_icon.ico") +``` + +对于指定了别名的,可以直接使用别名: + +```xml + + Icons/Python_icon.ico + +``` + +```python +icon = QPixmap(":/icons/Py_ico") +``` + +### 读取资源文件 + +需要使用 Qt 提供的 [QFile](https://doc.qt.io/qt-6/qfile.html) 或 [QDir](https://doc.qt.io/qt-6/qdir.html) 读取编译后的资源文件,而不再能使用 Python 提供的 `open()` 函数等。 + +例如,一段从 Markdown 文件中读取应用程序“关于”文本的代码,使用直接读取原资源文件的写法如下: + +```python +def get_about_text(): + about_file = open("Resources/About.md", "r", encoding="utf-8") # 调用Python内置的open() + about_text = about_file.read() + about_file.close() + return about_text +``` + +而使用 Qt 资源系统后,需要修改为如下形式: + +```python +from PySide6.QtCore import QFile, QIODevice + +def get_about_text(): + # 使用Qt风格读取文本文件 + about_file = QFile(":/texts/About_Text") # 使用Qt中的QFile类 + about_file.open(QIODevice.ReadOnly | QIODevice.Text) # 打开文件 + about_text = str(about_file.readAll(), encoding="utf-8") # 读取文件,并将 QBtyeArray 转为 str + about_file.close() + return about_text +``` + +或者使用本项目提供的 [`OpenQFile`](./open_qfile.py): + +```python +from open_qfile import OpenQFile + +with OpenQFile(":/texts/About_Text", "rt", encoding="utf-8") as f: + about_text = f.read() +``` + +对于图片,可以在创建 [QIcon](https://doc.qt.io/qt-6/qicon.html)、[QImage](https://doc.qt.io/qt-6/qimage.html)、[QPixmap](https://doc.qt.io/qt-6/qpixmap.html) 对象时将直接资源路径作为参数传入: + +```python +icon = QPixmap(":/icons/Python_icon.ico") +``` + +## 在 IDE 中配置 + +### 在 PyCharm 中配置使用 rcc + +可以将 rcc 工具添加至 PyCharm 中,避免每次使用都需要输入繁琐的命令行。(目前版本的 PyCharm 中已经原生内置了对 `pyrcc4` 和 `pyside-rcc` 的支持,但其他版本的 rcc 工具快捷使用仍需自行在「外部工具」中创建。) + +打开 文件 -> 设置 -> 工具 -> 外部工具(File -> Settings -> Tools -> External Tools) + +![打开设置-工具-外部工具](../../Resources/Images/qrc-rcc/20210925181843.png) + +然后创建工具。配置可以参考下图,仍然以 `pyside6-rcc` 为例: + +![在 PyCharm 中配置 rcc 工具](../../Resources/Images/qrc-rcc/20221204112134.png) + +其中比较重要的是「工具设置」里面的三行配置: + +```text +程序: $PyInterpreterDirectory$/pyside6-rcc +实参: -o compiled_$FileNameWithoutExtension$.py $FileName$ +工作目录: $FileDir$ +``` + +其中凡是以一对 `$` 包裹的字符,均为 PyCharm 提供的宏,分别代表「Python 解释器目录」、「不带扩展名的文件名」、「文件名」和「文件所在目录」。 + +完成配置后,在待编译的 `.qrc` 文件上打开右键菜单,找到「外部工具 - pyside6-rcc」,点击即可运行,非常方便。 + +![在右键菜单中使用pyside6-rcc外部工具](../../Resources/Images/qrc-rcc/20221204114804.png) + +### 使用 VS Code 编辑 qrc + +安装 [Qt for Python](https://marketplace.visualstudio.com/items?itemName=seanwu.vscode-qt-for-python) 插件后,VS Code 编辑器会对 `.qrc` 文件提供一定的语法高亮、亦可一键编译。 + +```shell +# VS Code 插件安装命令: +ext install seanwu.vscode-qt-for-python +``` + +![Qt for Python 插件提供了丰富的功能](../../Resources/Images/qrc-rcc/20221206210735.png) + +### 使用 QtCreator 编辑 qrc + +> 此小节参考自 。 + +直接在文本编辑器中以 XML 形式编写复杂的 `.qrc` 文件时,较为繁琐、易出错,可以考虑安装 Qt 官方的 [QtCreater](https://www.qt.io/product/development-tools) IDE 来生成 `.qrc` 文件。 + +```shell +$ tree resource +resource +├── icon +│   ├── ic_last_step.svg +│   ├── ic_next_step.svg +│   └── ic_start.svg +└── res.qrc +``` + +首先启动 QtCreater,在 `resource/` 目录中新建 `res.qrc` 文件: + +![创建qrc文件与添加图标路径](../../Resources/Images/qrc-rcc/20210925093659593.gif) + +然后以 icon 前缀创建一个分组: + +![添加前缀](../../Resources/Images/qrc-rcc/20210925093839859.gif) + +接着用 Add Files 按钮把图标文件添加进来,并保存: + +![将图标文件添加到路径中](../../Resources/Images/qrc-rcc/20210925094012183.gif) + +此时得到了 `res.qrc`: + +```xml + + + icon/ic_last_step.svg + icon/ic_next_step.svg + icon/ic_start.svg + + +``` + +为了缩短引用路径,还可以为每个图标文件设置别名(alias): + +![设置别名](../../Resources/Images/qrc-rcc/20210925102011356.gif) + +现在得到这样的 `res.qrc`: + +```xml + + + icon/ic_last_step.svg + icon/ic_next_step.svg + icon/ic_start.svg + + +``` + +## 进阶话题 + +### 国际化多语言 + +有时应用程序需要在不同的语言环境下使用不同的文件,可以通过设置 `lang` 属性来轻松实现。下面是一个例子: + +```xml + + cut.jpg + + + cut_fr.jpg + +``` + +当系统语言为其他语言时,Qt 程序将会使用文件 `cut.jpg`;而当系统语言为法语时,会自动替换为 `cut_fr.jpg`。 + +### 压缩 + +rcc 会尝试压缩内容以优化硬盘空间使用。默认情况下,它将进行启发式检查以确认是否值得压缩。如果不能充分压缩,则将直接存储非压缩的内容。可以使用 `-threshold` [选项](#rcc-命令行选项)控制此判断的阈值。例如,默认情况下阈值为 70,表示只有在压缩后的文件比原文件小 70%(不超过原文件大小的 30%)时才有必要压缩。 + +```shell +rcc -threshold 25 myresources.qrc +``` + +在某些情况下也可以关闭压缩功能。一种常见情况是,某些资源已经是压缩后的格式(例如 `.png` 文件),再次压缩几乎不会进一步减小文件体积,但会占用 CPU 成本。另一种情况是,硬盘空间非常充裕,期望应用程序在运行时可以将内容存储在干净的内存页中。在[命令行](#rcc-命令行选项)中添加 `-no-compress` 命令以关闭压缩。 + +```shell +rcc -no-compress myresources.qrc +``` + +还可以控制 rcc 使用的压缩算法与压缩级别,例如: + +```shell +rcc -compress 2 -compress-algo zlib myresources.qrc +``` + +表示使用 zlib 压缩算法,压缩等级为 2。 + +除了在命令行调用 rcc 时指定选项,还可以在 `.qrc` 文件中控制阈值、压缩算法与压缩等级: + +```xml + + data.txt + +``` + +rcc 具体支持的压缩算法类型与压缩等级,参见[官方文档](https://doc.qt.io/qt-6/resources.html#compression)。 + +## 参考资料 + +1. [Qt6 官方文档:The Qt Resource System](https://doc.qt.io/qt-6/resources.html) +2. [Qt6 官方文档:Resource Compiler (rcc)](https://doc.qt.io/qt-6/rcc.html) +3. [Qt for Python 官方教程:Using .qrc Files (pyside6-rcc)](https://doc.qt.io/qtforpython/tutorials/basictutorial/qrcfiles.html) +4. [pyside6(1):Qt 资源系统和qrc文件使用](https://blog.csdn.net/anbuqi/article/details/120455219) +5. [Stack Overflow: How can resources be provided in PyQt6 (which has no pyrcc)?](https://stackoverflow.com/questions/66099225) diff --git "a/07-Packaging-\350\265\204\346\272\220\347\256\241\347\220\206\344\270\216\346\211\223\345\214\205/01-\350\265\204\346\272\220\347\256\241\347\220\206/open_qfile.py" "b/07-Packaging-\350\265\204\346\272\220\347\256\241\347\220\206\344\270\216\346\211\223\345\214\205/01-\350\265\204\346\272\220\347\256\241\347\220\206/open_qfile.py" new file mode 100644 index 0000000..d2724a8 --- /dev/null +++ "b/07-Packaging-\350\265\204\346\272\220\347\256\241\347\220\206\344\270\216\346\211\223\345\214\205/01-\350\265\204\346\272\220\347\256\241\347\220\206/open_qfile.py" @@ -0,0 +1,201 @@ +import locale +import os +import pathlib +import warnings +from typing import Optional, Union + +from PySide6.QtCore import QFile, QIODevice + + +class QtFileOpen: + """ + 通过 QFile 读写文件的上下文管理器 \n + 使与 Python 的 with 语句风格统一 \n + + 使用举例: + + with QtFileOpen("./test.txt", "rt", encoding="utf-8") as f: + print(f.read()) + """ + + def __init__( + self, + file: Union[str, bytes, os.PathLike[str]], + mode="r", + encoding: Optional[str] = None, + ): + """ + :param file: 文件路径 + :param mode: 打开模式(暂时只支持文本读取) + :param encoding: 文本文件编码 + """ + + # 预处理文件路径,防止在 Windows 平台下 QFile 只能处理 '/' 导致的问题 + file_path = self.deal_path(file) + print(file_path) + + # 分析模式是否合法、返回正确的 FileIo 类实例 + # https://docs.python.org/zh-cn/3/library/functions.html#open + if "b" not in mode: + # 文本模式 + self.io_obj = PyQTextFileIo(file_path, mode, encoding) + else: + # 二进制模式(暂不支持) + # self.io_obj = PyQByteFileIo(file, mode) + raise ValueError("暂不支持该模式") + + def __enter__(self): + return self.io_obj + + def __exit__(self, exc_type, exc_val, exc_tb): + self.io_obj.close() + + @classmethod + def deal_path(cls, path) -> str: + """ + 预处理文件路径,确保使用 / 风格 + :param path: 文件路径 + :return: 使用正斜杠(/)的路径字符串 + """ + + # 若路径以字节串传入,则先处理成字符串 + if isinstance(path, bytes): + path = str(path, encoding=locale.getencoding()) + + return str(pathlib.PurePath(path).as_posix()) + + +class PyQTextFileIo: + """ + 将 QFile 中处理文本文件读写的部分封装成 Python的 io 风格 + 目前只支持读取,不支持写入 + """ + + def __init__( + self, + file: Union[str, bytes, os.PathLike[str]], + mode, + encoding: Optional[str] = None, + ): + self._file = QFile(file) + + if encoding is not None: + self.encoding = encoding + else: + # 用户未指定编码,则使用当前平台默认编码 + self.encoding = locale.getencoding() + + self.mode = self._parse_mode(mode) + self._file.open(self.mode) + + @classmethod + def _parse_mode(cls, py_mode: str) -> QIODevice: + """ + 解析文件打开模式,将 Python open() 风格转换至 QIODevice.OpenModeFlag + https://docs.python.org/zh-cn/3/library/functions.html#open + https://doc.qt.io/qt-6/qiodevicebase.html#OpenModeFlag-enum + :return: mode + """ + + qt_mode: QIODevice = QIODevice.Text + + # 暂不支持写入 + if "r" in py_mode and "+" not in py_mode: + qt_mode = qt_mode | QIODevice.ReadOnly + elif "w" in py_mode: + qt_mode = qt_mode | QIODevice.WriteOnly + elif "+" in py_mode: + qt_mode = qt_mode | QIODevice.ReadWrite + + if "x" in py_mode: + qt_mode = qt_mode | QIODevice.NewOnly + + return qt_mode + + def readable(self) -> bool: + """ + 当前文件是否可读 \n + :return: isReadable + """ + + return self._file.isReadable() + + def read(self, size: int = -1) -> str: + """ + 从流中读取至多 size 个字符并以单个 str 的形式返回。 如果 size 为负值或 None,则读取至 EOF。 \n + https://docs.python.org/3/library/io.html#io.TextIOBase.read + :param size: 读取的字符数,负值或 None 表示一直读取直到 EOF + :return: 文件中读出的文本内容 + """ + + if not self.readable(): + raise OSError(f"File '{self._file.fileName()}' is not Readable.") + + if size < 0 or size is None: + # 读取文件,并将 QByteArray 转为 str + text = str(self._file.readAll(), encoding=self.encoding) + else: + # 已知问题:性能太差 + # PySide6.QtCore.QIODevice.read(maxlen) 以字节而非字符方式计算长度,行为不一致 + # 而 QTextStream 对字符编码支持太差,许多编码并不支持 + text = str(self._file.readAll(), encoding=self.encoding)[0:size] # 性能太差 + + return text + + def readline(self, size: int = -1, /) -> str: + """ + 模仿 io.TextIOBase.readline 的行为,读取文件中的一行。 \n + https://docs.python.org/3/library/io.html#io.TextIOBase.readline + :param size: 如果指定了 size ,最多将读取 size 个字符。 + :return: 单行文本 + """ + + if not self.readable(): + raise OSError(f"File '{self._file.fileName()}' is not Readable.") + + if self._file.atEnd(): + warnings.warn( + f"Trying to read a line at the end of the file '{self._file.fileName()}'." + ) + return "" + else: + if size == 0: + return "" + else: + line = str(self._file.readLine(), encoding=self.encoding) + if size < 0: + return line + else: + return line[0:size] + + def readlines(self, hint: int = -1, /) -> list[str]: + """ + 模仿 Python 中 io.IOBase.readlines() 的行为,返回由所有行组成的字符串列表。 \n + Known issue: slower than `readline()` \n + https://docs.python.org/3/library/io.html#io.IOBase.readlines + :param hint: 要读取的字符数 + :return: 文本内容所有行组成的列表 + """ + + if not self.readable(): + raise OSError(f"File '{self._file.fileName()}' is not Readable.") + + if hint <= 0 or hint is None: + temp = str(self._file.readAll(), encoding=self.encoding) + all_lines = temp.splitlines(keepends=True) + else: + all_lines = [] + char_num = 0 + while char_num <= hint and not self._file.atEnd(): + new_line = self.readline() + all_lines.append(new_line) + char_num += len(new_line) + + return all_lines + + def close(self) -> None: + """ + 关闭打开的文件对象 + """ + + self._file.close() diff --git a/README.md b/README.md index efb742a..f3d683b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -logo +logo # PySide6 代码式教程 @@ -7,10 +7,10 @@ ![GitHub Repo stars](https://img.shields.io/github/stars/muziing/PySide6-Code-Tutorial) ![License](https://img.shields.io/github/license/muziing/PySide6-Code-Tutorial) ![GitHub Last Commit](https://img.shields.io/github/last-commit/muziing/PySide6-Code-Tutorial) -[![PySide Version](https://img.shields.io/badge/PySide-6.3-blue)](https://doc.qt.io/qtforpython/index.html) +[![PySide Version](https://img.shields.io/badge/PySide-6.6-blue)](https://doc.qt.io/qtforpython/index.html) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) -[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/) +[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/) ## 简介 @@ -21,7 +21,7 @@ - 在自己的机器上实际运行一下,仔细观察一下每个属性值的改变会怎样影响控件的外观行为,可能比静态的文档教程更有效 - 前身为 GitHub 热度最高的中文 PyQt5 教程 [PyQt-Practice](https://github.com/muziing/PyQt_practice),目前已有 ![PyQt-Practice Stars](https://img.shields.io/github/stars/muziing/PyQt_practice.svg) 个 Stars - 相比 [PyQt-Practice](https://github.com/muziing/PyQt_practice),改进了项目目录结构,增加了部分内容,更加清晰丰富 -- 使用最新的 Python 与 PySide 版本(目前为`3.10`与`6.3`) +- 使用最新的 Python 与 PySide 版本(目前为`3.11`与`6.6`) 希望本项目对你我的 Python-GUI 学习之旅有所帮助。 @@ -35,34 +35,34 @@ 1. Star 本仓库 2. 通过以下方法之一获取源码 - - 克隆仓库(推荐):`git clone https://github.com/muziing/PySide6-Code-Tutorial.git` - - 下载 zip: - - 查看 [Releases](https://github.com/muziing/PySide6-Code-Tutorial/releases) 界面,下载最新发布版(文件更小) + - 克隆仓库(推荐):`git clone https://github.com/muziing/PySide6-Code-Tutorial.git` + - 下载 zip: + - 查看 [Releases](https://github.com/muziing/PySide6-Code-Tutorial/releases) 界面,下载最新发布版(文件更小) 3. 进入项目目录 ### 二、配置虚拟环境与安装依赖 -**方式 A** :[Poetry](https://python-poetry.org/)(推荐) +**方式 A** :[venv](https://docs.python.org/zh-cn/3/library/venv.html)(简单易用,推荐) + +1. 确保 Python 版本与 [pyproject.toml](./pyproject.toml) 中要求的一致 +2. 创建虚拟环境 + - Windows: `python -m venv --upgrade-deps venv` + - Linux/macOS: `python3 -m venv --upgrade-deps venv` +3. 激活虚拟环境 + - Windows: `venv\Scripts\activate` + - Linux/macOS: `. venv/bin/activate` +4. 安装依赖:`pip install -r requirements.txt` + +**方式 B** :[Poetry](https://python-poetry.org/) 1. 确保 Python 版本与 [pyproject.toml](./pyproject.toml) 中要求的一致 2. 按[官方文档](https://python-poetry.org/docs/#installation)提示安装 Poetry 3. 创建虚拟环境:`poetry env use /full/path/to/python`(注意替换路径) -4. 安装依赖:`poetry install --no-dev` +4. 安装依赖:`poetry install --no-root --only main` 5. 使用该虚拟环境: `poetry shell`(或在 PyCharm 等 IDE 中配置) > 更多 Poetry 使用方法信息,请参阅其[官方文档](https://python-poetry.org/docs/)。 -**方式 B** :[venv](https://docs.python.org/zh-cn/3/library/venv.html)(简单易用) - -1. 确保 Python 版本与 [pyproject.toml](./pyproject.toml) 中要求的一致 -2. 创建虚拟环境 - - Windows: `python -m venv --upgrade-deps venv` - - Linux/macOS: `python3 -m venv --upgrade-deps venv` -3. 激活虚拟环境 - - Windows: `venv\Scripts\activate` - - Linux/macOS: `. venv/bin/activate` -4. 安装依赖:`pip install -r requirements.txt` - **方式 C** :其他包管理工具 1. 使用你喜欢的其他工具创建虚拟环境,如 [Pipenv](https://pipenv.pypa.io/)、[Conda](https://www.anaconda.com/) 等 @@ -86,10 +86,10 @@ | [01. HelloWorld - PySide 基本结构](./01-HelloWorld-基本结构) | 新手上路,PySide6 程序的基本结构 | | [02. QtCore - 非GUI的核心功能](./02-QtCore-非GUI的核心功能) | 元对象系统、「信号与槽」通信机制等 | | [03. QtWidgets - 常用控件](./03-QtWidgets-常用控件) | 按钮、输入框、文本编辑器、下拉菜单、滚动条等等常用控件的功能、用法 | -| [04. QtGui - 使用GUI功能扩展QtCore](./04-QtGui-使用GUI功能扩展QtCore) | 位图、字体、颜色、键盘快捷键等、事件 | +| [04. QtGui - 使用GUI功能扩展QtCore](./04-QtGui-使用GUI功能扩展QtCore) | 位图、字体、颜色、键盘快捷键等、事件(暂未完成) | | [05. QtWidgets - 进阶话题](./05-QtWidgets-进阶话题) | 布局管理器、QSS样式、主窗口控件等 | | [06. Model/View - 模型与视图、数据库](./06-ModelView-模型与视图、数据库) | 模型与视图、与数据库交互 | -| [07. Packaging - 打包、静态资源编译](./07-Packaging-打包与静态资源编译) | 将应用程序打包为 `exe`、将静态资源编译至二进制 `qrc` 文件 | +| [07. Packaging - 静态资源编译、打包](./07-Packaging-资源管理与打包) | 将应用程序打包为 `exe`、将静态资源编译至二进制 `qrc` 文件 | | …… | …… | ### 其他 @@ -97,7 +97,6 @@ | 目录/文件 | 描述 | |------------------------------------------------|-------------------| | [requirements.txt](./requirements.txt) | 依赖项,运行本项目必备 | -| [requirements_dev.txt](./requirements_dev.txt) | 开发依赖项,为本项目提交贡献时需要 | | [pyproject.toml](./pyproject.toml) | 项目配置文件 | | [poetry.lock](./poetry.lock) | Poetry 依赖项版本约束文件 | | [.gitignore](./.gitignore) | git 忽略提交规则 | @@ -140,6 +139,6 @@ PySide6 Code Tutorial 是一个开源项目,非常期待以及感谢你的参 ## 打赏 -本项目的[主要作者/维护者](https://muzing.top/about/)是一名还没有收入的在校学生,如果本项目对你有帮助,希望可以请他喝一杯冰可乐 :beer:。 +如果本项目对你有帮助,可以请[主要作者/维护者](https://muzing.top/about/)喝一杯冰可乐 :beer:。 -![微信收款码](./Resources/Images/muzing-WeChat-Collection-QRCode.png) +![微信赞赏码](./Resources/Images/muzing-WeChat-Collection.png) diff --git a/Resources/Images/muzing-WeChat-Collection.png b/Resources/Images/muzing-WeChat-Collection.png new file mode 100644 index 0000000..4f9f8de Binary files /dev/null and b/Resources/Images/muzing-WeChat-Collection.png differ diff --git a/Resources/Images/qrc-rcc/20210925093659593.gif b/Resources/Images/qrc-rcc/20210925093659593.gif new file mode 100644 index 0000000..478977b Binary files /dev/null and b/Resources/Images/qrc-rcc/20210925093659593.gif differ diff --git a/Resources/Images/qrc-rcc/20210925093839859.gif b/Resources/Images/qrc-rcc/20210925093839859.gif new file mode 100644 index 0000000..e3a3249 Binary files /dev/null and b/Resources/Images/qrc-rcc/20210925093839859.gif differ diff --git a/Resources/Images/qrc-rcc/20210925094012183.gif b/Resources/Images/qrc-rcc/20210925094012183.gif new file mode 100644 index 0000000..3a6202e Binary files /dev/null and b/Resources/Images/qrc-rcc/20210925094012183.gif differ diff --git a/Resources/Images/qrc-rcc/20210925102011356.gif b/Resources/Images/qrc-rcc/20210925102011356.gif new file mode 100644 index 0000000..73f973c Binary files /dev/null and b/Resources/Images/qrc-rcc/20210925102011356.gif differ diff --git a/Resources/Images/qrc-rcc/20210925181843.png b/Resources/Images/qrc-rcc/20210925181843.png new file mode 100644 index 0000000..0018251 Binary files /dev/null and b/Resources/Images/qrc-rcc/20210925181843.png differ diff --git a/Resources/Images/qrc-rcc/20221204112134.png b/Resources/Images/qrc-rcc/20221204112134.png new file mode 100644 index 0000000..fecf3ae Binary files /dev/null and b/Resources/Images/qrc-rcc/20221204112134.png differ diff --git a/Resources/Images/qrc-rcc/20221204114804.png b/Resources/Images/qrc-rcc/20221204114804.png new file mode 100644 index 0000000..d25d7e9 Binary files /dev/null and b/Resources/Images/qrc-rcc/20221204114804.png differ diff --git a/Resources/Images/qrc-rcc/20221206210735.png b/Resources/Images/qrc-rcc/20221206210735.png new file mode 100644 index 0000000..0414247 Binary files /dev/null and b/Resources/Images/qrc-rcc/20221206210735.png differ diff --git a/poetry.lock b/poetry.lock index 4572599..e650ddf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,37 +1,82 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + [[package]] name = "black" -version = "22.10.0" +version = "24.1.1" description = "The uncompromising code formatter." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "black-24.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c"}, + {file = "black-24.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445"}, + {file = "black-24.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a"}, + {file = "black-24.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4"}, + {file = "black-24.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7"}, + {file = "black-24.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8"}, + {file = "black-24.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161"}, + {file = "black-24.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d"}, + {file = "black-24.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8"}, + {file = "black-24.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e"}, + {file = "black-24.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6"}, + {file = "black-24.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b"}, + {file = "black-24.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62"}, + {file = "black-24.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5"}, + {file = "black-24.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6"}, + {file = "black-24.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717"}, + {file = "black-24.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9"}, + {file = "black-24.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024"}, + {file = "black-24.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2"}, + {file = "black-24.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac"}, + {file = "black-24.1.1-py3-none-any.whl", hash = "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168"}, + {file = "black-24.1.1.tar.gz", hash = "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b"}, +] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" +packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" [[package]] name = "click" -version = "8.1.3" +version = "8.1.7" description = "Composable command line interface toolkit" -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} @@ -39,300 +84,443 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" + +[[package]] +name = "distlib" +version = "0.3.8" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" + +[[package]] +name = "filelock" +version = "3.13.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" + +[[package]] +name = "identify" +version = "2.5.33" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, + {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, +] + +[package.extras] +license = ["ukkonen"] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" [[package]] name = "isort" -version = "5.10.1" +version = "5.13.2" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] [package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements_deprecated_finder = ["pip-api", "pipreqs"] +colors = ["colorama (>=0.4.6)"] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "mypy" -version = "0.982" +version = "1.8.0" description = "Optional static typing for Python" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, +] [package.dependencies] -mypy-extensions = ">=0.4.3" +mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = ">=3.10" +typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] reports = ["lxml"] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = "*" +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "pathspec" -version = "0.10.1" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +version = "4.2.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, +] [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] -name = "pyside6" -version = "6.3.2" -description = "Python bindings for the Qt cross-platform application and UI framework" -category = "main" +name = "pre-commit" +version = "3.6.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = "<3.11,>=3.6" +python-versions = ">=3.9" +files = [ + {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, + {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, +] [package.dependencies] -PySide6-Addons = "6.3.2" -PySide6-Essentials = "6.3.2" -shiboken6 = "6.3.2" +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] -name = "pyside6-addons" -version = "6.3.2" -description = "Python bindings for the Qt cross-platform application and UI framework (Addons)" -category = "main" +name = "pyside6-essentials" +version = "6.6.1" +description = "Python bindings for the Qt cross-platform application and UI framework (Essentials)" optional = false -python-versions = "<3.11,>=3.6" +python-versions = "<3.13,>=3.8" +files = [ + {file = "PySide6_Essentials-6.6.1-cp38-abi3-macosx_11_0_universal2.whl", hash = "sha256:0c8917b15236956957178a8c9854641b12b11dad79ba0caf26147119164c30cf"}, + {file = "PySide6_Essentials-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c7185616083eab6f42eaed598d97d49fac4f60ae2e7415194140d54f58c2b42c"}, + {file = "PySide6_Essentials-6.6.1-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:a383c3d60298392cfb621ec1a0cf24b4799321e6c5bbafc021d4cc8076ea1315"}, + {file = "PySide6_Essentials-6.6.1-cp38-abi3-win_amd64.whl", hash = "sha256:13da926e9e9ee3e26e3f66883a9d5e43726ddee70cdabddca02a07aa1ccf9484"}, +] [package.dependencies] -PySide6-Essentials = "6.3.2" -shiboken6 = "6.3.2" +shiboken6 = "6.6.1" [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] -name = "pyside6-essentials" -version = "6.3.2" -description = "Python bindings for the Qt cross-platform application and UI framework (Essentials)" -category = "main" +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" optional = false -python-versions = "<3.11,>=3.6" +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] -[package.dependencies] -shiboken6 = "6.3.2" +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" + +[[package]] +name = "setuptools" +version = "69.0.3" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "shiboken6" -version = "6.3.2" +version = "6.6.1" description = "Python/C++ bindings helper module" -category = "main" optional = false -python-versions = "<3.11,>=3.6" +python-versions = "<3.13,>=3.8" +files = [ + {file = "shiboken6-6.6.1-cp38-abi3-macosx_11_0_universal2.whl", hash = "sha256:d756fd1fa945b787e8eef142f2eb571da0b4c4dc2f2eec1a7c12a474a2cf84e4"}, + {file = "shiboken6-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:fb102e4bc210006f0cdd0ce38e1aaaaf792bd871f02a2b3f01d07922c5cf4c59"}, + {file = "shiboken6-6.6.1-cp38-abi3-manylinux_2_31_aarch64.whl", hash = "sha256:a605960e72af5eef915991cee7eef4cc72f5cabe63b9ae1a955ceb3d3b0a00b9"}, + {file = "shiboken6-6.6.1-cp38-abi3-win_amd64.whl", hash = "sha256:072c35c4fe46ec13b364d9dc47b055bb2277ee3aeaab18c23650280ec362f62a"}, +] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [[package]] name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.tuna.tsinghua.edu.cn/simple" +reference = "tsinghua_mirror" + +[[package]] +name = "virtualenv" +version = "20.25.0" +description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [package.source] type = "legacy" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -reference = "tsinghua" +reference = "tsinghua_mirror" [metadata] -lock-version = "1.1" -python-versions = ">=3.9,<3.11" -content-hash = "86afb4c6997c6c267e83a0b28cd1ecd237f2e10cc0e88d6a3315393ee7d375b7" - -[metadata.files] -black = [ - {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, - {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, - {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, - {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, - {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, - {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, - {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, - {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, - {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, - {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, - {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, - {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, - {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, - {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, - {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, - {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, - {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, - {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, - {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, - {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, - {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -mypy = [ - {file = "mypy-0.982-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5085e6f442003fa915aeb0a46d4da58128da69325d8213b4b35cc7054090aed5"}, - {file = "mypy-0.982-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:41fd1cf9bc0e1c19b9af13a6580ccb66c381a5ee2cf63ee5ebab747a4badeba3"}, - {file = "mypy-0.982-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f793e3dd95e166b66d50e7b63e69e58e88643d80a3dcc3bcd81368e0478b089c"}, - {file = "mypy-0.982-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86ebe67adf4d021b28c3f547da6aa2cce660b57f0432617af2cca932d4d378a6"}, - {file = "mypy-0.982-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:175f292f649a3af7082fe36620369ffc4661a71005aa9f8297ea473df5772046"}, - {file = "mypy-0.982-cp310-cp310-win_amd64.whl", hash = "sha256:8ee8c2472e96beb1045e9081de8e92f295b89ac10c4109afdf3a23ad6e644f3e"}, - {file = "mypy-0.982-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58f27ebafe726a8e5ccb58d896451dd9a662a511a3188ff6a8a6a919142ecc20"}, - {file = "mypy-0.982-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6af646bd46f10d53834a8e8983e130e47d8ab2d4b7a97363e35b24e1d588947"}, - {file = "mypy-0.982-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7aeaa763c7ab86d5b66ff27f68493d672e44c8099af636d433a7f3fa5596d40"}, - {file = "mypy-0.982-cp37-cp37m-win_amd64.whl", hash = "sha256:724d36be56444f569c20a629d1d4ee0cb0ad666078d59bb84f8f887952511ca1"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14d53cdd4cf93765aa747a7399f0961a365bcddf7855d9cef6306fa41de01c24"}, - {file = "mypy-0.982-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:26ae64555d480ad4b32a267d10cab7aec92ff44de35a7cd95b2b7cb8e64ebe3e"}, - {file = "mypy-0.982-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6389af3e204975d6658de4fb8ac16f58c14e1bacc6142fee86d1b5b26aa52bda"}, - {file = "mypy-0.982-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b35ce03a289480d6544aac85fa3674f493f323d80ea7226410ed065cd46f206"}, - {file = "mypy-0.982-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c6e564f035d25c99fd2b863e13049744d96bd1947e3d3d2f16f5828864506763"}, - {file = "mypy-0.982-cp38-cp38-win_amd64.whl", hash = "sha256:cebca7fd333f90b61b3ef7f217ff75ce2e287482206ef4a8b18f32b49927b1a2"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a705a93670c8b74769496280d2fe6cd59961506c64f329bb179970ff1d24f9f8"}, - {file = "mypy-0.982-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75838c649290d83a2b83a88288c1eb60fe7a05b36d46cbea9d22efc790002146"}, - {file = "mypy-0.982-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:91781eff1f3f2607519c8b0e8518aad8498af1419e8442d5d0afb108059881fc"}, - {file = "mypy-0.982-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaa97b9ddd1dd9901a22a879491dbb951b5dec75c3b90032e2baa7336777363b"}, - {file = "mypy-0.982-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a692a8e7d07abe5f4b2dd32d731812a0175626a90a223d4b58f10f458747dd8a"}, - {file = "mypy-0.982-cp39-cp39-win_amd64.whl", hash = "sha256:eb7a068e503be3543c4bd329c994103874fa543c1727ba5288393c21d912d795"}, - {file = "mypy-0.982-py3-none-any.whl", hash = "sha256:1021c241e8b6e1ca5a47e4d52601274ac078a89845cfde66c6d5f769819ffa1d"}, - {file = "mypy-0.982.tar.gz", hash = "sha256:85f7a343542dc8b1ed0a888cdd34dca56462654ef23aa673907305b260b3d746"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] -pyside6 = [ - {file = "PySide6-6.3.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4d47a1bac761f480fa06d93d0d9a72603eb6625f1e503288125caaff716e9e97"}, - {file = "PySide6-6.3.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e5730a80bc1ad61b05666e15e1db6d2554653c6651195c591bcbe73a84cae69d"}, - {file = "PySide6-6.3.2-cp36-abi3-win_amd64.whl", hash = "sha256:ac0dbe5b713402046e8c2c4474d4e1e001b75665628eef7f31d4fb0e966d5bbd"}, -] -pyside6-addons = [ - {file = "PySide6_Addons-6.3.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:13c2859c04d04430089db92831dc4cd45cfaf545b539ca34d38ad42b268a8c2f"}, - {file = "PySide6_Addons-6.3.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6bfdb6877ab3a500a5fdc0ca2a14286cc171a02ed69a069c1a2e4663212f65bb"}, - {file = "PySide6_Addons-6.3.2-cp36-abi3-win_amd64.whl", hash = "sha256:38af635b726dab72aa829cc64bdccc56f9f0353d1b79d51ed945a2570d0ae2e4"}, -] -pyside6-essentials = [ - {file = "PySide6_Essentials-6.3.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:67187a9d0f2659c2a4c8c622f3ea82ded737b16d0b7e096a26b2e418f92c5b65"}, - {file = "PySide6_Essentials-6.3.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a5d6528a0e7bcf4c7b892210f5ee34fdf2cb95ecddfafa1eb77509d924bcbbf1"}, - {file = "PySide6_Essentials-6.3.2-cp36-abi3-win_amd64.whl", hash = "sha256:944648e2bb9e423bd52d695aaaf7ea91d6f4663a71bca3a56fa10f5e7eb720c0"}, -] -shiboken6 = [ - {file = "shiboken6-6.3.2-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:4d14b7027885b4ded742d917b4c10d49c314572a5d1bcd33d8445cc6ffe7c183"}, - {file = "shiboken6-6.3.2-cp36-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e242361886679cde47c4cb367f2e3124274201ca8bf01049235861d032666320"}, - {file = "shiboken6-6.3.2-cp36-abi3-win_amd64.whl", hash = "sha256:b616f4f82ebac5080bc47b2c3f832f2b56dd3ad17e0ba71f985cee48a17ea8c7"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -typing-extensions = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, -] +lock-version = "2.0" +python-versions = ">=3.9,<3.13" +content-hash = "9a69db5a92317df6c62461f504fea9c49c52182ac8863256e91bfdbc9c17ccb9" diff --git a/pyproject.toml b/pyproject.toml index 0051796..154b49a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,20 +6,24 @@ authors = ["muzing "] license = "GPL-3.0" repository = "https://github.com/muziing/PySide6-Code-Tutorial" -# 使用清华pypi镜像 +[tool.poetry.urls] +"Bug Tracker" = "https://github.com/muziing/PySide6-Code-Tutorial/issues" + +# 使用清华 pypi 镜像 [[tool.poetry.source]] -name = "tsinghua" +name = "tsinghua_mirror" url = "https://pypi.tuna.tsinghua.edu.cn/simple" -default = true +priority = "default" [tool.poetry.dependencies] -python = ">=3.9,<3.11" -pyside6 = "^6.3.0" +python = ">=3.9,<3.13" +pyside6-essentials = "^6.2.0" -[tool.poetry.dev-dependencies] -black = "^22.10.0" -isort = "^5.10.0" -mypy = "^0.982" +[tool.poetry.group.dev.dependencies] +black = "^24.1.0" +isort = "^5.13.0" +mypy = "^1.8.0" +pre-commit = "^3.6.0" [build-system] requires = ["poetry-core>=1.0.0"] @@ -33,5 +37,5 @@ profile = "black" line_length = 100 [tool.mypy] -python_version = "3.10" +python_version = "3.11" warn_return_any = true diff --git a/requirements.txt b/requirements.txt index 1038ebf..52d53dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,4 @@ --index-url https://pypi.tuna.tsinghua.edu.cn/simple -pyside6-addons==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -pyside6-essentials==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -pyside6==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -shiboken6==6.3.2 ; python_version >= "3.9" and python_version < "3.11" +pyside6-essentials >= 6.2.0 ; python_version >= "3.9" and python_version < "3.13" +shiboken6 >= 6.2.0 ; python_version >= "3.9" and python_version < "3.13" diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 6c0e38c..0000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,16 +0,0 @@ ---index-url https://pypi.tuna.tsinghua.edu.cn/simple - -black==22.10.0 ; python_version >= "3.9" and python_version < "3.11" -click==8.1.3 ; python_version >= "3.9" and python_version < "3.11" -colorama==0.4.5 ; python_version >= "3.9" and python_version < "3.11" and platform_system == "Windows" -isort==5.10.1 ; python_version >= "3.9" and python_version < "3.11" -mypy-extensions==0.4.3 ; python_version >= "3.9" and python_version < "3.11" -mypy==0.982 ; python_version >= "3.9" and python_version < "3.11" -pathspec==0.10.1 ; python_version >= "3.9" and python_version < "3.11" -platformdirs==2.5.2 ; python_version >= "3.9" and python_version < "3.11" -pyside6-addons==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -pyside6-essentials==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -pyside6==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -shiboken6==6.3.2 ; python_version >= "3.9" and python_version < "3.11" -tomli==2.0.1 ; python_version >= "3.9" and python_version < "3.11" -typing-extensions==4.4.0 ; python_version >= "3.9" and python_version < "3.11"