杨景志 发表于 2024-3-19 19:39:58

PyQt5 GUI编程

一.PyQt5简介

PyQt5是一个用于创建图形用户界面(GUI)应用程序的跨平台工具集,它将Qt库(广泛用于C++编程语言中创建丰富的GUI应用程序)的功能包装给Python使用者。PyQt5是由Riverbank Computing开发的,并且可以在所有主流操作系统上运行,包含Windows、macOS和Linux。
PyQt5包括了超过620个类和6000个函数和方法。这个框架支持包括SQL数据库、线程、Unicode、正则表达式、网络编程等高级功能。除了GUI功能外,PyQt5还允许用户访问Qt的模型/视图架构和QML(Qt Modeling Language),这是一种专门为创建动态和自定义用户界面而设计的语言。
二.环境搭建

1.终端使用pip安装PyQt5库
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt52.如果出现Could not build wheels for PyQt5_sip, which is required to install pyproject.toml-based projects报错信息
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240220175827960-1140375394.png
 3.先安装 Visual Studio 后再安装PyQt5即可,终端执行如下指令
wget https://aka.ms/vs/17/release/vs_BuildTools.exe -o vs_BuildTools.exe ; cmd /c vs_BuildTools.exe勾选C++/CLI后安装就行
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240220180139514-1112466004.png
三.基本用法

1.PyQt5常见的模块

QApplication这个类管理GUI应用程序的控制流和主要设置,并且是每个PyQt5应用程序中必须有的部分QWidget所有用户界面对象的基类。当你想创建一个自定义的窗口时,你会使用或者继承这个类QLabel用于展示文本或图片的类QtCore 其他模块使用的核心非 GUI 类QAction用于处理菜单栏、工具栏或快捷键等的动作。QtSql使用 SQL 进行数据库集成的类QtXml处理 XML 的类QSlider滑动条,让用户通过滑动选择一个数值。 
2.一个简单的窗口创建

import sysfrom PyQt5.QtCore import *from PyQt5.QtGui import *from PyQt5.QtWidgets import QWidget, QLabel, QMessageBox, QApplicationdef windows():    # 创建一个 QApplication 类的应用程序对象    app = QApplication(sys.argv)    # 基于QWidget类声明窗口    w = QWidget()    # 添加一个QLabel对象,并将标签添加“helloworld”文本。    b = QLabel(w)    b.setText("Hello World!")    # 设置文本控件在窗口中的位置(x,y)    b.move(50, 50)    # 设置label控件的长和宽    b.resize(100,20)    # 设置字体样式大小    font = QFont()    font.setFamily("Arial")# 字体样式,中文英文都可(“楷体”)    font.setPointSize(20)# 字体大小    b.setFont(font)    # 通过 setGeometry() 方法定义窗口的大小和位置(x,y,w,h)    w.setGeometry(100, 100, 500, 1000)    # 设置窗口标题    w.setWindowTitle("PyQt5")    # 显示窗口    w.show()    # 进入应用程序的主循环app.exec_()方法(窗口一直显示)    sys.exit(app.exec_())if __name__ == '__main__':    windows()备注写的很详细了,这里就不一一介绍每行代码的意思了。
3.窗口icon设置

import sysfrom PyQt5.QtGui import *from PyQt5.QtWidgets import QWidget, QApplication# 导入尽量用具体类,不用*class Window(QWidget):    def __init__(self, parent=None):      super().__init__(parent)      self.initUI()      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle("PyQt5")    # 设置icon    def initUI(self):      self.setWindowIcon(QIcon('./2.jpg'))# 设置窗口左上角icondef main():    app = QApplication(sys.argv)    ex = Window()    ex.show()    sys.exit(app.exec_())if __name__ == '__main__':    main()上述代码中,我们在initUI函数中,调用父类setWindowIcon()方法去设置窗口icon,在Window类中初始化时去调用initUI函数来实现设置icon。
4.QLabel控件

    def qlabel(self):      font = QFont()      font.setFamily("Arial")      font.setPointSize(16)      label = QLabel(self)      label.setText("Hello World")# 设置文本      label.setFont(font)# 设置文本字体类型及大小      label.move(50, 20)# 控件在窗口的位置这里和如上写法一致,在Window类中写一个qlabel函数,里面去调用QLabel,再在Window类中初始化时调用这个函数即可(使用QLabel模块时需提前导入该模块),我们来看下结果。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240221105254339-534060428.png
