Я рисую виджет дерева и настраиваю список со множеством элементов в виджетах.Как отключить элемент в TreeWidget, запрограммированном в PYQT5
Элементы все проверены по умолчанию. Я хочу, чтобы всякий раз, когда элемент более высокого уровня не отмечен, все дети под этим элементом должны быть отключены. Моя программа успешно находит элементы, которые должны быть отключены, но функция (setDisabled) не работает. Я попробовал функцию (setHidden), но она также не работает.
from uitest import Ui_MainWindow
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel)
Menulevel1 = ["Action1", "Action2", "Action3"]
Menulevel2_1 = ["Action4", "Action6", "Action7"]
Menulevel3_1_1 = ["Action8", "Action9", "Action10"]
Menulevel3_1_2 = ["Action11", "Action12", "Action13"]
Menulevel3_1_3 = ["Action14", "Action15", "Action16"]
Menulevel2_2 = ["Action17", "Action18", "Action19"]
Menulevel3_2_1 = ["Action20", "Action21", "Action22"]
Menulevel3_2_2 = ["Action23", "Action24"]
Menulevel3_2_3 = [""]
Menulevel4_2_1_1 = ["Action25", "Action26", "Action27"]
Menulevel4_2_2_1 = ["Action28", "Action29", "Action30"]
Menulevel2_3 = ["Action31", "Action32", "Action33"]
Menulevel3_3_1 = ["Action34", "Action35", "Action36"]
Menulevel3_3_2 = ["Action37", "Action38", "Action39"]
Menulevel3_3_3 = [""]
class window(QMainWindow):
def __init__(self, parent=None):
super(window, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.treeload = False
self.changedact_name = "" # save the name of actions which will be dropped during trim process
self.changedact_dir = ""
self.changedact_pos = []
menutree = self.ui.Menutree # get the instance of tree widget
# check whether the tree has been set up before,
# if it has, there's no need to set up again (otherwise program will be stop)
if not self.treeload:
for i in range(len(Menulevel1)):
lvl1item = QTreeWidgetItem(menutree) # get the tree widget instance
lvl1item.setText(0, Menulevel1[i]) # set the first level text to be actions in menu level 1
# set up the first level elements to be a three state check box
# three state: checked, unchecked and partiallychecked, all used in handleItemChanged function
lvl1item.setFlags(lvl1item.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
# lvl1item.setDisabled(True)
lvl2 = eval("Menulevel2_%d" % (i + 1)) # set up a command for adding item of second level
for j in range(len(lvl2)): # loop to add menu level 2 action name
lvl2item = QTreeWidgetItem(lvl1item) # set up the parent level
# set up the child to be selectable
# If the child's checkbox isn't given a state, the checkbox element does not appear
lvl2item.setFlags(lvl2item.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
lvl2item.setText(0, lvl2[j]) # set up the item text to action name of menu level 2
lvl2item.setCheckState(0, Qt.Checked) # set the item default to checked
# set up a command for adding item of third level
lvl3 = eval("Menulevel3_%d_%d" % (i + 1, j + 1))
for k in range(len(lvl3)): # loop to add menu level 3 action name
if lvl3[k] is not "": # check whether there is action in menu level 3
lvl3item = QTreeWidgetItem(lvl2item) # set up the parent level
lvl3item.setFlags(lvl3item.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
lvl3item.setText(0, lvl3[k]) # set up the item text to action name of menu level 3
lvl3item.setCheckState(0, Qt.Checked) # set the item default to checked
# check whether the action is one of the first three actions, if it is,
# the action cannot be changed
try: # try add menu level 4 action name
# set up the command
lvl4 = eval("Menulevel4_%d_%d_%d" % (i + 1, j + 1, k + 1))
for l in range(len(lvl4)): # set up the loop
lvl4item = QTreeWidgetItem(lvl3item) # set up the parent
lvl4item.setFlags(lvl4item.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable)
lvl4item.setText(0, lvl4[l])
lvl4item.setCheckState(0, Qt.Checked)
except: # if there's no action in menu level 4
pass # continue the rest
menutree.expandAll() # expand all items on the tree
# put the tree load variable to true, whenever get in this section again there's no need to build tree again
# addition: whenever build the tree if try to build again, the program will
# stop at lvl1item.setText(0, Menulevel1_EN[i])
self.treeload = True
# whenever a checkbox is changed, handle item changed function will be called
# and the item will be determined
menutree.itemChanged.connect(self.handleItemChanged)
# the function to process changed check box in tree widget
def handleItemChanged(self, item, column):
if item.checkState(column) == Qt.Unchecked: # determine whether the checkbox of item is unchecked
self.changedact_name = item.text(column) + ";" # save the text of item (action name) in global variable
self.changedact_dir = "Drop" # set the change direction variable to drop - drop the action
# determine whether the checkbox of item is partiallychecked, usually the higher level will be the status
elif item.checkState(column) == Qt.PartiallyChecked:
# save the text of item (action name) in global variable, help determine which action is changed later
self.changedact_name += item.text(column) + ";"
elif item.checkState(column) == Qt.Checked: # determine whether the checkbox of item is unchecked
self.changedact_name += item.text(column) + ";" # save the text of item (action name) in global variable
# set the change direction variable to add - add the action which is dropped before
self.changedact_dir = "Add"
if item.text(column) in Menulevel1: # check whether the item reaches the menu level 1 - the top level
# actindex = Menulevel1_EN.index(item.text(column))
# call find changed action function to determine the status of which action is changed
self.findChangedAction()
self.changedact_name = "" # clear the variable for saving new changed item
self.changedact_dir = "" # clear the variable for saving new changed direction
def findChangedAction(self): # function of determining the status of which action is changed
changedactionlist = self.changedact_name.split(";") # using ; to separate the variable into list
changedaction = list(filter(None, changedactionlist)) #
changedaction.reverse()
length = len(changedaction) # determine the length of the list
# because the last item in the list is empty, the second last item will be the action in menu level 1
# determine the changed item is in which menu level
lvl1pos = Menulevel1.index(changedaction[0]) + 1
lvl2 = lvl3 = lvl4 = ""
lvl2pos = lvl3pos = lvl4pos = 0
if length >1:
lvl2 = eval("Menulevel2_%d" %lvl1pos)
lvl2pos = lvl2.index(changedaction[1])+1
try:
lvl3 = eval("Menulevel3_%d_%d" % (lvl1pos, lvl2pos))
lvl3pos = lvl3.index(changedaction[2]) + 1
try:
lvl4 = eval("Menulevel4_%d_%d_%d" % (lvl1pos, lvl2pos, lvl3pos))
lvl4pos = lvl4.index(changedaction[-1])+1
except:
pass
except:
pass
else:
lvl2 = ""
lvl2pos = 0
lvl3 = ""
lvl3pos = 0
lvl4 = ""
lvl4pos = 0
lvl2 = eval("Menulevel2_%d" %lvl1pos)
fullpos = lvl1pos * 1000 + lvl2pos * 100 + lvl3pos * 10 + lvl4pos
threepos = lvl1pos * 1000 + lvl2pos * 100 + lvl3pos * 10
twopos = lvl1pos * 1000 + lvl2pos * 100
onepos = lvl1pos * 1000
if fullpos == threepos and lvl4 != "":
for i in lvl4:
disableitem = self.ui.Menutree.findItems(i, Qt.MatchExactly | Qt.MatchRecursive, 0)
try:
disableitem.setDisabled(True)
except:
pass
elif fullpos == twopos and lvl3 != "":
for i in lvl3:
disableitem = self.ui.Menutree.findItems(i, Qt.MatchExactly | Qt.MatchRecursive, 0)
try:
disableitem.setDisabled(True)
except:
pass
if __name__ == "__main__":
app = QApplication([])
gui = window()
gui.show()
app.exec_()
И код UI здесь:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(816, 549)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 796, 440))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.verticalLayout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.Menutree = QtWidgets.QTreeWidget(self.scrollAreaWidgetContents)
self.Menutree.setObjectName("Menutree")
self.Menutree.header().setVisible(False)
self.verticalLayout.addWidget(self.Menutree)
spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
self.verticalLayout.addItem(spacerItem)
self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox.setTitle("")
self.groupBox.setObjectName("groupBox")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.Previous = QtWidgets.QPushButton(self.groupBox)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.Previous.setFont(font)
self.Previous.setObjectName("Previous")
self.horizontalLayout.addWidget(self.Previous)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.Next = QtWidgets.QPushButton(self.groupBox)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.Next.setFont(font)
self.Next.setObjectName("Next")
self.horizontalLayout.addWidget(self.Next)
spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem3)
self.Next_Save = QtWidgets.QPushButton(self.groupBox)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.Next_Save.setFont(font)
self.Next_Save.setObjectName("Next_Save")
self.horizontalLayout.addWidget(self.Next_Save)
spacerItem4 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem4)
self.verticalLayout.addWidget(self.groupBox)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.gridLayout.addWidget(self.scrollArea, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 816, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.TBlevel1 = QtWidgets.QToolBar(MainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.TBlevel1.sizePolicy().hasHeightForWidth())
self.TBlevel1.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(14)
self.TBlevel1.setFont(font)
self.TBlevel1.setObjectName("TBlevel1")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.TBlevel1)
self.TBlevel2 = QtWidgets.QToolBar(MainWindow)
font = QtGui.QFont()
font.setPointSize(12)
self.TBlevel2.setFont(font)
self.TBlevel2.setObjectName("TBlevel2")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.TBlevel2)
MainWindow.insertToolBarBreak(self.TBlevel2)
self.TBlevel3 = QtWidgets.QToolBar(MainWindow)
font = QtGui.QFont()
font.setPointSize(10)
self.TBlevel3.setFont(font)
self.TBlevel3.setObjectName("TBlevel3")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.TBlevel3)
MainWindow.insertToolBarBreak(self.TBlevel3)
self.TBlevel4 = QtWidgets.QToolBar(MainWindow)
self.TBlevel4.setObjectName("TBlevel4")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.TBlevel4)
MainWindow.insertToolBarBreak(self.TBlevel4)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Previous.setText(_translate("MainWindow", "Previous"))
self.Next.setText(_translate("MainWindow", "Next"))
self.Next_Save.setText(_translate("MainWindow", "Next and Save"))
self.TBlevel1.setWindowTitle(_translate("MainWindow", "toolBar"))
self.TBlevel2.setWindowTitle(_translate("MainWindow", "toolBar"))
self.TBlevel3.setWindowTitle(_translate("MainWindow", "toolBar_2"))
self.TBlevel4.setWindowTitle(_translate("MainWindow", "toolBar"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Я прочитал, что ответ (PyQt Tree Widget, adding check boxes for dynamic removal), прежде чем я прошу. Мой вопрос отличается от того, что, как я описал выше всякий раз, когда я снял флажок с родительского элемента, я хочу отключить его дочерние элементы. Я действительно использовал parent.setCheckState (0, Qt.Unchecked), но всякий раз, когда я узнаю, какой родительский элемент не отмечен, и попытайтесь отключить детей, моя программа всегда разбилась. Я не знаю почему. Поэтому я отправляю свой код и прошу помощи. Кто-нибудь может мне помочь? Спасибо!
Возможный дубликат [PyQt Tree Widget, добавление флажков для динамического удаления] (http://stackoverflow.com/questions/31342228/pyqt-tree-widget-adding-check-boxes-for-dynamic-removal) – ekhumoro
Спасибо за информацию. Я прочитал этот ответ, прежде чем спросить. Мой вопрос отличается от того, что, как я описал выше всякий раз, когда я снял флажок с родительского элемента, я хочу отключить его дочерние элементы. Я действительно использовал parent.setCheckState (0, Qt.Unchecked), но всякий раз, когда я узнаю, какой родительский элемент не отмечен, и попытайтесь отключить детей, моя программа всегда разбилась. Я не знаю почему. Поэтому я отправляю свой код и прошу помощи. – Zhentao