Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Solved QStandardItemModel doesn't update QTableView

    Qt for Python
    pyside python qt for python
    2
    6
    79
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      demberto last edited by demberto

      class EventsTableModel(QStandardItemModel):
          EVENT = 1000
      
          def __init__(self, et: EventTree, show_only: list[EventEnum]) -> None:
              super().__init__(None)
              self.et = et
              self.events = tuple(et.get(*show_only))
              self.set_horizontal_header_labels(["ID", "Value"])
      
              for event in self.events:
                  id_item = QStandardItem(str(event.id))
                  id_item.set_editable(False)
                  val_item = QStandardItem()
                  val_item.set_data(event, self.EVENT)
      
                  try:
                      val_item.set_data(event.value, Qt.ItemDataRole.DisplayRole)
                  except NotImplementedError:
                      continue
                  self.append_row((id_item, val_item))
      
          def set_data(self, index: QModelIndex, value, role: int = ...) -> bool:
              event = index.data(self.EVENT)
              try:
                  event.value = value
              except Exception as exc:
                  logging.exception(exc)
                  return False
              else:
                  self.dataChanged.emit(index, index)  # type: ignore
                  return True
      

      When I try to enter a new value in a cell's editor and press Enter, the new value doesn't appear in the cell. This occurs even if there are no exceptions.

      I am using a normal QTableView instance for this model. The data gets correctly displayed initially after loading.

      PySide: 6.4.2

      EDIT: Fixed it by adding this line before emitting dataChanged :

      self.item_from_index(index).set_data(value, Qt.ItemDataRole.DisplayRole)
      
      JonB 1 Reply Last reply Reply Quote 0
      • Topic has been marked as solved  D demberto 
      • JonB
        JonB @demberto last edited by JonB

        @demberto
        Your set_data() method does not use the role parameter passed to it, which it should, or you should not have it accept such a parameter.
        If you do make it use the parameter, you should be passing Qt.ItemDataRole.EditRole not DisplayRole.

        D 1 Reply Last reply Reply Quote 0
        • D
          demberto @JonB last edited by demberto

          @JonB Do you mean the place where I call self.item_from_index(index).set_data(value, Qt.ItemDataRole.DisplayRole)?

          OR do you mean this?

          def set_data(self, index: QModelIndex, value, role: int = ...) -> bool:
                  event = index.data(self.EVENT)
                  try:
                      event.value = value
                  except Exception as exc:
                      logging.exception(exc)
                      return False
                  else:
                      self.item_from_index(index).set_data(value, role)
                      self.dataChanged.emit(index, index)  # type: ignore
                      return True
          

          EDIT: That works
          I still don't understand why I have to call self.item_from_index(index).set_data(value, role) explicitly. Isn't that what set_data mechanism is supposed to do internally, or I should call super-class set_data in my else clause?

          JonB 1 Reply Last reply Reply Quote 0
          • JonB
            JonB @demberto last edited by JonB

            @demberto
            Yes, you should call base QStandardItemModel.setData() to handle the case you don't.

            Your code is bad for the normal, successful case. You do not return True, you just drop off the end of the method and Python will doubtless return None/False, could be a problem.

            The base setData() defaults role = EditRole for the parameter. You really ought do so too.

            Where you call it you show self.item_from_index(index).set_data(value, Qt.ItemDataRole.DisplayRole). That should really be EditRole, or you can omit it if you change to default as per previous point.

            D 1 Reply Last reply Reply Quote 1
            • D
              demberto @JonB last edited by

              @JonB Finally:

              Your code is bad for the normal, successful case. You do not return True, you just drop off the end of the method and Python will doubtless return None/False, could be a problem.

              def set_data(self, index: QModelIndex, value, role: int = Qt.ItemDataRole.EditRole) -> bool:
                      event = index.data(self.EVENT)
                      try:
                          event.value = value
                      except Exception as exc:
                          logging.exception(exc)
                          return False
                      else:
                          super().set_data(index, value, role)
                      return True
              

              Thanks!

              JonB 1 Reply Last reply Reply Quote 1
              • JonB
                JonB @demberto last edited by

                @demberto
                No need for else: IMHO :) Now you hide if the base class setData() were to fail. To me

                return super().set_data(index, value, role)
                

                as the final line makes sense.

                1 Reply Last reply Reply Quote 2
                • First post
                  Last post