更改 QTreeWidgetItem 标志时防止递归
Posted
技术标签:
【中文标题】更改 QTreeWidgetItem 标志时防止递归【英文标题】:Prevent recursion when changing QTreeWidgetItem flags 【发布时间】:2021-12-18 19:38:53 【问题描述】:我正在尝试制作一个非常基本的密码管理器,但在尝试编辑项目时遇到了问题。当按下“编辑密码”按钮时,它会使当前选定的项目可编辑,我希望在用户完成修改后将其删除。试图删除标志ItemIsEditable
会导致它在item.setFlags(item.flags() & ~Qt.ItemIsEditable)
行上进入无限递归。
# app class -------------------------------------------------------------------------- #
class App(QApplication):
# initialisation ----------------------------------------------------------------- #
def __init__(self, argv):
super().__init__(argv)
self.__ready = False
self.__setup__()
self.__load_data__()
self.__ready = True
# private methods ---------------------------------------------------------------- #
def __load_data__(self):
self.data_tree.headerItem().setText(0, "Client")
self.data_tree.headerItem().setText(1, "Workstation")
self.data_tree.headerItem().setText(2, "Login")
self.data_tree.headerItem().setText(3, "Password")
for level_1, client in enumerate(self.data["clients"]):
row_1 = QTreeWidgetItem(self.data_tree)
self.data_tree.topLevelItem(level_1).setText(0, client["name"])
for level_2, workstation in enumerate(client["workstations"]):
row_2 = QTreeWidgetItem(row_1)
self.data_tree.topLevelItem(level_1).child(level_2).setText(
1, workstation["name"]
)
for level_3, login in enumerate(workstation["logins"]):
row_3 = QTreeWidgetItem(row_2)
row_3.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
self.data_tree.topLevelItem(level_1).child(level_2).child(
level_3
).setText(2, login["username"])
self.data_tree.topLevelItem(level_1).child(level_2).child(
level_3
).setText(3, login["password"])
self.data_tree.setSortingEnabled(True)
def __setup__(self):
self.data = pd.read_json("list.json")
self.main_window = QMainWindow()
self.central_widget = QWidget(self.main_window)
self.data_tree = QTreeWidget(self.central_widget)
self.edit_password_button = QPushButton(self.central_widget)
self.central_widget.setGeometry(QRect(0, 0, 500, 500))
self.central_widget.setObjectName("central_widget")
self.data_tree.itemChanged.connect(self.save_password)
self.data_tree.setGeometry(QRect(0, 0, 500, 450))
self.data_tree.setObjectName("data_tree")
self.data_tree.sortByColumn(0, Qt.SortOrder.AscendingOrder)
self.main_window.setCentralWidget(self.central_widget)
self.main_window.setGeometry(QRect(200, 200, 500, 500))
self.main_window.setWindowTitle("Password Manager")
self.main_window.show()
self.edit_password_button.clicked.connect(self.edit_password)
self.edit_password_button.setGeometry(QRect(345, 455, 150, 40))
self.edit_password_button.setText("Edit Password")
# events ------------------------------------------------------------------------- #
@pyqtSlot()
def edit_password(self):
try:
item = self.data_tree.currentItem()
item.setFlags(item.flags() | Qt.ItemIsEditable)
self.data_tree.scrollToItem(item)
self.data_tree.editItem(item, 3)
except Exception as e:
print(e)
@pyqtSlot(QTreeWidgetItem, int)
def save_password(self, item, column):
if not self.__ready:
return
for client in self.data["clients"]:
if client["name"] == item.parent().parent().text(0):
for workstation in client["workstations"]:
if workstation["name"] == item.parent().text(1):
for login in workstation["logins"]:
if login["username"] == item.text(2):
login["password"] = item.text(3)
with open("list.json", "w") as file:
json.dump(json.loads(self.data.to_json()), file, indent=4)
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
def simulate_password(self):
keyboard.write(self.data_tree.currentItem().text(3))
def test_func(self):
print("test")
app = App(sys.argv)
keyboard.add_hotkey("ctrl+insert", app.simulate_password)
sys.exit(app.exec())
【问题讨论】:
【参考方案1】:itemChanged signal 是针对项目的所有 更改发出的,而不仅仅是其文本。为避免递归,您可以在设置标志时暂时阻止信号,这样save_password
插槽就不会再次被触发:
@pyqtSlot()
def edit_password(self):
item = self.data_tree.currentItem()
blocked = item.treeWidget().blockSignals(True)
item.setFlags(item.flags() | Qt.ItemIsEditable)
item.treeWidget().blockSignals(blocked)
self.data_tree.scrollToItem(item)
self.data_tree.editItem(item, 3)
@pyqtSlot(QTreeWidgetItem, int)
def save_password(self, item, column):
...
blocked = item.treeWidget().blockSignals(True)
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
item.treeWidget().blockSignals(blocked)
【讨论】:
添加此项可防止崩溃,但现在也可防止该字段可编辑。 对不起,让我详细说明一下。这些项目不能通过双击它们或类似的东西来编辑,只能通过单击按钮。为了做到这一点,他们最初都没有itemIsEditable
,但是当按下按钮时,它使他们可以编辑,直到用户完成编辑,然后他们删除了标志。
非常感谢。你是人间的神。以上是关于更改 QTreeWidgetItem 标志时防止递归的主要内容,如果未能解决你的问题,请参考以下文章