效果图:
目录和工具条的创建在前面几节就已经学过了,所以目录和工具条的布局可以自己画。
那么下面的部分,左侧是一个DockWidget,里面放置一个TreeWidget。右边是一个ScrollArea,里面放置一个Label,用来放置图片的。其他属性的设置可以按照自己的需求调节。
ui_treeWidget.py
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'ui_TreeWidget.ui' # # Created by: PyQt5 UI code generator 5.13.0 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1003, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) self.scrollArea.setGeometry(QtCore.QRect(0, 0, 721, 491)) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents = QtWidgets.QWidget() self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 719, 489)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.scrollAreaWidgetContents) self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.LabPicture = QtWidgets.QLabel(self.scrollAreaWidgetContents) self.LabPicture.setText("") self.LabPicture.setAlignment(QtCore.Qt.AlignCenter) self.LabPicture.setObjectName("LabPicture") self.horizontalLayout_2.addWidget(self.LabPicture) self.scrollArea.setWidget(self.scrollAreaWidgetContents) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1003, 21)) self.menubar.setObjectName("menubar") self.menu = QtWidgets.QMenu(self.menubar) self.menu.setObjectName("menu") self.menu_2 = QtWidgets.QMenu(self.menubar) self.menu_2.setObjectName("menu_2") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.toolBar = QtWidgets.QToolBar(MainWindow) font = QtGui.QFont() font.setPointSize(10) self.toolBar.setFont(font) self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.toolBar.setObjectName("toolBar") MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.dockWidget = QtWidgets.QDockWidget(MainWindow) self.dockWidget.setFeatures(QtWidgets.QDockWidget.AllDockWidgetFeatures) self.dockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea) self.dockWidget.setObjectName("dockWidget") self.dockWidgetContents = QtWidgets.QWidget() self.dockWidgetContents.setObjectName("dockWidgetContents") self.horizontalLayout = QtWidgets.QHBoxLayout(self.dockWidgetContents) self.horizontalLayout.setObjectName("horizontalLayout") self.treeWidget = QtWidgets.QTreeWidget(self.dockWidgetContents) self.treeWidget.setObjectName("treeWidget") self.treeWidget.headerItem().setText(0, "节点") self.treeWidget.headerItem().setTextAlignment(0, QtCore.Qt.AlignCenter) self.treeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignCenter) item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget) item_1 = QtWidgets.QTreeWidgetItem(item_0) item_2 = QtWidgets.QTreeWidgetItem(item_1) item_1 = QtWidgets.QTreeWidgetItem(item_0) item_2 = QtWidgets.QTreeWidgetItem(item_1) self.treeWidget.header().setDefaultSectionSize(150) self.horizontalLayout.addWidget(self.treeWidget) self.dockWidget.setWidget(self.dockWidgetContents) MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockWidget) self.actTree_AddFolder = QtWidgets.QAction(MainWindow) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("image/icon/AddFolder.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actTree_AddFolder.setIcon(icon) self.actTree_AddFolder.setObjectName("actTree_AddFolder") self.actTree_AddFiles = QtWidgets.QAction(MainWindow) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("image/icon/AddFiles.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actTree_AddFiles.setIcon(icon1) self.actTree_AddFiles.setObjectName("actTree_AddFiles") self.actZoomIn = QtWidgets.QAction(MainWindow) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap("image/icon/ZoomIn.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actZoomIn.setIcon(icon2) self.actZoomIn.setObjectName("actZoomIn") self.actZoomOut = QtWidgets.QAction(MainWindow) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap("image/icon/ZoomOut.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actZoomOut.setIcon(icon3) self.actZoomOut.setObjectName("actZoomOut") self.actZoomRealSize = QtWidgets.QAction(MainWindow) icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap("image/icon/ZoomRealSize.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actZoomRealSize.setIcon(icon4) self.actZoomRealSize.setObjectName("actZoomRealSize") self.actTree_DeleteItem = QtWidgets.QAction(MainWindow) icon5 = QtGui.QIcon() icon5.addPixmap(QtGui.QPixmap("image/icon/delete.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actTree_DeleteItem.setIcon(icon5) self.actTree_DeleteItem.setObjectName("actTree_DeleteItem") self.actZoomFitH = QtWidgets.QAction(MainWindow) icon6 = QtGui.QIcon() icon6.addPixmap(QtGui.QPixmap("image/icon/height.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actZoomFitH.setIcon(icon6) self.actZoomFitH.setObjectName("actZoomFitH") self.actZoomFitW = QtWidgets.QAction(MainWindow) icon7 = QtGui.QIcon() icon7.addPixmap(QtGui.QPixmap("image/icon/width.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actZoomFitW.setIcon(icon7) self.actZoomFitW.setObjectName("actZoomFitW") self.actTree_ScanItems = QtWidgets.QAction(MainWindow) icon8 = QtGui.QIcon() icon8.addPixmap(QtGui.QPixmap("image/icon/scanitem.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actTree_ScanItems.setIcon(icon8) self.actTree_ScanItems.setObjectName("actTree_ScanItems") self.actDockFloat = QtWidgets.QAction(MainWindow) self.actDockFloat.setCheckable(True) icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap("image/icon/dockfloat.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actDockFloat.setIcon(icon9) self.actDockFloat.setObjectName("actDockFloat") self.actDockVisible = QtWidgets.QAction(MainWindow) self.actDockVisible.setCheckable(True) icon10 = QtGui.QIcon() icon10.addPixmap(QtGui.QPixmap("image/icon/dockvisible.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actDockVisible.setIcon(icon10) self.actDockVisible.setObjectName("actDockVisible") self.actClose = QtWidgets.QAction(MainWindow) icon11 = QtGui.QIcon() icon11.addPixmap(QtGui.QPixmap("image/icon/quit.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actClose.setIcon(icon11) self.actClose.setObjectName("actClose") self.menu.addAction(self.actTree_AddFolder) self.menu.addAction(self.actTree_AddFiles) self.menu.addAction(self.actTree_DeleteItem) self.menu.addAction(self.actTree_ScanItems) self.menu.addSeparator() self.menu.addAction(self.actClose) self.menu_2.addAction(self.actZoomIn) self.menu_2.addAction(self.actZoomOut) self.menu_2.addAction(self.actZoomRealSize) self.menu_2.addSeparator() self.menu_2.addAction(self.actZoomFitH) self.menu_2.addAction(self.actZoomFitW) self.menubar.addAction(self.menu.menuAction()) self.menubar.addAction(self.menu_2.menuAction()) self.toolBar.addAction(self.actTree_AddFolder) self.toolBar.addAction(self.actTree_AddFiles) self.toolBar.addAction(self.actTree_DeleteItem) self.toolBar.addAction(self.actTree_ScanItems) self.toolBar.addSeparator() self.toolBar.addAction(self.actZoomIn) self.toolBar.addAction(self.actZoomOut) self.toolBar.addAction(self.actZoomRealSize) self.toolBar.addAction(self.actZoomFitW) self.toolBar.addAction(self.actZoomFitH) self.toolBar.addSeparator() self.toolBar.addAction(self.actDockFloat) self.toolBar.addAction(self.actDockVisible) self.toolBar.addSeparator() self.toolBar.addAction(self.actClose) self.retranslateUi(MainWindow) self.actClose.triggered.connect(MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.menu.setTitle(_translate("MainWindow", "目录树")) self.menu_2.setTitle(_translate("MainWindow", "视图")) self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) self.dockWidget.setWindowTitle(_translate("MainWindow", "图片目录树")) self.treeWidget.headerItem().setText(1, _translate("MainWindow", "节点类型")) __sortingEnabled = self.treeWidget.isSortingEnabled() self.treeWidget.setSortingEnabled(False) self.treeWidget.topLevelItem(0).setText(0, _translate("MainWindow", "图片文件")) self.treeWidget.topLevelItem(0).child(0).setText(0, _translate("MainWindow", "分组节点")) self.treeWidget.topLevelItem(0).child(0).child(0).setText(0, _translate("MainWindow", "图片节点")) self.treeWidget.topLevelItem(0).child(1).setText(0, _translate("MainWindow", "分组2")) self.treeWidget.topLevelItem(0).child(1).child(0).setText(0, _translate("MainWindow", "图片2")) self.treeWidget.setSortingEnabled(__sortingEnabled) self.actTree_AddFolder.setText(_translate("MainWindow", "添加目录...")) self.actTree_AddFolder.setToolTip(_translate("MainWindow", "添加目录")) self.actTree_AddFolder.setShortcut(_translate("MainWindow", "Ctrl+F")) self.actTree_AddFiles.setText(_translate("MainWindow", "添加文件...")) self.actTree_AddFiles.setToolTip(_translate("MainWindow", "添加文件")) self.actTree_AddFiles.setShortcut(_translate("MainWindow", "Ctrl+N")) self.actZoomIn.setText(_translate("MainWindow", "放大")) self.actZoomIn.setToolTip(_translate("MainWindow", "放大图片")) self.actZoomIn.setShortcut(_translate("MainWindow", "Ctrl+I")) self.actZoomOut.setText(_translate("MainWindow", "缩小")) self.actZoomOut.setToolTip(_translate("MainWindow", "缩小图片")) self.actZoomOut.setShortcut(_translate("MainWindow", "Ctrl+O")) self.actZoomRealSize.setText(_translate("MainWindow", "实际大小")) self.actZoomRealSize.setToolTip(_translate("MainWindow", "图片实际大小显示")) self.actTree_DeleteItem.setText(_translate("MainWindow", "删除节点")) self.actTree_DeleteItem.setToolTip(_translate("MainWindow", "删除节点")) self.actZoomFitH.setText(_translate("MainWindow", "适合高度")) self.actZoomFitH.setToolTip(_translate("MainWindow", "适合高度")) self.actZoomFitH.setShortcut(_translate("MainWindow", "Ctrl+H")) self.actZoomFitW.setText(_translate("MainWindow", "适合宽度")) self.actZoomFitW.setToolTip(_translate("MainWindow", "适合宽度")) self.actZoomFitW.setShortcut(_translate("MainWindow", "Ctrl+W")) self.actTree_ScanItems.setText(_translate("MainWindow", "遍历节点")) self.actTree_ScanItems.setToolTip(_translate("MainWindow", "遍历节点")) self.actDockFloat.setText(_translate("MainWindow", "窗体浮动")) self.actDockFloat.setToolTip(_translate("MainWindow", "窗体浮动")) self.actDockVisible.setText(_translate("MainWindow", "窗体可见")) self.actDockVisible.setToolTip(_translate("MainWindow", "窗体可见")) self.actClose.setText(_translate("MainWindow", "退出")) self.actClose.setToolTip(_translate("MainWindow", "退出"))
myMainWindow_TreeWidget.py
#!/usr/bin/env python # _*_ coding: UTF-8 _*_ """================================================= @Project -> File : Operate-system -> myMainWindow_QtreeWidget.py @IDE : PyCharm @Author : zihan @Date : 2020/4/17 8:50 @Desc : =================================================""" import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QTreeWidgetItem, QLabel, QFileDialog, QDockWidget from enum import Enum from PyQt5.QtGui import QIcon, QPixmap from PyQt5.QtCore import pyqtSlot, Qt, QDir, QFileInfo from ui_TreeWidget 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() self.ui.setupUi(self) self.curPixmap = QPixmap() # 图片 self.pixRatio = 1 # 显示比例 # 节点标志 self.itemFlags = Qt.ItemIsSelectable|Qt.ItemIsUserCheckable|Qt.ItemIsEnabled|Qt.ItemIsAutoTristate self.setCentralWidget(self.ui.scrollArea) self.__iniTree() # 添加目录节点 self.ui.actTree_AddFolder.triggered.connect(self.do_act_tree_add_folder_triggered) # 添加文件节点 self.ui.actTree_AddFiles.triggered.connect(self.do_act_tree_add_file_triggered) # 删除节点 self.ui.actTree_DeleteItem.triggered.connect(self.do_act_zoom_delete_item_triggered) # 遍历节点 self.ui.actTree_ScanItems.triggered.connect(self.do_act_tree_scan_item_triggered) # 目录树上当前节点变化时 self.ui.treeWidget.currentItemChanged.connect(self.do_tree_widget_current_item_changed) # 适应高度显示图片 self.ui.actZoomFitH.triggered.connect(self.do_act_zoom_fith_triggerd) # 适应宽度显示图片 self.ui.actZoomFitW.triggered.connect(self.do_act_zoom_fitw_triggered) # 放大显示 self.ui.actZoomIn.triggered.connect(self.do_act_zoom_in_triggered) # 缩小显示 self.ui.actZoomOut.triggered.connect(self.do_act_zoom_out_triggered) # 实际大小 self.ui.actZoomRealSize.triggered.connect(self.do_act_zoom_realsize_triggered) # 设置停靠区浮动性 self.ui.actDockFloat.triggered.connect(self.do_act_dock_float_triggered) # 设置停靠区可见性 self.ui.actDockVisible.triggered.connect(self.do_act_dock_visible_triggered) # 停靠区浮动性改变 self.ui.dockWidget.topLevelChanged.connect(self.do_dock_widget_toplevelchanged) # 停靠区可见性改变 self.ui.dockWidget.visibilityChanged.connect(self.do_dock_widget_visibilitychanged) def __iniTree(self): # 初始化目录树 self.ui.treeWidget.clear() icon = QIcon("./image/icon/pic.jpg") # 创建节点 item = QTreeWidgetItem(TreeItemType.itTopItem.value) item.setIcon(TreeColNum.colItem.value, icon) 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) # 添加目录节点 def do_act_tree_add_folder_triggered(self): dirStr = QFileDialog.getExistingDirectory() # 选择目录 if dirStr == "": return parItem = self.ui.treeWidget.currentItem() # 当前节点 if parItem is None: parItem = self.ui.treeWidget.topLevelItem(0) icon = QIcon("./image/icon/AddFolder.jpg") dirObj = QDir(dirStr) # QDir对象 nodeText = dirObj.dirName() # 最后一级目录的名称 item = QTreeWidgetItem(TreeItemType.itGroupItem.value) # 节点类型 item.setIcon(TreeColNum.colItem.value, icon) item.setText(TreeColNum.colItem.value, nodeText) # 第一列 item.setText(TreeColNum.colItemType.value, "Group") # 第二列 # 设置文字居中 item.setTextAlignment(TreeColNum.colItemType.value, Qt.AlignCenter) 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) # 添加文件节点 def do_act_tree_add_file_triggered(self): fileList, flt = QFileDialog.getOpenFileNames(self, "选择一个或多个文件", "", "Images(*.jpg)") if len(fileList) < 1: return item = self.ui.treeWidget.currentItem() # 当前节点 if item.type() == TreeItemType.itImageItem.value: parItem = item.parent() # 当前是图片节点 else: parItem = item icon = QIcon("./image/icon/onepic.jpg") for i in range(len(fileList)): fullFileName = fileList[i] # 带路径文件名 fileinfo = QFileInfo(fullFileName) nodeText = fileinfo.fileName() # 不带路径文件名 item = QTreeWidgetItem(TreeItemType.itImageItem.value) # 节点类型 item.setIcon(TreeColNum.colItem.value, icon) # 第一列的图标 item.setText(TreeColNum.colItem.value, nodeText) # 第一列的文字 item.setText(TreeColNum.colItemType.value, "Image") # 第二列的文字 # 设置文字居中 item.setTextAlignment(TreeColNum.colItemType.value, Qt.AlignCenter) 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 do_act_zoom_delete_item_triggered(self): item = self.ui.treeWidget.currentItem() parItem = item.parent() parItem.removeChild(item) # 遍历节点 def do_act_tree_scan_item_triggered(self): cout = self.ui.treeWidget.topLevelItemCount() for i in range(cout): 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 do_tree_widget_current_item_changed(self, current, previous): if current is 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) # 显示图片 def __displayImage(self, item): # 显示节点item的图片 filename = item.data(TreeColNum.colItem.value, Qt.UserRole) self.ui.statusbar.showMessage(filename) # 状态栏显示文件名 self.curPixmap.load(filename) # 原始图片 self.do_act_zoom_fith_triggerd() 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) # 适应高度显示图片 def do_act_zoom_fith_triggerd(self): H = self.ui.scrollArea.height() # 得到scrollArea的高度 realH = self.curPixmap.height() # 原始图片的实际高度 self.pixRatio = float(H) / realH # 当前显示比例,必须转换为浮点数 pix = self.curPixmap.scaledToHeight(H - 30) # 图片缩放到指定高度 self.ui.LabPicture.setPixmap(pix) # 设置Lable的PixMap # 适应宽度显示图片 def do_act_zoom_fitw_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.LabPicture.setPixmap(pix) # 放大显示 def do_act_zoom_in_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.LabPicture.setPixmap(pix) # 缩小显示 def do_act_zoom_out_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.LabPicture.setPixmap(pix) # 实际大小 def do_act_zoom_realsize_triggered(self): self.pixRatio = 1 self.ui.LabPicture.setPixmap(self.curPixmap) # 设置停靠区浮动性 @pyqtSlot(bool) def do_act_dock_float_triggered(self, checked): self.ui.dockWidget.setFloating(checked) # 设置停靠区可见性 @pyqtSlot(bool) def do_act_dock_visible_triggered(self, checked): self.ui.dockWidget.setVisible(checked) # 停靠区浮动性改变 @pyqtSlot(bool) def do_dock_widget_toplevelchanged(self, topLevel): self.ui.actDockFloat.setChecked(topLevel) # 停靠区可见性改变 @pyqtSlot(bool) def do_dock_widget_visibilitychanged(self, visible): self.ui.actDockVisible.setChecked(visible) if __name__ == "__main__": app = QApplication(sys.argv) # 创建app,用QApplication类 form = QmyMainWindow() form.show() sys.exit(app.exec_())
ok。
里面有一个方法,感觉还不错,就是把节点类型和目录树的列号都作为一个类,方便阅读,很清晰。