注:本文示例都是从官方文档中找到的,有条件的可以去看一下。
基本结构
首先,我们看一下,Qt应用最简单的结构是什么样。
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hello World!")
label.show()
app.exec()
一行一行解释。
前两行是导入需要使用的包。这个后面再讲。
app = QApplication(sys.argv)
这行代码创建了一个QApplication类的实例。首先什么是QApplication?回答这个问题可能会比较复杂。我们先了解一下PySide6这个包的结构。
主要就是这三个模块。其中QtCore提供了Qt项目的基础机制,例如信号与槽等等。在QtCore基础上,QtGui提供了有关图形界面的基础操作,比如事件,2d或者3d的表现等等。最后才是真正我们看到的东西——QtWidgets,它包含了所有的组件。
而在上面的例子中,我们知道QApplication是从QtWidgets中导入的,因此它应该属于GUI的组件部分(QtGUI我认为是GUI的机制部分)。
但实际上QApplication并不会创造一个可视化的界面。你可以理解它为一个初始化的地基,它提供了很多初始化的能力,例如使用系统风格或者切换主题等等,详见官方文档QApplication
因此一个Qt的GUI应用都必须要实例一个QApplication,而构造函数中的参数sys.argv并不是必须的,关于sys.argv我看的这篇博客Python中的sys.argv是什么含义。简单的说就是用命令行启动的时候可以传参,实际上写成这两个也没问题。
app = QApplication()
#or
app = QApplication([])
然后是label = QLabel("Hello World!"); label.show();
实例了一个QLabel对象,然后show。哪些组件可以show哪些不能?show又是什么方法?关于这个我们需要了解其父类。
图中可以看到,QLabel是QWidget的子类,实际上绝大多数都是QWidget的子类,因此可以使用QWidget的show方法。
补充,关于什么是QWidget?我目前的理解是,Qt中实际上只有QWidget这一种容器,然后这个容器里又可以存放其他容器或组件,组件实际上也就是一种特殊的容器。
而show方法是创建一个界面的方法,例如我可以创建多个QLabel
,然后全部show,程序运行后就会出现多个界面,每个界面里面有一个label。如下图:
最后则是app.exec()
,也可以写成app.exec_()
。在Qt的应用中,实际上运行到这一步,上面创建的QLabel
才开始出现
在调试中,走到最后一步,还没有出现GUI界面。原理是,最后一行代码进入循环,直到所有的线程结束(我还不确定),程序结束。
一个更标准的代码结构
python支持面向对象,那我们必须投入面向对象的怀抱啊。
通常来说,一个应用是拥有多个界面类以及一个主函数。
先上示例:
"""PySide6 Active Qt Viewer example"""
import sys
from PySide6.QtAxContainer import QAxSelect, QAxWidget
from PySide6.QtGui import QAction
from PySide6.QtWidgets import (QApplication, QDialog,
QMainWindow, QMessageBox, QToolBar)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
toolBar = QToolBar()
self.addToolBar(toolBar)
fileMenu = self.menuBar().addMenu("&File")
loadAction = QAction("Load...", self, shortcut="Ctrl+L", triggered=self.load)
fileMenu.addAction(loadAction)
toolBar.addAction(loadAction)
exitAction = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close)
fileMenu.addAction(exitAction)
aboutMenu = self.menuBar().addMenu("&About")
aboutQtAct = QAction("About &Qt", self, triggered=qApp.aboutQt)
aboutMenu.addAction(aboutQtAct)
self.axWidget = QAxWidget()
self.setCentralWidget(self.axWidget)
def load(self):
axSelect = QAxSelect(self)
if axSelect.exec() == QDialog.Accepted:
clsid = axSelect.clsid()
if not self.axWidget.setControl(clsid):
QMessageBox.warning(self, "AxViewer", f"Unable to load {clsid}.")
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWin = MainWindow()
availableGeometry = mainWin.screen().availableGeometry()
mainWin.resize(availableGeometry.width() / 3, availableGeometry.height() / 2)
mainWin.show()
sys.exit(app.exec())
效果如下:
还是一步步来解读代码。
- 首先,创建了一个MainWindow类,我们上个示例中展示了两个label,但出现了两个页面,那我想放在一个界面里怎么办?那就需要容器。
QMainWindow
就是一个容器,我们看一下它的继承关系,就是一个QWidget
的子类。
然后这个QMainWindow
有啥用呢?其实就是内置了一些布局和属性。如图:
因而在上面的例子中,addToolBar()
和menuBar()
就不难理解。
不过有一个小细节是我之前在思考的,为什么添加工具栏用的是addToolBar()
而菜单栏是fileMenu = self.menuBar().addMenu("&File")
呢?
因为工具栏可以有零或多个,而菜单栏只有一个。
- 再看一下这条语句:
fileMenu = self.menuBar().addMenu("&File")
给菜单栏添加菜单项可以有三种方式传参,得到QMenu菜单项后,就可以给它添加下拉菜单里的QAction,如图:
关于QAction,其实看示例也明白它的用处了,最后一个参数trigger用来绑定事件,目前还没了解这个绑定事件的操作有没有用到信号/槽。需要注意的是,QAction属于QtGui包,不属于QtWidgets。
- 然后是QAxWidget,例子是在官网找的,目前这一块好像官网给的资料都不多,暂且不表,目前只知道这是一个插件支持ActiveX,应该是用来加载文件的。我后续有时间必定给他解决
- 最后是主函数调整窗口大小位置那一块的
QScreen
,该类一般用于获得屏幕属性,例如屏幕的大小角度颜色深度等等,而availableVirtualGeometry()
则是获得屏幕的可用尺寸,一般就是去除了任务栏的尺寸。resize()
顾名思义对住窗口改变长宽。