添加新项时如何避免 QListWidget 列表项被重置?

How to avoid QListWidget list item being reset when adding new item?

我有一个带有 QListWidget 的 GUI,它以没有条目开头。使用 "add" 按钮添加条目。我遇到的问题是,当您编辑列表项的文本时,如果您在按回车键或单击离开之前再次单击添加按钮,您输入的文本将被删除(参见 gif 以供参考)

此外,另一个 gif 显示代码以其他方式工作:

问题是它不会保存您每次​​击键时输入的内容。它会等到您完成并更改选择或按下回车键。

任何人都可以提出解决此问题的方法吗?

代码:

我在 GUI 的初始化函数中声明了以下信号 class:

self.w_client_list.itemChanged.connect(self.edit_client_name)
self.w_client_list.itemSelectionChanged.connect(self.switching_clients)
self.b_add_client.clicked.connect(self.add_client)

这些是信号连接到的槽函数:

    def get_index(self):
        """Gets index number of selected client for client details functions"""
        for i in range(self.w_client_list.count()):
            if self.w_client_list.item(i).isSelected():
                index = i
                return index
        index = None
        return index

    @Slot()
    def switching_clients(self):
        index = self.get_index()
        if index == None:
            self.l_email.clear()
            self.c_main_email.setCheckState(Qt.Unchecked)
            self.c_secondary_email.setCheckState(Qt.Unchecked)
            self.w_phone.clear()
            self.l_preferred_name.clear()
            self.w_title.setCurrentText('Mr')
        else:
            # Email
            self.l_email.setText(self.client.individual[index]['email'][0])
            self.c_main_email.setChecked(self.client.individual[index]['email'][1])
            self.c_secondary_email.setChecked(self.client.individual[index]['email'][2])
            # Phone
            self.update_phone_list()
            # Preferred Name
            self.l_preferred_name.setText(self.client.individual[index]['preferred_name'])
            # Title
            self.w_title.setCurrentText(self.client.individual[index]['title'])

    @Slot()
    def edit_client_name(self):
        index = self.get_index()
        self.client.individual[index]['full_name'] = self.w_client_list.item(index).text().strip()
        self.switching_clients()

    @Slot()
    def add_client(self):
        self.client.individual.append({'title': 'Mr', 'first_name': '', 'middle_name': '', 'last_name': '',
                                        'full_name': 'Enter full name',
                                        'preferred_name': '', 'salutation': '', 'postal_salutation': '',
                                        'email': ['', 0, 0], 'address': [], 'phone': [],
                                        'preferred_name_connected': True})
        self.update_client_list()  # Updates the client form to show new address row

    def update_client_list(self):
        self.w_client_list.clear()
        client_list = []
        for client in self.client.individual:
            item = QtWidgets.QListWidgetItem()
            item.setText(client['full_name'])
            item.setFlags(
                QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled)
            self.w_client_list.addItem(item)
        item.setSelected(True)


我要做的是,当用户单击 "add" 时,程序首先通过比较 "old" 字符串来验证条目是否已更改。 和新的。如果是,它将保存新字符串并将其设置为小部件。否则它只会添加新条目。我希望这可以引导您找到解决方案。

当前行为是预期行为。

您正确地识别了罪魁祸首:编辑更改需要用户提交,中断编辑过程将取消它。如果您希望立即应用更改,您需要一个自定义委托来实现您的替代行为。 (有关自定义委托的工作方式,请参阅 this example in Qt docs)。

请注意,像这样改变基本 UI 行为会被强烈忽略。您的应用程序看起来与任何其他应用程序一样,但与其他应用程序的行为略有不同。在UI的世界里,通常一致性才是王道。自定义此类行为也会产生无法预料的副作用,尤其是当您针对多个平台时。而且需要维护的是很多额外的代码。

您可以通过 setting the focus policy of the buttons to NoFocus. This allows the item-editor to stay open when the buttons are clicked (because they won't steal the focus). The list-widget's isPersistentEditorOpen 方法修复此问题,然后可用于防止用户仍在编辑时进行不必要的操作。

更新:

如果您想在添加新项目时提交当前编辑,只需在列表小部件上调用 setFocus(因为按钮不会抢走焦点)。这也意味着不再需要按照上面的建议检查项目编辑器是否打开。


这是一个基于您的代码的工作演示:

import sys
from PyQt5 import QtCore, QtWidgets

class Client:
    individual = []

class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.client = Client()
        self.b_add_client = QtWidgets.QPushButton('Add')
        self.b_add_client.setFocusPolicy(QtCore.Qt.NoFocus)
        self.w_client_list = QtWidgets.QListWidget()
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.w_client_list)
        layout.addWidget(self.b_add_client)
        self.w_client_list.itemChanged.connect(self.edit_client_name)
        self.b_add_client.clicked.connect(self.add_client)

    def get_index(self):
        selection = self.w_client_list.selectedItems()
        if selection:
            return self.w_client_list.indexFromItem(selection[0]).row()

    def switching_clients(self):
        pass

    def edit_client_name(self):
        index = self.get_index()
        if index is not None:
            text = self.w_client_list.item(index).text().strip()
            if text:
                self.client.individual[index]['full_name'] = text
        self.switching_clients()

    def add_client(self):
        self.w_client_list.setFocus()
        self.client.individual.append({
            'title': 'Mr', 'first_name': '', 'middle_name': '',
            'last_name': '', 'full_name': 'Enter full name',
            'preferred_name': '', 'salutation': '',
            'postal_salutation': '', 'email': ['', 0, 0],
            'address': [], 'phone': [],
            'preferred_name_connected': True,
            })
        self.update_client_list()

    def update_client_list(self):
        if len(self.client.individual):
            self.w_client_list.clear()
            for client in self.client.individual:
                item = QtWidgets.QListWidgetItem()
                item.setText(client['full_name'])
                item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
                self.w_client_list.addItem(item)
            item.setSelected(True)
            self.w_client_list.editItem(item)

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(600, 100, 300, 200)
    window.show()
    sys.exit(app.exec_())