PyQt5-QTreeWidget和QDockWidget

image
image

1.设计的GUI界面为:

image

dockWidget和treeWidget采用栅格布局

image

2.对象查看器

image

image

image

image

3.动作编辑器

image

4.myWidget.py文件

import sys
from PyQt5.QtWidgets import  (QMainWindow,QApplication,QTreeWidgetItem,
                              QLabel,QFileDialog,QDockWidget)
from enum import Enum ##枚举类型
from PyQt5.QtCore import pyqtSlot,Qt,QDir,QFileInfo
from PyQt5.QtGui import QIcon,QPixmap
from ui_QtApp import Ui_MainWindow

class TreeItemType(Enum) : ##节点类型枚举类型
    itTopItem = 1001  # 顶层节点
    itGroupItem = 1002  # 组节点
    itImageItem = 1003  # 图片文件节点

class TreeColNum(Enum) :##目录树的列号枚举类型
    colItem = 0  # 分组/文件名列
    colItemType = 1  # 节点类型列

class QmyMainWindow(QMainWindow):
    def __init__(self,parent=None):
        super().__init__(parent) #调用父类构造函数
        self.ui=Ui_MainWindow() #创建UI对象
        self.ui.setupUi(self) #构造UI

        self.curPixmap = QPixmap()  # 图片
        self.pixRatio = 1  # 显示比例

        self.itemFlags = (
                    Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsAutoTristate)  # 节点标志
        self.setCentralWidget(self.ui.scrollArea)
        self.__iniTree()

        ##以下的属性在UI Designer里已经设置,这里是代码设置方法
        self.ui.dockWidget.setFeatures(QDockWidget.AllDockWidgetFeatures)
        self.ui.dockWidget.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)#允许左停靠和右停靠
        self.ui.scrollArea.setWidgetResizable(True)  # 自动调整内部组件大小
        self.ui.scrollArea.setAlignment(Qt.AlignCenter)
        self.ui.label.setAlignment(Qt.AlignCenter)

    ## ====由connectSlotsByName()自动与组件的信号关联的槽函数=====
    def __iniTree(self):##初始化目录树
        self.ui.treeWidget.clear()
        item=QTreeWidgetItem(TreeItemType.itTopItem.value)
        item.setText(TreeColNum.colItem.value,"图片文件")
        item.setFlags(self.itemFlags)
        item.setCheckState(TreeColNum.colItem.value,Qt.Checked)
        item.setData(TreeColNum.colItem.value,Qt.UserRole,"")
        self.ui.treeWidget.addTopLevelItem(item)

    @pyqtSlot()  ##添加目录节点
    def on_actTree_AddFolder_triggered(self):
        dirStr=QFileDialog.getExistingDirectory()# 选择目录
        if (dirStr== ""):
            return
        parItem = self.ui.treeWidget.currentItem()  # 当前节点
        if (parItem == None):
            parItem = self.ui.treeWidget.topLevelItem(0)
        dirObj = QDir(dirStr)
        # QDir对象
        nodeText=dirObj.dirName()
        # 最后一级目录的名称
        item = QTreeWidgetItem(TreeItemType.itGroupItem.value)
        # 节点类型
        item.setText(TreeColNum.colItem.value,nodeText)
        # 第1列
        item.setText(TreeColNum.colItemType.value, "Group")
        # 第2列
        item.setFlags(self.itemFlags)
        item.setCheckState(TreeColNum.colItem.value,Qt.Checked)
        item.setData(TreeColNum.colItem.value,Qt.UserRole,dirStr)  # 关联数据
        parItem.addChild(item)
        parItem.setExpanded(True)
        # 展开节点

    @pyqtSlot()  # 添加图片文件节点
    def on_actTree_AddFiles_triggered(self):
        fileList,flt = QFileDialog.getOpenFileNames(self,"选择一个或多个文件","","Images( *.jpg)")
        if (len(fileList) < 1):  # fileList是1list[str]
            return
        item = self.ui.treeWidget.currentItem()# 当前节点
        if (item.type() == TreeItemType.itImageItem.value):# 当前是图片节点
            parItem = item.parent()
        else:  # 否则取当前节点为父节点parItem=item
            parItem=item

        for i in range(len(fileList)):
            fullFileName = fileList[i]
            # 带路径文件名
            fileinfo = QFileInfo(fullFileName)
            nodeText = fileinfo.fileName()
            # 不带路径文件名
            item = QTreeWidgetItem(TreeItemType.itImageItem.value)
            # 节点类型
            item.setText(TreeColNum.colItem.value, nodeText)
            # 第1列的文字
            item.setText(TreeColNum.colItemType.value,"Image")
            # 第2列的文字
            item.setFlags(self.itemFlags)
            item.setCheckState(TreeColNum.colItem.value, Qt.Checked)
            item.setData(TreeColNum.colItem.value, Qt.UserRole, fullFileName)
            parItem.addChild(item)
            parItem.setExpanded(True)#展开节点

    def on_treeWidget_currentItemChanged(self, current, previous):
        if (current == None):
            return
        nodeType = current.type()# 获取节点类型
        if (nodeType == TreeItemType.itTopItem.value):# 顶层节点
            self.ui.actTree_AddFolder.setEnabled(True)
            self.ui.actTree_AddFiles.setEnabled(True)
            self.ui.actTree_DeleteItem.setEnabled(False)# 顶层节点不能删除
        elif (nodeType == TreeItemType.itGroupItem.value):  # 分组节点
            self.ui.actTree_AddFolder.setEnabled(True)
            self.ui.actTree_AddFiles.setEnabled(True)
            self.ui.actTree_DeleteItem.setEnabled(True)
        elif (nodeType == TreeItemType.itImageItem.value):  # 图片节点
            self.ui.actTree_AddFolder.setEnabled(False)
            self.ui.actTree_AddFiles.setEnabled(True)
            self.ui.actTree_DeleteItem.setEnabled(True)
            self.__displayImage(current)  # 显示图片

    @pyqtSlot()  ##删除当前节点
    def on_actTree_DeleteItem_triggered(self):
        item = self.ui.treeWidget.currentItem()
        parItem = item.parent()
        parItem.removeChild(item)

    @pyqtSlot()#遍历节点
    def on_actTree_ScanItems_triggered(self):
        count=self.ui.treeWidget.topLevelItemCount()
        for i in range(count) :
            item=self.ui.treeWidget.topLevelItem(i)
            self.__changeItemCaption(item)

    def __changeItemCaption(self, item):#递归调用函数,修改节点标题
        title="*"+item.text(TreeColNum.colItem.value)
        item.setText(TreeColNum.colItem.value,title)
        if (item.childCount()>0):
            for i in range(item.childCount()):
                self.__changeItemCaption(item.child(i))

    def __displayImage(self,item):##显示节点item的图片
        filename=item.data(TreeColNum.colItem.value,Qt.UserRole)
        self.ui.statusbar.showMessage(filename)
        #状态栏显示文件名
        self.curPixmap.load(filename)
        #原始图片
        self.on_actZoomFitH_triggered()
        #适合高度显示
        self.ui.actZoomFitH.setEnabled(True)
        self.ui.actZoomFitW.setEnabled(True)
        self.ui.actZoomIn.setEnabled(True)
        self.ui.actZoomOut.setEnabled(True)
        self.ui.actZoomRealSize.setEnabled(True)

    @pyqtSlot()  # 适应高度显示图片
    def on_actZoomFitH_triggered(self):
        H=self.ui.scrollArea.height()
        # 得到scrollArea的高度
        realH=self.curPixmap.height()
        # 原始图片的实际高度
        self.pixRatio=float(H)/realH# 当前显示比例,必须转换为浮点数
        pix = self.curPixmap.scaledToHeight(H-30)# 图片缩放到指定高度
        self.ui.label.setPixmap(pix)# 设置Labe1的PixMap

    @pyqtSlot()  ##适应宽度显示图片
    def on_actZoomFitW_triggered(self):
        W=self.ui.scrollArea.width()-20
        realW = self.curPixmap.width()
        self.pixRatio = float(W)/realW
        pix = self.curPixmap.scaledToWidth(W - 30)
        self.ui.label.setPixmap(pix)
        # 设置Label的PixMap

    @ pyqtSlot()  ##放大显示
    def on_actZoomIn_triggered(self):
        self.pixRatio = self.pixRatio * 1.2
        W=self.pixRatio * self.curPixmap.width()
        H=self.pixRatio * self.curPixmap.height()
        pix=self.curPixmap.scaled(W, H)# 图片缩放到指定高度和宽度,保持长宽比例
        self.ui.label.setPixmap(pix)

    @pyqtSlot()  ##缩小显示
    def on_actZoomOut_triggered(self):
        self.pixRatio = self.pixRatio * 0.8
        W = self.pixRatio * self.curPixmap.width()
        H=self.pixRatio * self.curPixmap.height()
        pix=self.curPixmap.scaled(W, H)# 图片缩放到指定高度和宽度, 保持长宽比例
        self.ui.label.setPixmap(pix)

    @pyqtSlot()
    ##实际大小
    def on_actZoomRealSize_triggered(self):
        self.pixRatio = 1  # 恢复显示比例为1
        self.ui.label.setPixmap(self.curPixmap)

    @pyqtSlot(bool)  ##设置停靠区浮动性
    def on_actDockFloat_triggered(self, checked):
        self.ui.dockWidget.setFloating(checked)

    @pyqtSlot(bool)  ##设置停靠区可见性
    def on_actDockVisible_triggered(self, checked):
        self.ui.dockWidget.setVisible(checked)

    @pyqtSlot(bool)  # 停靠区浮动性改变
    def on_dockWidget_topLevelChanged(self,topLevel):
        self.ui.actDockFloat.setChecked(topLevel)

    @pyqtSlot(bool)  ##停靠区可见性改变
    def on_dockWidget_visibilityChanged(self, visible):
        self.ui.actDockVisible.setChecked(visible)


if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyMainWindow() #创建窗体
    form.show()
    sys.exit(app.exec_())

5.appMain.py文件

## GUI应用程序主程序
import sys
from PyQt5.QtWidgets import  QApplication
from myWidget import  QmyMainWindow

app = QApplication(sys.argv) # 创建app,用QApplication类
myWidget = QmyMainWindow() #创建窗体
myWidget.show()
sys.exit(app.exec_())

6.最终效果图

image

image

image

image

image

image

image

image

image

image

posted @ 2022-05-28 10:11  司砚章  阅读(555)  评论(0编辑  收藏  举报