常用控件4

点击这里,边看视频讲解,边学习下面的内容

菜单栏/菜单

菜单栏/菜单 相关的 Python QT 官方文档 链接如下:

菜单栏

菜单

QAction


需要菜单栏的,通常是 QMainWindow 类型的窗口, 我们可以使用代码创建菜单栏内容,如下

from PySide2 import QtWidgets
from PySide2.QtGui import QIcon

class Window(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()
        self.resize(600,200)

        # 创建 菜单栏QMenuBar 对象 并返回
        menuBar = self.menuBar()

        # 一级菜单
        fileMenu = menuBar.addMenu("文件")
        editMenu = menuBar.addMenu("编辑")
        helpMenu = menuBar.addMenu("帮助")
        # 一级Action
        actionHomePage = menuBar.addAction('主页')
        actionHomePage.triggered.connect(self.actionHomePageClicked)

        # 一级菜单的 action项
        actionAddNode = fileMenu.addAction(QIcon("./Images/folder.png"),"添加")
        fileMenu.addSeparator() # 分隔符
        actionDelNode = fileMenu.addAction("删除")
        actionAddNode.triggered.connect(self.actionAddNodeClicked)
        actionDelNode.triggered.connect(self.actionDelNodeClicked)

        # 二级菜单
        edit_1 = editMenu.addMenu("插入图表")
        edit_2 = editMenu.addMenu("插入图片")

        # 二级菜单的 action项
        action1 = edit_1.addAction("action1")
        action2 = edit_1.addAction("action2")

    def actionHomePageClicked(self):
        print('actionHomePageClicked')

    def actionAddNodeClicked(self):
        print('actionAddNodeClicked')

    def actionDelNodeClicked(self):
        print('actionDelNodeClicked')


app = QtWidgets.QApplication([])
ex = Window()
ex.show()
app.exec_()

大家可以运行一下上面的代码,看一下界面。


菜单层级结构是这样的:

菜单栏(QMenuBar) ->  菜单(QMenu) -> QAction

当然,菜单里面还可以有子菜单,就是这样

菜单栏(QMenuBar) ->  菜单(QMenu)->  子菜单(QMenu) -> QAction

注意:上面说的子菜单,并不是一种新的类型,也是 QMenu , 只是从属于其他Qmenu, 就像 QLayout 形成的层级关系一样。


菜单里面 点击能触发操作的条目,称之为 QAction ,中文叫 动作


也可以在 Qt Designer上很方便的为 QMainWindow 类型的窗口添加菜单,如下所示

image

点击 菜单Action, 会触发信号 triggered, 处理点击菜单的的代码如下

self.ui.actionOpenFile.triggered.connect(self.openPageFile)

工具栏

工具栏的 Python QT 官方文档 链接如下:

工具栏


工具里面的可以点击的条目 也是 QAction ,和菜单栏一样!

可以用代码创建工具栏的内容,如下

from PySide2 import QtWidgets
from PySide2.QtGui import QIcon

class Window(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()
        self.resize(600,200)

        # 创建 工具栏 对象 并添加
        toolbar = QtWidgets.QToolBar(self)
        self.addToolBar(toolbar)

        # 添加 工具栏 条目Action
        actionAddNode = toolbar.addAction(QIcon("./Images/folder.png"),"添加")
        actionAddNode.triggered.connect(self.actionAddNodeClicked)

        action = toolbar.addAction("删除")
        action = toolbar.addAction("修改")
        action = toolbar.addAction("查询")
        toolbar.addSeparator()             # 添加分隔符
        action = toolbar.addAction("帮助")

    def actionAddNodeClicked(self):
        print('actionAddNodeClicked')


app = QtWidgets.QApplication([])
ex = Window()
ex.show()
app.exec_()

如果 菜单栏 和 工具栏有 相同的 action ,可以公用一个Action对象。


也可以在 Qt Designer上很方便的为 QMainWindow 类型的窗口添加工具栏。

右键点击 Main Window 类型的窗体空白处,如下所示

image

选择添加工具栏


注意,只有 Main Window 类型的窗体,才能添加工具栏,如下

image


添加工具栏后,还要在工具栏上添加 条目Action (中文称之为: 动作 )。

方法是点击右下角 动作编辑器 ,新建动作,如下图所示

image

然后如下图所示进行设置

image

添加动作成功后,就可以直接拖到工具栏上了。


然后,在代码中定义动作触发后的处理函数,如下所示

self.ui.actionAddNote.triggered.connect(self.actionAddNode)

如果菜单和工具栏有 相同的 action ,通常是先在 动作编辑器 创建一个action, 然后分别拖动到 菜单 和 工具栏

状态栏

官网介绍

状态栏通常显示在窗口底部,对应的控件类型是: QStatusBar

需要底部状态栏的,通常是 QMainWindow 类型的窗口, 用 Qt Designer 设计的Qt Designer, 会自带状态栏,缺省属性名称为 statusbar


要在状态栏显示文本信息,只需要调用 状态栏 QStatusBar 的 showMessage 方法,如下

self.ui.statusbar.showMessage(f'打开文件{filePath}')

提示框

QMessageBox 类可以用来弹出各种提示框

官网介绍

该类可以通过一系列静态方法,显示 如下弹出框

  • 错误报告

image

使用 critical 方法

from PySide2.QtWidgets import QMessageBox

QMessageBox.critical(
    self.ui,
    '错误',
    '请选择爬取数据存储路径!')
  • 警告

image

使用 warning 方法

from PySide2.QtWidgets import QMessageBox

QMessageBox.warning(
    self.ui,
    '阅读太快',
    '阅读客户协议必须超过1分钟')
  • 信息提示

image

使用 information 方法

from PySide2.QtWidgets import QMessageBox

QMessageBox.information(
    self.ui,
    '操作成功',
    '请继续下一步操作')

也可以使用 about 方法

from PySide2.QtWidgets import QMessageBox

QMessageBox.about(
    self.ui,
    '操作成功',
    '请继续下一步操作')
  • 确认继续

image

使用 question 方法

from PySide2.QtWidgets import QMessageBox

choice = QMessageBox.question(
    self.ui,
    '确认',
    '确定要删除本文件吗?')

if choice == QMessageBox.Yes:
    print('你选择了yes')
if choice == QMessageBox.No:
    print('你选择了no')

输入对话框

QInputDialog 输入对话框 只让用户输入一行数据信息,比如 姓名、年龄等。

可以方便的用来获取简单的信息。

image

官网介绍


比如

from PySide2.QtWidgets import QInputDialog,QLineEdit

# 返回值分别是输入数据 和 是否点击了 OK 按钮(True/False)
title, okPressed = QInputDialog.getText(
    self, 
    "输入目录名称",
    "名称:",
    QLineEdit.Normal,
    "")

if not okPressed:
    print('你取消了输入')

常用的方法有:

  • getText

    弹出对话框,让用户输入 单行文本

  • getMultiLineText

    弹出对话框,让用户输入 多行文本

  • getInt

    弹出对话框,让用户输入 整数

  • getItem

    弹出对话框,让用户选择 选项

    items = ["春天", "夏天", "秋天", "冬天"]
    
    item, ok = QInputDialog().getItem(self, 
                                      "请选择",
                                      "季节:", 
                                      items, 
                                      0, 
                                      False)
    if ok and not item.isEmpty():
        itemLabel.setText(item)
    

剪贴板

Qt程序可以获取和设置剪贴板内容

官网介绍

from PySide2.QtGui import QGuiApplication

cb = QGuiApplication.clipboard()
# 获取剪贴板内容
originalText = cb.text()
# 设置剪贴板内容
clipboard.setText(newText)

树控件

QTreeWidget 树控件 树控件, 是和 QTreeWidgetItem 树节点控件 结合使用的。

如下图所示

image

QTreeWidget 官网介绍

QTreeWidgetItem 官网介绍


本节内容的视频讲解 在老师发你的 实战班内部补充学习视频网盘 里的 树控件 目录中。


说明

树控件用来展示树状层级结构的数据,典型例子有: 文件目录结构、知识点结构

设置属性

如果用 Qt 设计师 工具 制作界面,首先应该设置好 QTreeWidget 的一些属性,如下

image

其中,常见的设置是 :

  • 设置有几个column ,也就是有几列,

    双击树控件,就可以编辑列名,如下图

    image

  • 可以设置列标头 是否可见

添加节点

设置好 QTreeWidget 的属性以后,代码中加载界面资源文件,就可以在树上添加节点了,如下代码所示

注意:QTreeWidget 有一个不可见根节点 ,树的第一层节点 都是这个 不可见根节点的 子节点,它是整个树的根。 可以通过 invisibleRootItem 方法获得。

from PySide2.QtWidgets import QApplication
from PySide2.QtUiTools import QUiLoader

# 导入 QTreeWidget, QTreeWidgetItem, QIcon
from PySide2.QtWidgets import  QTreeWidget, QTreeWidgetItem
from PySide2.QtGui import QIcon

class SomeWindow:

    def __init__(self):

        self.ui = QUiLoader().load('main.ui')
        # 调用设置树控件
        self.setupTree()

    def setupTree(self):
        # 获取树控件对象
        tree = self.ui.tree

        # 隐藏标头栏
        tree.setHeaderHidden(True)

        # 获取树控件的不可见根节点
        root = tree.invisibleRootItem()

        # 准备一个folder节点
        folderItem = QTreeWidgetItem()
        # 创建图标对象
        folderIcon = QIcon("./Images/folder.png")
        # 设置节点图标
        folderItem.setIcon(0, folderIcon)
        # 设置该节点  第1个column 文本
        folderItem.setText(0, '学员李辉')
        # 添加到树的不可见根节点下,就成为第一层节点
        root.addChild(folderItem)
        # 设置该节点为展开状态
        folderItem.setExpanded(True)

        # 准备一个 叶子 节点
        leafItem = QTreeWidgetItem()
        leafIcon = QIcon("./Images/leaf.gif")
        # 设置节点图标
        leafItem.setIcon(0, leafIcon)
        # 设置该节点  第1个column 文本
        leafItem.setText(0, '作业 - web自动化1')
        # 设置该节点  第2个column 文本
        leafItem.setText(1, '提交日期20200101')
        # 添加到 叶子节点 到 folerItem 目录节点下
        folderItem.addChild(leafItem)

app = QApplication([])
w = SomeWindow()
w.ui.show()
app.exec_()

上面的程序运行后,大概的结果图如下

image

注意:

  • 每个 节点 都是 QTreeWidgetItem 对象

  • 添加节点 必须通过 该节点的 父节点

    可以使用 addChild 方法,添加到最后

    也可以使用 insertChild 方法,插入到指定位置,比如

    folderItem.insertChild(2, leafItem)
    

    就插入到 第3个 子节点的位置上,因为第1个子节点的索引是0。

  • 如果控件宽度不够,字符串会显示为省略号。

列宽度

列的宽度,可以在界面上 该 QTreeWidget 控件的属性编辑里面, 调整 headerDefaultSectionSizeheaderStretchLastSection 来控制。


也可以通过代码来控制,如下

    def setupTree(self):
        # 其他代码...

        tree.setColumnWidth(0, 200) # 设置第一列宽度,200px

        header = tree.header()
        header.setStretchLastSection(True)

如果想让列宽度 自适应 内容,使用 下面的方法

from PySide2.QtWidgets import QHeaderView


    def setupTree(self):
        # 其他代码...

        header = tree.header()
        # 让列宽度 自适应 内容
        header.setSectionResizeMode(QHeaderView.ResizeToContents)

当前选中节点

我们有时要在当前节点下面添加节点、删除当前节点,这就需要先获取当前节点。

QTreeWidgetcurrentItem 方法可以获取当前节点。

下面是一段 在选中节点下面添加子节点 的示例代码

from PySide2.QtWidgets import QLineEdit, QInputDialog
from PySide2.QtCore import Qt

class SomeWindow:

    def __init__(self):

        self.ui = QUiLoader().load('main.ui')
       
        self.ui.btn_add.clicked.connect(self.addChildNode)

    # 其他部分代码
    .... 

    def addChildNode(self):
        # 获取树控件对象
        tree = self.ui.tree

        # 获取当前用户点选的节点
        currentItem = tree.currentItem()
        # 没有当前选中节点,不可见根节点作为当前节点
        if not currentItem:
            currentItem = tree.invisibleRootItem()

        # 当前节点的第一列文本内容
        col1Text = currentItem.text(0)
        print(col1Text)

        # 让用户输入信息
        title, okPressed = QInputDialog.getText(
                self.ui, "输入名称", "名称:",
                QLineEdit.Normal, "")

        if not okPressed or title == '':
            return

        # 准备一个folder节点
        folderItem = QTreeWidgetItem()
        # 创建图标对象
        folderIcon = QIcon("./images/folder_close.png")
        # 设置节点图标
        folderItem.setIcon(0, folderIcon)
        # 设置该节点  第1个column 文本
        folderItem.setText(0, title.strip())
        # 设置该节点在以前的flag基础上,多一个可编辑 ItemIsEditable
        folderItem.setFlags(folderItem.flags() | Qt.ItemIsEditable)

        currentItem.addChild(folderItem)
        currentItem.setExpanded(True)

获取父节点

获取一个节点的父节点是调用 该QTreeWidgetItem节点的 parent 方法

如下


    # 获取某个节点item的父节点item
    parentItem = treeItem.parent()
    # 如果返回值为None,其必定为顶层节点,它的父节点是不可见的根节点
    if not parentItem:
        parentItem = tree.invisibleRootItem()

删除节点

删除 QTreeWidget 的节点, 是 通过其父节点调用 removeChild 方法。

示例代码如下:

    # 获取当前用户点选的节点
    currentItem = tree.currentItem()

    # 如果没有当前选中节点
    if not currentItem:
        return
    
    # 找到改节点的父节点
    parentItem = currentItem.parent()
    # 如果没有父节点,就是不可见父节点
    if not parentItem:
        parentItem = tree.invisibleRootItem()
    # 删除该节点
    parentItem.removeChild(currentItem)

注意:删除一个节点,同时也就删除了其所有子节点。

删除所有节点

可以使用 QTreeWidget 的方法 clear,如下

tree.clear()

也可以删除不可见根节点的所有子节点的方法,如下

root = tree.invisibleRootItem()

for i in reversed(range(root.childCount())):
    root.removeChild(root.child(i))

编辑节点文本

假设我们要 实现,双击节点文本 可以 编辑节点文本,就是如下所示

image

首先必须设置节点flag为 : 可编辑 ItemIsEditable

可以在创建节点的时候设置,如下代码所示

from PySide2.QtCore import Qt

# 准备一个folder节点
folderItem = QTreeWidgetItem()
folderItem.setIcon(0, folderIcon)
folderItem.setText(0, '白月黑羽学员李辉')

# 设置该节点在以前的flag基础上,多一个可编辑 ItemIsEditable
folderItem.setFlags(folderItem.flags()  | Qt.ItemIsEditable)

信号处理

QTreeWidget 常见的信号有:单击节点、双击节点、当前节点变动 等等。

详细信息参考官方文档

大家可以根据自己的需要,定义信号处理函数


比如,可以这样定义节点 被点击事件 的处理函数


class SomeWindow:

    def __init__(self):

        self.ui = QUiLoader().load('main.ui')

        # 添加 被点击事件 的处理函数
        self.ui.tree.itemClicked.connect(self.itemClicked)

    # 参数 item 是被点击节点对应的 QTreeWidgetItem 对象
    # 参数 column 是被点击的column号
    def itemClicked(self, item, column):
        # 获取被点击的节点文本
        clickedText = item.text(column)

        if 'bottle' in clickedText:
            self.bottle()
        elif 'cube' in clickedText:
            self.cube()

再看一个例子,可编辑的节点文本被编辑改变后,其所属 QTreeWidget 就会触发 itemChanged 信号

我们应该定义该信号的处理函数,如下所示


class SomeWindow:

    def __init__(self):

        self.ui = QUiLoader().load('main.ui')

        # 必须先加载树,然后再设置信号处理,
        # 否则加载过程也会触发 itemChanged 信号
        self.ui.tree.itemChanged.connect(self.itemChanged)


    def itemChanged(self, item, column):
        # 参数 item 是修改的 节点 QTreeWidgetItem对象
        # 参数 column 是修改的 列号

        newText = item.text(column)

        # 根据改变的 column 得知是哪个数据修改了
        # 保存到对应的数据库表记录中
            

节点关联数据

Python中, 类对象可以动态添加属性,

所以我们可以根据需要,给 QTreeWidgetItem 节点对象 关联 各种类型的数据。

如下所示:

    nodeitem = QTreeWidgetItem()
    nodeitem.setText(0, filename)
     # python 对象可以动态添加属性
    nodeitem._my_data1 = '给节点关联的数据,根据需要设定'
    nodeitem._my_data2 = ['其它数据1','其它数据2']

这些关联的数据,可以在后续操作节点时,根据需要取出来使用。


关联数据又什么用呢? 想象这样一个案例:

我们用树控件显示一个目录下的文件。

当用户双击节点,修改了文件的名字,代码应该 在 itemChanged 信号处理函数中真正修改该文件名。

但是如果,用户修改的名字已经存在同名文件,就会产生冲突,这时,应该恢复该节点的名字为原来的名字。

但是,界面上改为新名字了,原来名字丢失了怎么办?

这时就可以使用 关联数据的方案:

  • 添加节点时,除了 这样 设置文件名,
nodeitem.setText(0, filename)

再给节点动态添加一个属性,比如

nodeitem._my_filename = filename

备份一个文件名的记录


后面如果修改节点名方法,发现名字冲突了,就改回原来的名字

    # 修改节点名
    def treeItemNameChanged(self, item, column):

        newName = item.text(column)
        filepath = os.path.join(self.thisFolderPath, newName)

        # 文件名冲突,还原
        if os.path.exists(filepath):
            QMessageBox.information(
                self.ui, '错误',
                f'文件 {filepath} 已经存在,请重新修改')

            # 原来的名字保存在自己定义的 _my_filename 属性中
            item.setText(0, item._my_filename)
            return

        # 不冲突的后续处理
        oriFilePath = os.path.join(self.thisFolderPath, item._my_filename)
        # 修改文件名
        os.rename(oriFilePath, filepath)

获取节点的子节点

QTreeWidgetItemchildCount() 方法可以获取子节点的个数

QTreeWidgetItemchild() 方法可以获取子节点对应的 QTreeWidgetItem 对象,参数就是子节点的编号,从0开始。

tree.child(0) 就是获取第1个子节点


下面这段代码就是打印某个树节点的 所有直接子节点 文本

    def printChildren(parent):
        child_count = parent.childCount()
        for i in range(child_count):
            item = parent.child(i)
            print(item.text(0))

如果要打印某个树节点的 所有后代节点 文本,最方便的就是用递归

    def printChildren(parent):
        child_count = parent.childCount()
        for i in range(child_count):
            item = parent.child(i)
            print(item.text(0))
            
            printChildren(item) # 调用自身,进行递归

上下文菜单

要用 树节点右键菜单功能,可以这样处理:

先这样做初始化设置

from PySide2.QtWidgets import QMenu, QAction 
from PySide2.QtCore import Qt

# 其它代码
...

    def __init__(self):
        
        # 其它初始化代码
        ...

        # 设置上下文菜单策略,也可以在 Qt Designer上设置
        self.ui.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        # 定义信号处理方法
        self.ui.tree.customContextMenuRequested.connect(
            self.show_context_menu_onfiletree)    

然后,定义信号处理方法

    def show_context_menu_onfiletree(self, position):
    
        tree = self.ui.tree 

        # 获取当前用户点选的节点
        curItem = tree.currentItem()

        # 没有当前选中节点
        if not curItem:
            print('没有选中节点,返回')
            return
                   
        # 创建 上下文菜单 和 菜单项Action      
        menu = QMenu(tree)

        action_delnode = QAction("删除")
        action_delnode.triggered.connect(self.action_delnode)  

        action_addnode = QAction("添加子节点")
        action_addnode.triggered.connect(self.action_addChildNode)  

        menu.addAction(action_delnode)
        menu.addAction(action_addnode)

        # 在鼠标点击处展示上下文菜单
        menu.exec_(tree.mapToGlobal(position))

    # 菜单项Action对应的处理函数
    def action_delnode(self, position):        
        # 这些写处理代码

    # 菜单项Action对应的处理函数
    def action_addChildNode(self, position):        
        # 这些写处理代码        

MDI 多个子窗口

QMdiArea 提供了一个主窗口区,里面可以存放多个 QMdiSubWindow 子窗口

如图:

image

QMdiArea 官网介绍

QMdiSubWindow 官网介绍



本节内容的视频讲解 在老师发你的 实战班内部补充学习视频网盘 里的 MDI 多个子窗口 目录中。


QMdiSubWindow 里面的子窗口,就是我们前面讲解的 QMainWindow

可以把任何前面示例的窗口作为 子窗口里面的内容。


可以直接用代码 创建有QMdiArea的主窗口界面,和 子窗口界面

示例代码如下

from PySide2 import QtCore, QtWidgets

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.resize(600, 400)
        self.setWindowTitle('主窗口')

        # 顶层布局
        centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(centralWidget)
        topLayout = QtWidgets.QVBoxLayout(centralWidget)

        # 添加一个 Label
        topLayout.addWidget(QtWidgets.QLabel('下面是MDI区域'))

        #  创建 MDI 区域
        self.mdiArea = QtWidgets.QMdiArea()
        topLayout.addWidget(self.mdiArea)


        # 创建子窗口对象1
        self.subWin1 = QtWidgets.QMdiSubWindow()
        # 设置子窗口里面的 的功能窗口
        self.subWin1.setWidget(Window1())
        # 把子窗口加入到 MDI 区域
        self.mdiArea.addSubWindow(self.subWin1)

        # 创建子窗口对象2
        self.subWin2 = QtWidgets.QMdiSubWindow()
        self.subWin2.setWidget(Window2())
        self.mdiArea.addSubWindow(self.subWin2)

class Window1(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # 顶层布局
        centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(centralWidget)
        topLayout = QtWidgets.QVBoxLayout(centralWidget)

        # 添加一个 Label
        topLayout.addWidget(QtWidgets.QLabel('该窗口实现 设备管理功能'))

class Window2(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        # 顶层布局
        centralWidget = QtWidgets.QWidget(self)
        self.setCentralWidget(centralWidget)
        topLayout = QtWidgets.QVBoxLayout(centralWidget)

        # 添加一个 Label
        topLayout.addWidget(QtWidgets.QLabel('该窗口实现 计费功能'))


app = QtWidgets.QApplication()
window = MainWindow()
window.show()
app.exec_()

也可以采用 QUiLoader().load 加载界面的方式,如下

from PySide2 import QtCore, QtWidgets
from PySide2.QtUiTools import QUiLoader

# 这个 func 里面的 SomeWindow 也是一个QUiLoader().load加载ui的类
# 其实例属性 ui 对应一个 QMainWindow
from func import SomeWindow


class MainWindow:
    def __init__(self):

        self.ui = QUiLoader().load('main.ui')

        # 创建子窗口对象
        self.subWin = QtWidgets.QMdiSubWindow()
        # 设置子窗口里面的 的功能窗口
        self.funcWin = SomeWindow()
        '''
        注意,上面这里不能用 funcWin = SomeWindow() 这样的局部变量保存
        因为下面 setWidget 保存的是 SomeWindow的ui属性对应的窗口对象,
        而不是 SomeWindow 对象本身
        '''       
        
        self.subWin.setWidget(self.funcWin.ui) 

        # 把子窗口加入到 MDI 区域
        self.ui.mdiArea.addSubWindow(self.subWin)


app = QtWidgets.QApplication()
window = MainWindow()
window.ui.show()
app.exec_()

也可以不是初始化界面就创建MDI子窗口,而是某个信号处理中,创建子窗口界面。

关键代码差不多的,就是最后要有把子窗口提到最上层显示的代码,

如下

from PySide2.QtWidgets import  QMdiArea,QMdiSubWindow
from PySide2.QtCore import Qt

class MainWindow:
    def __init__(self):
        # 一些主窗口的初始化代码

    # 信号处理代码
    def clickAddSomeWindow(self):  
        
        # 创建子窗口对象,代码和前面差不多
        self.subWin = QtWidgets.QMdiSubWindow()
        self.funcWin = SomeWindow()
        self.subWin.setWidget(self.funcWin.ui) 
        self.ui.mdiArea.addSubWindow(self.subWin)

        # 显示子窗口
        subWindow.show()
        # 子窗口提到最上层,并且最大化
        subWindow.setWindowState(Qt.WindowActive|Qt.WindowMaximized)


上面3D模型图图所示的例子是使用 pythonocc 3D 模型库开发的一个例子。

对应的代码包点击这里下载:

链接:https://pan.baidu.com/s/1N78n5ZJSqNxSs-tjrt6IOw 提取码:byhy


要能正确运行,需要按照如下步骤安装环境

  • 先下载 miniconda

    因为 pythonocc 包 只能通过conda 下载,不支持pip

    点击这里下载 https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe

    (注意;清华源的pythonocc必须64位才能找到pkg)

    安装好以后,打开 conda shell,执行下面的操作

  • 添加 conda 清华大学的国内源

    因为国外conda 源安装太慢了,所以要添加 conda 清华大学的国内源

    执行命令

    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
    
  • 安装 pythonocc-core

    conda install -c conda-forge pythonocc-core=7.4.0

  • 安装 pyside2

    这是 miniconda 里面Python解释器环境中安装 pyside2

    执行命令 pip install pyside2