5.tips信息提示框

    def tips(self):      # 创建一个按钮控件      btn = QPushButton('Button', self)      # 设置文本字体及大小      btn.setFont(QFont('SansSerif', 50))      # 设置tips      btn.setToolTip('This is a widget')      # 设置按钮在窗口的位置      btn.move(100, 100)效果如下,鼠标悬浮在button上时,会出现tips信息弹框。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240221105822129-2010407473.png
6.关闭二次确定弹框

主动关闭窗口(即点击窗口右上角X),弹出二次确定弹框,提示是否关闭。
import sysfrom PyQt5.QtGui import *from PyQt5.QtWidgets import QWidget, QApplication, QMessageBox, QDesktopWidget# 导入尽量用具体类,不用*class Window(QWidget):    def __init__(self, parent=None):      super().__init__(parent)      self.initUI()      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle("PyQt5")      self.center()    # 设置icon    def initUI(self):      self.setWindowIcon(QIcon('./2.jpg'))    def closeEvent(self, event):# 关闭二次确定弹框      reply = QMessageBox.question(self, '是否关闭',                                     "Are you sure to quit?", QMessageBox.Yes, QMessageBox.No)      if reply == QMessageBox.Yes:            event.accept()# 关闭窗口      else:            event.ignore()# 不关闭    def center(self):# 设置窗口居中      qt = self.frameGeometry()   # 获取需要操作的窗口位置,长宽(即设置的setGeometry)      cp = QDesktopWidget().availableGeometry().center()# 获取电脑分辨率      qt.moveCenter(cp)# 获取电脑中间位置      self.move(qt.topLeft())# 将窗口移动到中间位置def main():    app = QApplication(sys.argv)    ex = Window()    ex.show()    sys.exit(app.exec_())if __name__ == '__main__':    main()上述代码中重写了父类中的closeEvent方法,通过QMessageBox.question()来获取用户行为,event.accept()来确定关闭窗口。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240221112709390-1874761739.png
7.关闭窗口事件

    def clos(self):      qbtn = QPushButton('Quit', self)# 创建一个按钮      qbtn.clicked.connect(QCoreApplication.instance().quit)# 回调关闭事件      qbtn.setToolTip("点击关闭窗口")# tips提示      qbtn.move(0, 0)如下图效果,鼠标点击Quit按钮后窗口关闭,其效果和关闭按钮X一致。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240221111854396-439678754.png
8.菜单栏和工具栏

QMainWindow用于创建主应用程序窗口的类。它是 QWidget 的一个子类,提供了创建具有菜单栏、工具栏、状态栏等的主窗口所需的功能。
1)状态栏
import sysfrom PyQt5.QtWidgets import QMainWindow, QApplicationclass Example(QMainWindow):    def __init__(self):      super().__init__()      self.initUI()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')      self.statusBar().showMessage("状态栏")# 设置状态栏if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())状态栏的设置很简单,通过调用QMainWindow的statusBar()方法创建状态栏,showMessage()来设置状态栏显示的文本。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222164232007-379027425.png
2)菜单栏
    def bar(self):      action = QAction(QIcon('./2.jpg'), '登录', self)# 创建QAction实例      action.setShortcut('Ctrl+a')# 设置快捷键操作      action.setStatusTip('登录')# 状态栏提示,窗口的左下角出现,鼠标悬停在选项上会出现      action.triggered.connect(qApp.quit)# 点击事件后回调的方法(qApp.quit关闭窗口)      menubar = self.menuBar()# 创建一个菜单栏      menu = menubar.addMenu('File')# 设置菜单栏tab      menu.addAction(action)# 关联事件用过menuBar()创建一个菜单栏,并添加addMenu()tab项,通过addAction()添加QAction行为动作,具体效果如下。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222170628911-1363068885.png
 triggered.connect(qApp.quit)设置了触发动作后回调事件,即点击登录选项或快捷键Ctrl+A时会触发qApp.quit关闭窗口。上诉中我们只创建了一个菜单栏并只绑定了一个QAction如果想要多个菜单栏多个动作,可以创建多个addMenu(),下面看下具体实例。
   def bar(self):      action = QAction(QIcon('./2.jpg'), '登录', self)# 创建QAction实例      action.setShortcut('Ctrl+a')# 设置快捷键操作      action.setStatusTip('登录')# 状态栏提示,窗口的左下角出现,鼠标悬停在选项上会出现      action.triggered.connect(qApp.quit)# 点击事件后回调的方法(qApp.quit关闭窗口)      action1 = QAction(QIcon('./2.jpg'), '登录', self)# 创建QAction实例      action1.setShortcut('Ctrl+a')# 设置快捷键操作      action1.setStatusTip('退出')# 状态栏提示,窗口的左下角出现,鼠标悬停在选项上会出现      action1.triggered.connect(qApp.quit)# 点击事件后回调的方法(qApp.quit关闭窗口)      menubar = self.menuBar()# 创建一个菜单栏      menu = menubar.addMenu('File')# 设置菜单栏tab      menubar1 = self.menuBar()# 创建一个菜单栏      menu1 = menubar1.addMenu('File1')# 设置菜单栏tab      menu.addAction(action)# 关联事件      menu.addAction(action1)# 关联事件3)子菜单栏
