用代码定义界面
用过java
的swing
来设计界面的朋友对这种方式一定不陌生,通过函数(方法)、类或模块(包)来定义界面,并将界面与要执行的函数(方法)绑定。
用函数定义界面
通过一个函数定义界面,如setupUI()
函数,定义界面中的各个控件。开发时可参照Qt的PySide6官方文档,例如程序中关于PySide6.QtCore.Qt
的相关描述。
from functools import partial
import sys
import PySide6.QtCore
from PySide6.QtWidgets import QApplication,QWidget,QLabel,QPushButton,QMessageBox
def showInfo(window):
QMessageBox.information(window, "提示信息", "这是用函数定义的界面。")
def setupUi(window): #形参window是一个窗口实例对象
window.setWindowTitle('用函数定义界面') #设置窗口标题
window.resize(300, 150) #设置窗口尺寸
label = QLabel(window) #在窗口上创建标签
label.setText('使用函数定义界面中的控件!')
label.setGeometry(80, 50, 150, 20) #设置标签在窗口中的位置和标签的宽度和高度
dlgButton = QPushButton(window) #创建一个弹窗按钮
dlgButton.setText("弹 框") #定义按钮文字
dlgButton.setGeometry(80, 100, 50, 20) #设置按钮在窗口中的位置(x, y坐标)和宽度、高度
dlgButton.clicked.connect(partial(showInfo, window)) #关联按钮事件,使用偏函数(functools.partial)传参
# dlgButton.clicked.connect(lambda: showInfo(window)) #关联按钮事件,使用lambda表达式传参
button = QPushButton(window) #在窗口上创建按钮
button.setText("关 闭")
button.setGeometry(170, 100, 50, 20) #设置按钮在窗口中的位置和按钮的宽度和高度
button.clicked.connect(window.close) #按钮事件与窗口事件的关联
if __name__ == '__main__':
app = QApplication(sys.argv)
myWindow = QWidget()
myWindow.setWindowFlags(myWindow.windowFlags() & ~PySide6.QtCore.Qt.WindowMaximizeButtonHint
| PySide6.QtCore.Qt.WindowCloseButtonHint) #禁用最大化按钮
setupUi(myWindow) #调用setupUi()函数,并把窗口作为实参传递给setupUi()函数
myWindow.show()
sys.exit(app.exec())
用类定义界面
通过一个类来定义窗体界面,控件是类的属性,setupUI()
则作为其中一个函数(实例方法)存在。
实例方法(instance method)、类方法(class method)与静态方法(static method)
实例方法:没有前置装饰器,其第一个参数应该是
self
,引用对象本身;
类方法:前置装饰器为
@classmethod
,其第一个参数应该是cls
(或者其它,只要不是保留字class
就行),引用类本身;
静态方法:前置装饰器为
@staticmethod
,其第一个参数不能是对象或类。
import sys
from PySide6.QtWidgets import QApplication,QWidget,QLabel,QPushButton, QMessageBox
class MyUi(): #定义MyUi类
def setupUi(self, window): # 定义方法,形参window是一个窗口实例对象
window.setWindowTitle('用类定义界面')
window.resize(300, 150)
self.label = QLabel(window) # 在窗口上创建标签
self.label.setText('使用类定义界面中的控件!')
self.label.setGeometry(80, 50, 150, 20)
self.dlgButton = QPushButton(window) #创建一个弹窗按钮
self.dlgButton.setText("弹 框") #定义按钮文字
self.dlgButton.setGeometry(80, 100, 50, 20) #设置按钮在窗口中的位置(x, y坐标)和宽度、高度
self.button = QPushButton(window) # 在窗口上创建按钮
self.button.setText("关 闭")
self.button.setGeometry(170, 100, 50, 20)
#self.button.clicked.connect(window.close)
def showInfo(self, window):
QMessageBox.information(window, "提示信息", "这是用类定义的界面。")
if __name__ == '__main__':
app = QApplication(sys.argv)
myWindow = QWidget()
ui = MyUi() # 用MyUi类创建实例ui
ui.setupUi(myWindow) # 调用ui的方法setupUi(),并以窗口实例对象作为实参
ui.button.setText("Close") # 重新设置按钮上显示的文字
ui.button.clicked.connect(myWindow.close) # 窗口上的按钮事件与窗口事件关联
ui.dlgButton.clicked.connect(lambda: ui.showInfo(myWindow)) # 与showInfo方法关联,采用lambda表达式传参
myWindow.show()
sys.exit(app.exec())
用模块定义界面
显然,对于界面设计,我们往往需要多种的控件,那么,这时候就需要采用模块的方式定义界面,举个例子,from PySide6.QtWidgets import QApplication,QWidget,QLabel,QPushButton, QMessageBox
就是引用PySide的QtWidgets
模块来定义一个界面。我们可以将上述的的MyUI
类作为一个模块中的类引用。
我们把`MyUI`类定义到`my_ui.py`文件中:
from PySide6.QtWidgets import QApplication,QWidget,QLabel,QPushButton, QMessageBox
class MyUi(): # 定义MyUi类,对于python 3,类默认继承object,对于python 2,若需要类继承object,则要显式声明,即MyUI(object)
def setupUi(self, window): # 定义方法,形参window是一个窗口实例对象
window.setWindowTitle('用模块定义界面')
window.resize(300, 150)
self.label = QLabel(window) # 在窗口上创建标签
self.label.setText('使用模块定义界面中的控件!')
self.label.setGeometry(80, 50, 150, 20)
self.dlgButton = QPushButton(window) # 创建一个弹窗按钮
self.dlgButton.setText("弹 框") # 定义按钮文字
self.dlgButton.setGeometry(80, 100, 50, 20) # 设置按钮在窗口中的位置(x, y坐标)和宽度、高度
self.button = QPushButton(window) # 在窗口上创建按钮
self.button.setText("关 闭")
self.button.setGeometry(170, 100, 50, 20)
def showInfo(self, window):
QMessageBox.information(window, "提示信息", "这是用模块定义的界面。")
值得注意的是,python的版本会影响到类继承关系和模块定义的方式方法。以python 3
为例,类默认继承自object
,但对于python 2
,若要求类继承object
对象,需要在类中显式继承,如:
from PySide6.QtWidgets import QApplication,QWidget,QLabel,QPushButton, QMessageBox
class MyUi(object): # 定义MyUi类
def setupUi(self, window): # 定义方法,形参window是一个窗口实例对象
window.setWindowTitle('用模块定义界面')
window.resize(300, 150)
self.label = QLabel(window) # 在窗口上创建标签
self.label.setText('使用模块定义界面中的控件!')
self.label.setGeometry(80, 50, 150, 20)
self.dlgButton = QPushButton(window) # 创建一个弹窗按钮
self.dlgButton.setText("弹 框") # 定义按钮文字
self.dlgButton.setGeometry(80, 100, 50, 20) # 设置按钮在窗口中的位置(x, y坐标)和宽度、高度
self.button = QPushButton(window) # 在窗口上创建按钮
self.button.setText("关 闭")
self.button.setGeometry(170, 100, 50, 20)
def showInfo(self, window):
QMessageBox.information(window, "提示信息", "这是用模块定义的界面。")
为了使Python
程序更具伸缩性,可将模块组织成文件和模块层次,这就是包(package
)。包就是含有.py
文件的子目录,可以有多个层级。而对于python 3.3
之前的版本,要将目录识别成包,还需要加一个名为__init__.py
的文件,该文件可以为空。
接下来,我们调用这个自定义类:
import sys
from PySide6.QtWidgets import QApplication, QWidget
from my_ui import MyUi # 导入my_ui.py文件中的MyUi类
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = QWidget()
ui = MyUi() # 用MyUi类创建实例ui
ui.setupUi(myWindow) # 调用ui的方法setupUi(),并以窗口实例作为实参
ui.button.setText("Close") # 重新设置按钮上显示的文字
ui.button.clicked.connect(myWindow.close) # 窗口上的按钮事件与窗口事件关联
ui.dlgButton.clicked.connect(lambda: ui.showInfo(myWindow))
myWindow.show()
sys.exit(app.exec())
运行效果如下:
界面与逻辑分离
与Web的前后端分离类似,定义界面的代码可以作为界面代码,实现控件动作的代码称为逻辑或业务代码。我们也可以采用函数、类的继承等方式将它们分离。
- 用函数将界面代码和业务代码分离
import sys
from PySide6.QtWidgets import QApplication, QWidget
from my_ui import MyUi # 导入my_ui.py文件中的MyUi类
def myWidget(parent = None):
widget = QWidget(parent) # 创建QWidget类的对象,调用QWidget类的__init__()函数
ui = MyUi() # 实例化myUi.py文件中的MyUi类
ui.setupUi(widget) # 调用MyUi类的setupUi(),以widget为实参传递给形参window
ui.button.setText("Close") # 重新设置按钮上显示的文字
ui.button.clicked.connect(widget.close) # 窗口上的按钮事件与窗口事件关联
ui.dlgButton.clicked.connect(lambda: ui.showInfo(widget))
return widget # 函数的返回值是窗口实例对象
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = myWidget() # 调用myWidget()函数,返回值是窗口实例对象
myWindow.show()
sys.exit(app.exec())
- 用类的单继承方式实现界面代码和业务代码的分离
import sys
from PySide6.QtWidgets import QApplication, QWidget
from my_ui import MyUi # 导入my_ui.py文件中的MyUi类
class MyWidget(QWidget): # 创建MyWindget类,父类是QWidget
def __init__(self,parent = None):
super().__init__(parent) # 初始化父类QWidget,self将是QWidget的窗口对象
ui = MyUi() # 实例化myUi.py文件中的MyUi类
ui.setupUi(self) # 调用MyUi的setupUi(),以self为实参传递给形参window
ui.button.setText("Close") # 重新设置按钮的显示文字
ui.button.clicked.connect(self.close) # 窗口上的按钮事件与窗口事件关联
ui.dlgButton.clicked.connect(lambda: ui.showInfo(self))
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = MyWidget() # 用MyWidget类创建窗口对象myWindow
myWindow.show()
sys.exit(app.exec())
- 用类的多重继承方式实现界面代码和义务代码的分离
import sys
from PySide6.QtWidgets import QApplication, QWidget
from my_ui import MyUi # 从my_ui.py文件中导入MyUi类
class MyWidget(QWidget,MyUi): # 创建MyWindget类,父类是QWidget和MyUi
def __init__(self,parent = None):
super().__init__(parent) # 初始化父类QWidget,self是QWidget的窗口对象
self.setupUi(self) # 调用MyUi的setupUi(),以self为实参传递给形参window
self.button.setText("Close") # 重新设置按钮的显示文字
self.button.clicked.connect(self.close) # 窗口上的按钮事件与窗口事件关联
self.dlgButton.clicked.connect(lambda: self.showInfo(self))
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = MyWidget() # 用MyWidget类创建窗口对象myWindow
myWindow.show()
sys.exit(app.exec())