PyQt5-QTreeWidget和QDockWidget
1.设计的GUI界面为:
dockWidget和treeWidget采用栅格布局
2.对象查看器
3.动作编辑器
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.最终效果图
转载请注明出处,欢迎讨论和交流!