上面我们只是实现了一级菜单栏,那么在需求中要求创建二级,三级或者多级菜单,此时就需要用到QMenu()来创建下拉菜单栏了,我们先来看下二级菜单栏的创建。
    # 创建子菜单    def bar_z(self):      menubar = self.menuBar()# 创建菜单栏      menu = menubar.addMenu('File')# 设置菜单栏tab      newmenu = QMenu('一级下拉框', self)# 创建一个下拉菜单      impAct = QAction('二级目录', self)# 设置一个动作      impAct.triggered.connect(self.btn)# 点击事件后回调的方法      newmenu.addAction(impAct)# 添加动作到下菜单中      newact = QAction('一级目录', self)# 创建动作      menu.addAction(newact)# 添加动作到菜单栏      menu.addMenu(newmenu)# 添加下拉菜单到菜单栏    def btn(self):      # 创建一个按钮控件      btn = QPushButton('Button', self)      # btn.setGeometry(100, 100, 80, 30)      btn.move(100, 100)      btn.setToolTip("button")      btn.show()https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222172752559-523758500.png
 如果我们想创建三级目录甚至更多级的目录,可以创建多个下拉菜单栏,并通过addMenu()添加进去,下面看下具体实现。
# 创建子菜单    def bar_z(self):      menubar = self.menuBar()# 创建菜单栏      menu = menubar.addMenu('File')# 设置菜单栏tab      newmenu1 = QMenu('二级下拉框', self)# 创建一个下拉菜单      impAct1 = QAction('三级目录', self)# 设置一个动作      impAct1.triggered.connect(self.btn)# 点击事件后回调的方法      newmenu1.addAction(impAct1)# 添加动作到下菜单中      newmenu = QMenu('一级下拉框', self)# 创建一个下拉菜单      impAct = QAction('二级目录', self)# 设置一个动作      impAct.triggered.connect(self.btn)# 点击事件后回调的方法      newmenu.addAction(impAct)# 添加动作到下菜单中      newmenu.addMenu(newmenu1)# 添加下拉菜单栏到二级菜单下      newact = QAction('一级目录', self)# 创建动作      menu.addAction(newact)# 添加动作到菜单栏      menu.addMenu(newmenu)# 添加下拉菜单到菜单栏https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222173306017-1634877281.png
4)带复选框的菜单
    def bar_checkable(self):      menubar = self.menuBar()      bar_menu = menubar.addMenu('View')# 添加菜单栏      statact = QAction('复选框', self, checkable=True)# 创建一个可以勾选的动作      statact.setStatusTip('View statusbar')      statact.setChecked(True)# 设置默认选中      statact.triggered.connect(self.menu)      bar_menu.addAction(statact)    def menu(self, state):      if state:            print("勾选后执行的事件")# 勾选了      else:            print("取消勾选执行的事件")# 取消勾选QAction()中,checkable=True表示可以勾选的动作。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222174209721-1669569066.png
5)右键栏
鼠标悬浮再窗口上,右击打开的菜单栏,此功能需要重写父类中contextMenuEvent()方法,看下代码演示。
    def contextMenuEvent(self, event):      rightmenu = QMenu(self)# 创建一个下拉菜单      # 添加动作      d = rightmenu.addAction("打印")      q = rightmenu.addAction("退出")      ture = rightmenu.addAction("确定")      action = rightmenu.exec_(self.mapToGlobal(event.pos()))# exec_()显示菜单。获取动作行为      if action == d:            self.btn()      elif action == q:            qApp.quit()# 关闭窗口      else:            print("无确定内容")6)工具栏
