【问题标题】:How to avoid QListWidget list item being reset when adding new item?添加新项目时如何避免 QListWidget 列表项被重置?
【发布时间】:2020-03-02 15:54:43
【问题描述】:

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

另外,另一个 gif 显示代码在其他方面可以正常工作:

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

谁能提出解决这个问题的方法?

代码:

我在我的 GUI 类的 init 函数中声明了以下信号:

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)


【问题讨论】:

    标签: python pyqt pyqt5 qlistwidget


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      当前行为是预期行为。

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

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

      【讨论】:

      • 谢谢ypnos。是的 - 我对使用自定义委托并不感兴趣,而且我不介意每次击键都不会提交更改。但是,如果用户正在编辑它,我希望单击“添加”按钮会将更改提交到列表项。我已经在 ekhumoros 回答下评论了我在上面的尝试。
      • 更晦涩难懂,坦率地说,只有委托接收自定义信号来提交,您可以通过自己跟踪焦点事件在焦点更改之前触发它......总而言之,没有什么令人愉快的做。
      • @ypnos 实际上,它比这简单得多。一旦按钮不再获得焦点,就可以在列表小部件上显式设置焦点,这将依次提交项目编辑器中的数据(如果打开的话)。也可以连接到 item-delegate 以强制它提交其数据,但我认为在这种特殊情况下没有必要。
      • 有趣!很棒的方法!
      【解决方案3】:

      您可以通过将按钮的setting the focus policy 修复为NoFocus。这允许项目编辑器在单击按钮时保持打开状态(因为它们不会窃取焦点)。然后可以使用列表小部件的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_())
      

      【讨论】:

      • 谢谢 ekhumoro。这很棒,但如果用户正在编辑,如果单击“添加”按钮将提交更改,我会非常喜欢它。我试图通过在单击“添加”按钮时更改焦点来实现这一点,但我认为它需要多线程才能工作,因为否则它将继续添加新的列表项并在 itemChanged 信号/插槽被触发之前刷新列表。使用多线程来解决这个问题似乎很麻烦,所以我希望有一个更明显的方法。
      • 不能在多个线程中更改 Qt GUI。当您进行 GUI 操作时,您必须停留在一个线程中。
      • @Hol3yMol3y 我已经更新了我的答案,以便它以你想要的方式工作。不需要多线程或任何其他类似的复杂情况。
      • 太棒了!这完美地工作,是一个如此简单的解决方案。非常感谢。
      猜你喜欢
      • 1970-01-01
      • 2021-05-08
      • 2021-07-26
      • 1970-01-01
      • 1970-01-01
      • 2018-11-12
      • 1970-01-01
      • 2015-10-14
      • 1970-01-01
      相关资源
      最近更新 更多