欢迎关注『OpenCV-PyQT项目实战 @ Youcans』系列,持续更新中
OpenCV-PyQT项目实战(1)安装与环境配置
OpenCV-PyQT项目实战(2)QtDesigner 和 PyUIC 快速入门
OpenCV-PyQT项目实战(3)信号与槽机制
OpenCV-PyQT项目实战(4)OpenCV 与PyQt的图像转换
OpenCV-PyQT项目实战(5)项目案例01图像模糊
OpenCV-PyQT项目实战(6)项目案例02滚动条应用
OpenCV-PyQT项目实战(6)项目案例02:滚动条应用
本节介绍两个 OpenCV-PyQt 项目案例,通过案例学习滚动条等调节输入控件。
1. 调节输入控件
1.1 输入控件
在 QtDesigner 左侧的 “WidgetBox” 工具栏中的"Input Widget" 组,设有多种不同类型的输入控件,例如:
文本输入控件:QlineEdit(单行输入)、QTextEdit(多行输入)、QPlainTextEdit(普通多行输入);
数字输入控件:QSpinBox(整型数据输入)、QDoubleSpinBox(浮点数据输入);
调节输入控件:QAbstractSpinBox(步长调节输入)、QDateEdit(日期输入)、QTimeEdit(时间输入)、QDateTimeEdit(日期和时间输入)。
用鼠标将工具栏中的输入控件拖拽到 QtDesigner 中间的图形界面编辑窗口,就可以在图像界面创建了一个按钮控件。
1.2 水平/垂直滚动条(QScrollBar)
PyQt 中提供了的滚动条组件 QScrollBar,包括水平滚动条(Horizontal Scroll Bar)和垂直滚动条(Vertical Scroll Bar)。
滚动条为当前位置提供视觉指示,用于访问当前不可见的文档或图像区域。滚动条有一个滑块,也可以用于用于调节整数值,但默认不显示数字。
QScrollBar的常用属性:
- minimum:最小值
- maximum:最大值
- singlestep:步距
- value:初始值
- sliderposition:位置,如果数字是从1开始且步距是1,则value和sliderposition是一致的。
- notchesVisible :是否设置刻度
- wrapping :是否刻度不留缺口
- notchTarget :设置刻度密度,即单位刻度所代表的大小
QScrollBar的常用方法:
- setMinimum(): 设置滚动条的最小值
- setMaximum(): 设置滚动条的最大值
- setSingleStep(): 设置滚动条的步长
- setValue(): 设置滚动条的值
- value(): 获得滚动条控件的值
QScrollBar可以发送的信号(即可以使用这些信号来触发槽函数):
- valueChanged: 当滑块的值发生改变时发射此信号,此信号是最常用的
- sliderPressed: 当用户按下滑块时发射此信号
- sliderMoved: 当用户拖动滑块时发射此信号
- sliderReleased: 当用户释放滑块时发射此信号
1.3 水平/垂直滑动槽(QSlider)
PyQt 中提供了的滑动槽组件 QSlider,包括水平滑动槽(Horizontal Slider)和垂直滑动槽(Vertical Slider)。
滑动槽组件展示了一个可以移动的滑块,它是控制有界值的部件,常用于调节整数大小。
QSlider的常用属性:
- minimum:最小值
- maximum:最大值
- singlestep:步距
- value:初始值
- sliderposition:位置,如果数字是从1开始且步距是1,则value和sliderposition是一致的。
- notchesVisible :是否设置刻度
- wrapping :是否刻度不留缺口
- notchTarget :设置刻度密度,即单位刻度所代表的大小
QSlider的常用方法:
- setMinimum(): 设置滑动槽的最小值
- setMaximum(): 设置滑动槽的最大值
- setSingleStep(): 设置滑动槽的递增步长
- setTickInterval():将刻度数放在凹槽上
- setValue(): 设置滑动槽的值
- value(): 获得滑动槽控件的值
QSlider可以发送的信号(即可以使用这些信号来触发槽函数):
- valueChanged: 当滑块的值发生改变时发射此信号,此信号是最常用的
- sliderPressed: 当用户按下滑块时发射此信号
- sliderMoved: 当用户拖动滑块时发射此信号
- sliderReleased: 当用户释放滑块时发射此信号
1.4 旋转调节盘(QDial)
QDial是一个圆表盘控件, 也称为旋转调节盘,可以用于处理整数或浮点数值。各种仪表仪盘都可以抽象成一个圆表盘控件,例如汽车仪表盘上的速度计。
QDial的常用属性:
- minimum:最小值
- maximum:最大值
- singlestep:步距
- value:初始值
- sliderposition:位置,如果数字是从1开始且步距是1,则value和sliderposition是一致的。
- notchesVisible :是否设置刻度
- wrapping :是否刻度不留缺口
- notchTarget :设置刻度密度,即单位刻度所代表的大小
QDial常用方法:
- setNotchesVisible(): 设置是否显示刻度
- notchesVisile(): 刻度可见返回True,不可见返回False
- setWrapping(): 设置是否回绕
- wrapping(): 如果回绕则返回True, 否则返回False
- setNotchTarget(): 设置刻度之间的目标刻度
- notchTarget(): 返回刻度间的目标宽度
- notchSize(): 当前刻度尺寸
1.5 其它输入调节控件
步长调节输入(QAbstractSpinBox)
QAbstractSpinBox 将所有步长调节器的通用的功能抽象出了一个父类,也可以直接实例化使用。QAbstractSpinBox包含了一个QLineEdit和两个QPushbutton,数据的更改可以通过点击按钮或使用键盘输入。
日期和时间输入(QDateEdit/QTimeEdit/QDateTimeEdit)
QDateEdit 控件用于编辑日期,QTimeEdit 控件用于编辑时间,QDateTimeEdit同时编辑日期时间的控件。可以使用键盘上的上下键头按钮来增加或减少日期、时间。
整型数字调节框(QSpinBox)
QSpinBox 是一个计数器控件,允许用户选择一个整数通过上下按键递增或者递减,也可以直接输入整数的数值。默认取值范围为 0-99,每次调节的步长为 1。
浮点数字调节框(QDoubleSpinBox)
QDoubleSpinBox 是浮点数据计数器控件,用于处理浮点数值。默认精度为 2位小数。
2. 项目实战:使用滑动槽(QSlider)调节模糊尺度
在uiDemo4.ui中,我们创建了按钮控件:“1 打开”、“2 灰度”、“3 模糊”、“4 帮助”、“5 退出”。其中模糊功能中,模糊尺度是在程序内部设置的。本例中,我们使用滑动槽(QSlider)调节模糊尺度。
2.1 使用 QtDesigner 开发 PyQt5 图形界面
使用 QtDesigner 开发 PyQt5 图形界面的基本步骤是:
(1)使用图形界面设计工具 QtDesigner 进行图形界面设计,生成 .ui 文件;
(2)使用 UI 转换工具 PyUIC 将 .ui 文件转换为 .py 文件;
(3)编写一个 Python 应用程序调用 .py 界面文件,就可以实现 Python 平台的 GUI 编程。
本例在 uiDemo4.ui 的基础上,添加一个滑动槽控件 QSlider:
从 QtDesigner 左侧控件栏的 “Input Widgets” 中选择 滑动槽控件 QSlider,移动鼠标将滑动槽 QSlider拖动到新建图形窗口内的任意位置,就在图形窗口位置生成了一个 QSlider 对象。
- 鼠标左键选中图形窗口中的这个 QSlider滑动槽对象,拖动鼠标可以调整控件的位置。
- 鼠标选中 QSlider滑动槽对象,可以在右侧的 “属性编辑器” 内对对象的属性进行编辑和修改,例如:
- 将 QSlider 对象的高度修改为 80,宽度修改为 40;
- 设置QSlider 对象的最小值minimum=1、最大值maximum=64和步长singleStep=1。
类似地,添加一个整型数字调节框(QSpinBox)控件。
于是,我们就完成了本项目的图形界面设计,将其保存为 uiDemo5.ui文件。
在 PyCharm中,使用 PyUIC 将选中的 uiDemo5.ui 文件转换为 .py 文件,就得到了 uiDemo5.py 文件。
2.2. 项目主程序的开发
2.2.1 getHorizontalSliderValue 槽函数
getHorizontalSliderValue 槽函数,由valueChanged信号触发。
def getHorizontalSliderValue(self):
self.sigma = max(self.horizontalSlider.value(),3) # 修改模糊尺度
ksize = (self.sigma, self.sigma) # 高斯滤波器核的尺寸
print("HorizontalSlider=", self.sigma)
2.2.2 getSpinBoxValue槽函数
getSpinBoxValue槽函数,由valueChanged信号触发。
def getSpinBoxValue(self):
self.sigma = self.spinBox.value() # 修改模糊尺度
print("SpinBoxValue=", self.sigma)
ksize = (self.sigma, self.sigma) # 高斯滤波器核的尺寸
blur = cv.GaussianBlur(self.img1, ksize, 0) # sigma 由 ksize 计算
self.refreshShow(blur, self.label_2) # 刷新显示
2.2.3 信号与槽的连接
# 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
# self.pushButton_1.clicked.connect(self.openSlot) # 点击 pushButton_1 触发
self.pushButton_1.clicked.connect(self.click_pushButton_1) # 点击 pushButton_1 触发
# self.pushButton_2.clicked.connect(self.click_pushButton_2) # 点击 pushButton_2 触发
self.pushButton_3.clicked.connect(self.click_pushButton_3) # 点击 pushButton_3 触发
# self.pushButton_4.clicked.connect(self.trigger_actHelp) # 点击 pushButton_4 触发
self.pushButton_5.clicked.connect(self.close) # 点击 pushButton_5 关闭窗口
self.spinBox.valueChanged.connect(self.getSpinBoxValue) # spinBox控件valueChanged信号与getSpinBoxValue槽函数关联
self.horizontalSlider.valueChanged.connect(self.getHorizontalSliderValue) # horizontalSlider控件valueChanged信号触发
2.3 主程序
# OpenCVPyqt06.py
# Demo06 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-03
if __name__ == '__main__':
app = QApplication(sys.argv) # 在 QApplication 方法中使用,创建应用程序对象
myWin = MyMainWindow() # 实例化 MyMainWindow 类,创建主窗口
myWin.show() # 在桌面显示控件 myWin
sys.exit(app.exec_()) # 结束进程,退出程序
2.4. 项目例程的测试
测试应用程序 OpenCVPyqt06.py的各项功能:
(1)运行 OpenCVPyqt06,弹出程序窗口,自动加载图像 Fig0301。
(2)点击 “1 打开”,运行 click_pushButton_1 槽函数。选择目录路径和图像文件,读取图像并在窗口显示彩色图像。
(3)点击 "3 模糊"按钮,运行 click_pushButton_3 槽函数。在窗口右侧显示高斯模糊处理的彩色图像。
(4)调节滑动槽或整型数字调节框,用户设置模糊尺度,则在 Label_2 刷新模糊图像。
(5)点击 "5 退出"按钮,关闭窗口。
3. 项目实战:调节图像亮度和对比度
本项目模拟 PhotoShop 与 AcdSee 中的图像亮度和对比度方法,通过手动调节阴影、中间调和高光参数设置,调节图像的亮度和对比度。相关方法的原理和OpenCV算法实现,详见:【OpenCV 例程300篇】206. Photoshop 色阶调整算法。
3.1 使用 QtDesigner 开发 PyQt5 图形界面
本例在 uiDemo4.ui 的基础上,添加滑动槽控件 QSlider:
从 QtDesigner 左侧控件栏的 “Input Widgets” 中选择 滑动槽控件 QSlider,移动鼠标将滑动槽 QSlider拖动到新建图形窗口内的任意位置,就在图形窗口位置生成了一个 QSlider 对象。
- 鼠标左键选中图形窗口中的这个 QSlider滑动槽对象,拖动鼠标可以调整控件的位置。
- 鼠标选中 QSlider滑动槽对象,可以在右侧的 “属性编辑器” 内对对象的属性进行编辑和修改,例如:
- 将 QSlider 对象的高度修改为 80,宽度修改为 40;
- 设置QSlider 对象的最小值minimum=1、最大值maximum=64和步长singleStep=1。
类似地,添加一个整型数字调节框(QSpinBox)控件。
于是,我们就完成了本项目的图形界面设计,将其保存为 uiDemo7.ui文件。
在 PyCharm中,使用 PyUIC 将选中的 uiDemo7.ui 文件转换为 .py 文件,就得到了 uiDemo7.py 文件。
3.2. 项目主程序的开发
3.2.1 getHorizontalSliderValue 槽函数
getHorizontalSliderValue 槽函数,由valueChanged信号触发。
def getHorizontalSliderValue_1(self): # 最小值
slideValue1 = self.horizontalSlider_1.value()
self.spinBox_1.setValue(slideValue1) # 同步修改
self.spinBox_3.setMinimum(slideValue1) # 关联修改
self.horizontalSlider_3.setMinimum(slideValue1) # 关联修改
print("HorizontalSliderValue_1 = ", slideValue1)
def getHorizontalSliderValue_2(self):
slideValue2 = self.horizontalSlider_2.value()
self.spinBox_2.setValue(slideValue2)
print("HorizontalSliderValue_2 = ", slideValue2)
def getHorizontalSliderValue_3(self):
slideValue3 = self.horizontalSlider_3.value()
self.spinBox_3.setValue(slideValue3) # 同步修改
self.spinBox_1.setMaximum(slideValue3) # 关联修改
self.horizontalSlider_1.setMaximum(slideValue3) # 关联修改
print("HorizontalSliderValue_3 = ", slideValue3)
3.2.2 getSpinBoxValue槽函数
getSpinBoxValue槽函数,由valueChanged信号触发。
def getSpinBoxValue_1(self):
spinBoxValue1 = self.spinBox_1.value()
self.horizontalSlider_1.setValue(spinBoxValue1)
self.spinBox_3.setMinimum(spinBoxValue1) # 关联修改
self.horizontalSlider_3.setMinimum(spinBoxValue1) # 关联修改
print("SpinBoxValue_1 = ", spinBoxValue1)
def getSpinBoxValue_2(self):
spinBoxValue2 = self.spinBox_2.value()
self.horizontalSlider_2.setValue(spinBoxValue2)
print("SpinBoxValue_2 = ", spinBoxValue2)
def getSpinBoxValue_3(self):
spinBoxValue3 = self.spinBox_3.value()
self.horizontalSlider_3.setValue(spinBoxValue
3.2.3 信号与槽的连接
# 菜单栏
self.actionOpen.triggered.connect(self.openSlot) # 连接并执行 openSlot 子程序
self.actionSave.triggered.connect(self.saveSlot) # 连接并执行 saveSlot 子程序
self.actionHelp.triggered.connect(self.trigger_actHelp) # 连接并执行 trigger_actHelp 子程序
self.actionQuit.triggered.connect(self.close) # 连接并执行 trigger_actHelp 子程序
# 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
self.pushButton_1.clicked.connect(self.click_pushButton_1) # 按钮触发:导入图像
self.pushButton_3.clicked.connect(self.click_pushButton_3) # # 按钮触发:调整色阶
self.pushButton_5.clicked.connect(self.close) # 点击 # 按钮触发:关闭
self.horizontalSlider_1.valueChanged.connect(self.getHorizontalSliderValue_1) # horizontalSlider控件valueChanged信号触发
self.horizontalSlider_2.valueChanged.connect(self.getHorizontalSliderValue_2)
self.horizontalSlider_3.valueChanged.connect(self.getHorizontalSliderValue_3)
self.spinBox_1.valueChanged.connect(self.getSpinBoxValue_1) # spinBox控件valueChanged信号与getSpinBoxValue槽函数关联
self.spinBox_2.valueChanged.connect(self.getSpinBoxValue_2)
self.spinBox_3.valueChanged.connect(self.getSpinBoxValue_3)
3.3 完整例程及运行结果
# OpenCVPyqt07.py
# Demo07 of GUI by PyQt5
# Copyright 2023 Youcans, XUPT
# Crated:2023-02-08
import sys
import cv2 as cv
import numpy as np
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from uiDemo7 import Ui_MainWindow # 导入 uiDemo5.py 中的 Ui_MainWindow 界面类
class MyMainWindow(QMainWindow, Ui_MainWindow): # 继承 QMainWindow 类和 Ui_MainWindow 界面类
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent) # 初始化父类
self.setupUi(self) # 继承 Ui_MainWindow 界面类
self.img1 = np.ndarray(()) # 初始化图像 ndarry,用于存储图像
# self.img2 = np.ndarray(())
# 菜单栏
self.actionOpen.triggered.connect(self.openSlot) # 连接并执行 openSlot 子程序
self.actionSave.triggered.connect(self.saveSlot) # 连接并执行 saveSlot 子程序
self.actionHelp.triggered.connect(self.trigger_actHelp) # 连接并执行 trigger_actHelp 子程序
self.actionQuit.triggered.connect(self.close) # 连接并执行 trigger_actHelp 子程序
# 通过 connect 建立信号/槽连接,点击按钮事件发射 triggered 信号,执行相应的子程序 click_pushButton
self.pushButton_1.clicked.connect(self.click_pushButton_1) # 按钮触发:导入图像
self.pushButton_3.clicked.connect(self.click_pushButton_3) # # 按钮触发:调整色阶
self.pushButton_5.clicked.connect(self.close) # 点击 # 按钮触发:关闭
self.horizontalSlider_1.valueChanged.connect(self.getHorizontalSliderValue_1) # horizontalSlider控件valueChanged信号触发
self.horizontalSlider_2.valueChanged.connect(self.getHorizontalSliderValue_2)
self.horizontalSlider_3.valueChanged.connect(self.getHorizontalSliderValue_3)
self.spinBox_1.valueChanged.connect(self.getSpinBoxValue_1) # spinBox控件valueChanged信号与getSpinBoxValue槽函数关联
self.spinBox_2.valueChanged.connect(self.getSpinBoxValue_2)
self.spinBox_3.valueChanged.connect(self.getSpinBoxValue_3)
# 初始化
self.img1 = cv.imread("../images/Fig0301.png") # OpenCV 读取图像
self.refreshShow(self.img1, self.label_1)
self.refreshShow(self.img1, self.label_2)
return
def getHorizontalSliderValue_1(self): # 最小值
slideValue1 = self.horizontalSlider_1.value()
self.spinBox_1.setValue(slideValue1) # 同步修改
self.spinBox_3.setMinimum(slideValue1) # 关联修改
self.horizontalSlider_3.setMinimum(slideValue1) # 关联修改
print("HorizontalSliderValue_1 = ", slideValue1)
def getHorizontalSliderValue_2(self):
slideValue2 = self.horizontalSlider_2.value()
self.spinBox_2.setValue(slideValue2)
print("HorizontalSliderValue_2 = ", slideValue2)
def getHorizontalSliderValue_3(self):
slideValue3 = self.horizontalSlider_3.value()
self.spinBox_3.setValue(slideValue3) # 同步修改
self.spinBox_1.setMaximum(slideValue3) # 关联修改
self.horizontalSlider_1.setMaximum(slideValue3) # 关联修改
print("HorizontalSliderValue_3 = ", slideValue3)
def getSpinBoxValue_1(self):
spinBoxValue1 = self.spinBox_1.value()
self.horizontalSlider_1.setValue(spinBoxValue1)
self.spinBox_3.setMinimum(spinBoxValue1) # 关联修改
self.horizontalSlider_3.setMinimum(spinBoxValue1) # 关联修改
print("SpinBoxValue_1 = ", spinBoxValue1)
def getSpinBoxValue_2(self):
spinBoxValue2 = self.spinBox_2.value()
self.horizontalSlider_2.setValue(spinBoxValue2)
print("SpinBoxValue_2 = ", spinBoxValue2)
def getSpinBoxValue_3(self):
spinBoxValue3 = self.spinBox_3.value()
self.horizontalSlider_3.setValue(spinBoxValue3)
print("SpinBoxValue_3 = ", spinBoxValue3)
def click_pushButton_1(self): # 点击 pushButton_1 触发
self.img1 = self.openSlot() # 读取图像
print("click_pushButton_1", self.img1.shape)
self.refreshShow(self.img1, self.label_1) # 刷新显示
return
def click_pushButton_2(self): # 点击 pushButton_2 触发
print("pushButton_2")
self.img2 = cv.cvtColor(self.img1, cv.COLOR_BGR2GRAY) # 图片格式转换:BGR -> Gray
self.refreshShow(self.img2, self.label_2) # 刷新显示
return
def click_pushButton_3(self): # 点击 pushButton_3 触发 调整色阶
print("pushButton_3")
Sin = self.horizontalSlider_1.value()
Mt = self.horizontalSlider_2.value()
Hin = self.horizontalSlider_3.value()
Sin = min(max(Sin, 0), Hin - 2) # Sin, 黑场阈值, 0<=Sin<Hin
Hin = min(Hin, 255) # Hin, 白场阈值, Sin<Hin<=255
Mt = min(max(Mt, 0.01), 9.99) # Mt, 灰场调节值, 0.01~9.99
Sout = 0#min(max(Sout, 0), Hout - 2) # Sout, 输出黑场阈值, 0<=Sout<Hout
Hout = 255#min(Hout, 255) # Hout, 输出白场阈值, Sout<Hout<=255
print("Sin={},Hin={},Mt={}".format(Sin, Hin, Mt))
difIn = Hin - Sin
difOut = Hout - Sout
table = np.zeros(256, np.uint8)
for i in range(256):
V1 = min(max(255 * (i - Sin) / difIn, 0), 255) # 输入动态线性拉伸
V2 = 255 * np.power(V1 / 255, 1 / Mt) # 灰场伽马调节
table[i] = min(max(Sout + difOut * V2 / 255, 0), 255) # 输出线性拉伸
imgTone = cv.LUT(self.img1, table)
self.refreshShow(imgTone, self.label_2) # 刷新显示
return
def refreshShow(self, img, label):
print(img.shape, label)
qImg = self.cvToQImage(img) # OpenCV 转为 PyQt 图像格式
label.setPixmap((QPixmap.fromImage(qImg))) # 加载 PyQt 图像
return
def openSlot(self, flag=1): # 读取图像文件
# OpenCV 读取图像文件
fileName, _ = QFileDialog.getOpenFileName(self, "Open Image", "../images/", "*.png *.jpg *.tif")
if flag==0 or flag=="gray":
img = cv.imread(fileName, cv.IMREAD_GRAYSCALE) # 读取灰度图像
else:
img = cv.imread(fileName, cv.IMREAD_COLOR) # 读取彩色图像
print(fileName, img.shape)
return img
def saveSlot(self): # 保存图像文件
# 选择存储文件 dialog
fileName, tmp = QFileDialog.getSaveFileName(self, "Save Image", "../images/", '*.png; *.jpg; *.tif')
if self.img1.size == 1:
return
# OpenCV 写入图像文件
ret = cv.imwrite(fileName, self.img1)
if ret:
print(fileName, self.img.shape)
return
def cvToQImage(self, image):
# 8-bits unsigned, NO. OF CHANNELS=1
if image.dtype == np.uint8:
channels = 1 if len(image.shape) == 2 else image.shape[2]
if channels == 3: # CV_8UC3
# Create QImage with same dimensions as input Mat
qImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_RGB888)
return qImg.rgbSwapped()
elif channels == 1:
# Create QImage with same dimensions as input Mat
qImg = QImage(image, image.shape[1], image.shape[0], image.strides[0], QImage.Format_Indexed8)
return qImg
else:
QtCore.qDebug("ERROR: numpy.ndarray could not be converted to QImage. Channels = %d" % image.shape[2])
return QImage()
def qPixmapToCV(self, qPixmap): # PyQt图像 转换为 OpenCV图像
qImg = qPixmap.toImage() # QPixmap 转换为 QImage
shape = (qImg.height(), qImg.bytesPerLine() * 8 // qImg.depth())
shape += (4,)
ptr = qImg.bits()
ptr.setsize(qImg.byteCount())
image = np.array(ptr, dtype=np.uint8).reshape(shape) # 定义 OpenCV 图像
image = image[..., :3]
return image
def trigger_actHelp(self): # 动作 actHelp 触发
QMessageBox.about(self, "About",
"""数字图像处理工具箱 v1.0\nCopyright YouCans, XUPT 2023""")
return
if __name__ == '__main__':
app = QApplication(sys.argv) # 在 QApplication 方法中使用,创建应用程序对象
myWin = MyMainWindow() # 实例化 MyMainWindow 类,创建主窗口
myWin.show() # 在桌面显示控件 myWin
sys.exit(app.exec_()) # 结束进程,退出程序
运行结果:
【本节完】
版权声明:
Copyright 2023 youcans, XUPT
Crated:2023-2-8