工具栏可以理解为是多个动作的集合,可以将多个QAction()添加展示出来。
    def bar_tool(self):# 多个动作集合      action = QAction("工具1",self)      action2 = QAction("工具2",self)      action.setStatusTip("点击退出")      action.triggered.connect(qApp.quit)      toolbat = self.addToolBar("工具栏")# 创建一个工具栏      toolbat.addAction(action)# 将动作添加到工具栏      toolbat.addAction(action2)# 将动作添加到工具栏https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222175306719-1261792888.png
7)主窗口显示
这个就不做过多介绍,在初始__init__中调用上诉几种方法即可,默认菜单栏在最顶部,添加的动作会更加调用的先后从左到右排列,工具栏默认在菜单栏下发,这里只看下效果截图。
https://img2024.cnblogs.com/blog/1668630/202402/1668630-20240222174958637-811340293.png
 9.页面布局

1)坐标布局
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifimport sysfrom PyQt5.QtGui import QIconfrom PyQt5.QtWidgets import QLabel, QApplication, QWidgetclass Example(QWidget):    def __init__(self):      super().__init__()      self.initUI()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')      q1 = QLabel("quit", self)      q2 = QLabel("quit2", self)      q3 = QLabel("quit3", self)      q1.move(20, 20)# 坐标布局      q2.move(20, 80)# 坐标布局      q3.move(20, 140)# 坐标布局if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())坐标布局 上述中通过move(x, y)方法来设置qlable的位置
https://img2024.cnblogs.com/blog/1668630/202403/1668630-20240318164319829-1247308064.png
2)界面比例布局
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifimport sysfrom PyQt5.QtGui import QIconfrom PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QWidgetclass Example(QWidget):    def __init__(self):      super().__init__()      self.initUI()      self.button()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')    def button(self):# 比例布局      ok = QPushButton("ok")# 创建三个按钮      cancel = QPushButton("cancel")      cancel1 = QPushButton("cancel1")      hbox1 = QHBoxLayout()# 创建一个水平布局      hbox1.addWidget(ok)# 添加按钮到水平布局中      hbox1.addStretch(1)# 设置水平比例间距      hbox1.addWidget(cancel)# 添加按钮到水平布局中      hbox1.addStretch(1)# 设置水平比例间距      hbox1.addWidget(cancel1)      hbox1.addStretch(6)      self.setLayout(hbox1)# 添加到布局器if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())水平布局上面代码中通过QHBoxLayout() 创建一个水平布局,addWidget()将按钮添加到布局中,再通过addStretch()来设置比例间距,可以看到设置的比例为1:1:6https://img2024.cnblogs.com/blog/1668630/202403/1668630-20240318175210820-102278827.png
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifimport sysfrom PyQt5.QtGui import QIconfrom PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QVBoxLayout, QWidgetclass Example(QWidget):    def __init__(self):      super().__init__()      self.initUI()      self.button()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')    def button(self):# 比例布局      ok = QPushButton("ok")# 创建三个按钮      cancel = QPushButton("cancel")      cancel1 = QPushButton("cancel1")      hbox = QHBoxLayout()# 创建一个水平布局      hbox.addStretch(1)# 设置水平比例间距(只设置一个stretch,会将按钮挤到最右侧。若stretch写在addWidget下面,则按钮会被寄到最左侧)      hbox.addWidget(ok)# 添加按钮到水平布局中      hbox.addWidget(cancel)      vbox = QVBoxLayout()# 创建一个垂直布局      vbox.addStretch(1)# 设置垂直比例间距(只设置一个stretch,会将按钮挤到最下面。若stretch写在addlayout下面,则按钮会被寄到最下面)      vbox.addLayout(hbox)# 将刚刚创建的水平布局添加到垂直布局中      self.setLayout(vbox)# 将垂直布局加到布局器中(按钮位于页面右下角)if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())垂直布局https://img2024.cnblogs.com/blog/1668630/202403/1668630-20240318175716605-154895655.png
3)栅格化布局
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifimport sysfrom PyQt5.QtGui import QIconfrom PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QGridLayoutclass Example(QWidget):    def __init__(self):      super().__init__()      self.initUI()      self.Grid()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')    def Grid(self):# 栅格化的按钮      grid = QGridLayout()# 创建一个栅格化布局      name = ["7", "8", "9", "/",                "4", "5", "6", "x",                "1", "2", "3", "-",                "清除", "0", ".", "="]      # 列表推导式      pos = [(x, y) for x in range(4) for y in range(4)]      for names, p in zip(name, pos):# 同时迭代两个序列            button = QPushButton(names)# 创建按钮            grid.setSpacing(10)# 设置各个单元格之间的间距            grid.addWidget(button, *p)# 添加到栅格化布局中      self.setLayout(grid)# 将栅格化布局加到布局器if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())栅格化布局效果图
https://img2024.cnblogs.com/blog/1668630/202403/1668630-20240318180416965-1557912194.png
 栅格化布局理论上也是通过坐标来定位的,通过列表推导式可到得到几个坐标(0,0)(0,1)(0,2)(1,0)(1,1)(1,2)..........,然后再通过坐标去逐个添加。
