• 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 PyQt5

    2.如果出现Could not build wheels for PyQt5_sip, which is required to install pyproject.toml-based projects报错信息

     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后安装就行

    三.基本用法

    1.PyQt5常见的模块

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

     

    2.一个简单的窗口创建

    复制代码
    import sys
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *
    from PyQt5.QtWidgets import QWidget, QLabel, QMessageBox, QApplication
    
    
    def 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 sys
    from 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'))  # 设置窗口左上角icon
    
    def 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模块时需提前导入该模块),我们来看下结果。

    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信息弹框。

    6.关闭二次确定弹框

    主动关闭窗口(即点击窗口右上角X),弹出二次确定弹框,提示是否关闭。

    复制代码
    import sys
    from 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()来确定关闭窗口。

    7.关闭窗口事件

        def clos(self):
            qbtn = QPushButton('Quit', self)  # 创建一个按钮
            qbtn.clicked.connect(QCoreApplication.instance().quit)  # 回调关闭事件
            qbtn.setToolTip("点击关闭窗口")  # tips提示
            qbtn.move(0, 0)

    如下图效果,鼠标点击Quit按钮后窗口关闭,其效果和关闭按钮X一致。

    8.菜单栏和工具栏

    QMainWindow用于创建主应用程序窗口的类。它是 QWidget 的一个子类,提供了创建具有菜单栏、工具栏、状态栏等的主窗口所需的功能。

    1)状态栏

    复制代码
    import sys
    from PyQt5.QtWidgets import QMainWindow, QApplication
    
    class 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()来设置状态栏显示的文本。

    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行为动作,具体效果如下。

     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()
    复制代码

     如果我们想创建三级目录甚至更多级的目录,可以创建多个下拉菜单栏,并通过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)  # 添加下拉菜单到菜单栏
    复制代码

    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表示可以勾选的动作。

    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)  # 将动作添加到工具栏
    复制代码

    7)主窗口显示

    这个就不做过多介绍,在初始__init__中调用上诉几种方法即可,默认菜单栏在最顶部,添加的动作会更加调用的先后从左到右排列,工具栏默认在菜单栏下发,这里只看下效果截图。

     9.页面布局

    1)坐标布局

    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QLabel, QApplication, QWidget
    
    
    class 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的位置

    2)界面比例布局

    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QWidget
    
    
    class 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:6

    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication, QPushButton, QHBoxLayout, QVBoxLayout, QWidget
    
    
    class 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_())
    垂直布局

    3)栅格化布局

    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QGridLayout
    
    
    class 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_())
    栅格化布局

    效果图

     栅格化布局理论上也是通过坐标来定位的,通过列表推导式可到得到几个坐标(0,0)(0,1)(0,2)(1,0)(1,1)(1,2)..........,然后再通过坐标去逐个添加。

    4)实例

    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QLabel, QApplication,QWidget, QGridLayout, \
        QLineEdit, QTextEdit
    
    
    class 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(文版编辑) 进行的整合使用,下面看下结果。

    四.实例

     以一个简单计算器功能为例,先来看下代码实现和效果展示

    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QGridLayout, \
        QLineEdit
    
    
    class 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_())
    计算器

     使用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/ ,请勿转载
  • 相关阅读:
    java中的注解
    【idea学习】
    [从零开始学习FPGA编程-56]:视野篇-常见概念:chip(芯片)、chipset(芯片组)、chiplet(芯粒)、die(裸片)的区别
    Redis - String|Hash|List|Set|Zset数据类型的基本操作和使用场景
    二维码智慧门牌管理系统升级解决方案:轻松实现辖区范围门址统计
    C语言之数学运算强化练习题
    速锐得解码TANK300烈马应用前大灯随动转向车灯照明系统DEMO
    共享虚拟主机可以处理多少流量?
    程序设计中遇到的程序不通、逻辑不顺等问题
    springboot的web开发
  • 原文地址:https://www.cnblogs.com/lihongtaoya/p/18023773