4)实例
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifimport sysfrom PyQt5.QtGui import QIconfrom PyQt5.QtWidgets import QLabel, QApplication,QWidget, QGridLayout, \    QLineEdit, QTextEditclass Example(QWidget):    def __init__(self):      super().__init__()      self.initUI()      self.input()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')    def input(self):      grid = QGridLayout()      # 设置标签      title = QLabel("title")      Author = QLabel("Author")      Review = QLabel("Review")      # 设置输入框      titleEdit = QLineEdit()# 行编辑      authorEdit = QLineEdit()      reviewEdit = QTextEdit()# 文版编辑      grid.setSpacing(10)# 设置间距      grid.addWidget(title, 0, 0)      grid.addWidget(titleEdit, 0, 1)      grid.addWidget(Author, 1, 0)      grid.addWidget(authorEdit, 1, 1)      grid.addWidget(Review, 2, 0)      grid.addWidget(reviewEdit, 2, 1)      self.setLayout(grid)if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())实例上述中实例通过QGridLayout()来将QLabel(), QLineEdit(行编辑)  ,QTextEdit(文版编辑) 进行的整合使用,下面看下结果。
https://img2024.cnblogs.com/blog/1668630/202403/1668630-20240318181138576-1971696194.png
四.实例

 以一个简单计算器功能为例,先来看下代码实现和效果展示
https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gifhttps://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gifimport sysfrom PyQt5.QtGui import QIconfrom PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QGridLayout, \    QLineEditclass Example(QWidget):    def __init__(self):      super().__init__()      self.initUI()      self.Grid()    def initUI(self):      self.setGeometry(100, 100, 500, 500)      self.setWindowTitle('Statusbar')    def Grid(self):# 栅格化的按钮      grid = QGridLayout()      hbox = QLineEdit()      grid.addWidget(hbox, 0, 0, 1, 4)      name = [            "7", "8", "9", "/",            "4", "5", "6", "*",            "1", "2", "3", "-",            "清除", "0", ".", "="]      # 列表推导式      pos = [(x, y) for x in range(1,5) for y in range(4)]      for names, p in zip(name, pos):# 同时迭代两个序列            if names == "":                continue            elif names == "hbox":                grid.addWidget(hbox, *p)            else:                button = QPushButton(names)                grid.addWidget(button, *p)                button.clicked.connect(lambda checked, btn_text=names: on_button_clicked(btn_text))            grid.setSpacing(10)# 设置各个单元格之间的间距      self.setLayout(grid)      def on_button_clicked(btn_text):            try:                if btn_text == "清除":                  hbox.clear()                elif btn_text == "=":                  str_num = eval(hbox.text())                  hbox.clear()                  hbox.insert(str(str_num))                else:                  hbox.insert(btn_text)            except:                hbox.insert("error")if __name__ == '__main__':    app = QApplication(sys.argv)    ex = Example()    ex.show()    sys.exit(app.exec_())计算器https://img2024.cnblogs.com/blog/1668630/202403/1668630-20240319111102452-219825561.png
 使用addWidget将输入框添加到栅格化布局中,后面无个参数分别表示:(添加对象,x位置,y位置,占据的单元格高度,占据的单元格宽度)。
grid.addWidget(hbox, 0, 0, 1, 4)QLineEdit()几个常用的方法
      hbox = QLineEdit()      hbox.setText("默认文案")# 设置默认文案      hbox.setPlaceholderText("暗文")# 当输入框内容为空时显示该文案      hbox.insert("243")# 添加      print(hbox.text())# 获取框内容      hbox.clear()# 清空五.打包

可参考:https://www.cnblogs.com/lihongtaoya/p/17349911.html
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
文章来源:https://www.cnblogs.com/lihongtaoya/ ,请勿转载
来源:https://www.cnblogs.com/lihongtaoya/p/18023773
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: PyQt5 GUI编程