Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. tableView not updated after calling dataChanged
Forum Updated to NodeBB v4.3 + New Features

tableView not updated after calling dataChanged

Scheduled Pinned Locked Moved Solved Qt for Python
12 Posts 2 Posters 5.7k Views
  • 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.
  • Carlos DiazC Offline
    Carlos DiazC Offline
    Carlos Diaz
    wrote on last edited by
    #1

    Hi

    I'm doing a toy project to understand the QAbstractTableModel and display it's data into a tableView widget. I have been reading some of the old posts here but most of them aren't solved.

    Expected:
    At the begginning i expect the string '0x0800C000' being displayed on column 0, row 0, after pressing the button I remove all the rows to clean the view and after that have the following list displayed on column 0, each element on it's own row: '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014'.

    What I get:
    The first string is properly displayed, the rows are being removed but the view isn't being updated.

    Here's what I have tried so far:

    #!/usr/bin/env python3
    
    from fbs_runtime.application_context.PySide2 import ApplicationContext
    
    from PySide2.QtCore import *
    from PySide2.QtWidgets import *
    from PySide2.QtGui import QIntValidator
    from PySide2.QtUiTools import QUiLoader
    
    import sys
    
    class TestModel(QAbstractTableModel):
        def __init__(self):
            QAbstractTableModel.__init__(self)
            
            # Here we keep the data
            self.display = []
    
        def rowCount(self, parent=QModelIndex()):
            return len(self.display)
    
        def columnCount(self, parent=QModelIndex()):
            return 1
    
        def setData(self, index, value, role=Qt.EditRole):
            '''
            Adjust the data (set it to value <value>) depending on the given index
            and role
            '''
    
            if role != Qt.EditRole:
                return False
    
            if index.isValid() and 0 <= index.row():
                print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column{index.column()}')
                if index.column() == 0:
                    self.display.append(value)
                else:
                    return False
                
                print(f'data changed signal')
                # Let Qt know there's new data to be displayed
                self.dataChanged.emit(index, index)
                return True
    
            return False
    
        def flags(self, index):
            '''
            Set the item flags at the given index. Seems like we're implementing
            this function just to see ho it's done, as we manually adjust each
            tableView to have NoEditTriggers.
            '''
            if not index.isValid():
                return Qt.ItemIsEnabled
            return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
    
        def insertRows(self, position, rows=1, index=QModelIndex()):
            '''
            Insert a row from the model.
            '''
            
            self.beginInsertRows(QModelIndex(), position, position + rows - 1)
    
            self.endInsertRows()
    
            return True
    
        def removeRows(self, position, rows=1, index=QModelIndex()):
            '''
            Remove a row from the model.
            '''
            
            self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
    
            print(self.display)
            
            print(f'Removing {rows} rows from {position} to {position+rows}')
            del self.display[position:position+rows]
    
            print(self.display)
    
            self.endRemoveRows()
    
            return True
    
        def insertColumns(self, column, count, parent):
            pass
    
        def removeColumns(self):
            pass
    
        def data(self, index, role=Qt.DisplayRole):
    
            if not index.isValid():
                return None
            
            if role != Qt.DisplayRole and role != Qt.EditRole:
                return None
    
            column = index.column()
            row = index.row()
    
            print(f'[DATA] Column: {column}; Row: {row}')
            
            if column == 0:
                return self.display[index.row()]
            else:
                return None
    
        def headerData(self, section, orientation, role):
            if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                if section == 0:
                    return 'Address'
    
    class AppContext(ApplicationContext):
        def run(self):
    
            self.app.setStyle('Fusion')
    
            ui_file = self.get_resource("mainwindow.ui")
            self.file = QFile(ui_file)
            self.file.open(QFile.ReadOnly)
            self.loader = QUiLoader()
            self.window = self.loader.load(self.file)
    
            self.window.updateView.clicked.connect(self.onUpdateView)
    
            self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
    
            self.model = TestModel()
    
            first_index = self.model.createIndex(0, 0)
    
            self.model.setData(first_index, self.address_list[0], Qt.EditRole)
    
            self.window.tableView.setModel(self.model)
            self.window.tableView.show()
            
            print(self.model.rowCount())
    
            # Show the application to the user        
            self.window.show()
            return self.app.exec_()
    
        def onUpdateView(self):
    
            current_rows = self.model.rowCount()
    
            print(f'Updating view, removing {current_rows} rows')
            self.model.removeRows(0, current_rows)
    
            current_rows = self.model.rowCount()
            print(f'Currently we have {current_rows} rows')
            
            row = 0
            for address in self.address_list:
                idx = self.model.createIndex(row, 0)
                self.model.setData(idx, address, Qt.EditRole)
                row += 1
            
            current_rows = self.model.rowCount()
            print(f'Currently we have {current_rows} rows')
    
    if __name__ == '__main__':
        appctxt = AppContext()
        exit_code = appctxt.run()
        sys.exit(exit_code)
    

    The tableView starts like this:
    Table view when launching the application: https://imgur.com/eIfwwxm

    After pressing the button i get the following log data:

    [SET_DATA] DATA: 0x0800C000 index row: 0; column0
    data changed signal
    [SET_DATA] DATA: 0x0800C004 index row: 1; column0
    data changed signal
    [SET_DATA] DATA: 0x0800C008 index row: 2; column0
    data changed signal
    [SET_DATA] DATA: 0x0800C00C index row: 3; column0
    data changed signal
    [SET_DATA] DATA: 0x0800C010 index row: 4; column0
    data changed signal
    [SET_DATA] DATA: 0x0800C014 index row: 5; column0
    data changed signal
    Currently we have 6 rows
    

    So the data is being inserted in the self.display list.
    But the widget looks still empty: https://imgur.com/moPD7x3

    You can find the complete repo here, I'm using fbs for the application so you should clone the repo, enter the cloned directory and do fbs run to get it running.

    Regards

    JonBJ 1 Reply Last reply
    0
    • Carlos DiazC Carlos Diaz

      After taking a closer look at the log we can see the method data isn't being called after setData.

      [SET_DATA] DATA: 0x0800C000 index row: 0; column 0 # Here i load the first item of the list into the model
      data changed signal
      ['0x0800C000']
      Setting model
      Showing model
      [DATA] Column: 0; Row: 0 # Here the data method is being called
      0x0800C000
      [DATA] Column: 0; Row: 0
      0x0800C000
      Updating view, removing 1 rows
      ['0x0800C000']
      Removing 1 rows from 0 to 1
      []
      Currently we have 0 rows
      [SET_DATA] DATA: 0x0800C000 index row: 0; column 0 # Updating the data in the model, but the data method isn't being called after this
      data changed signal
      ['0x0800C000']
      [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
      data changed signal
      ['0x0800C000', '0x0800C004']
      [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
      data changed signal
      ['0x0800C000', '0x0800C004', '0x0800C008']
      [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
      data changed signal
      ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
      [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
      data changed signal
      ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
      [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
      data changed signal
      ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
      Currently we have 6 rows
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #4

      @Carlos-Diaz
      As I said above.

      I believe you will find your problem is because: having removed all rows via removeRows() you simply use setData() to put stuff into the model rows. You do not call insertRows(). If that is not called, the view won't get the signal and know there are any new rows.

      Put a debug in to show it's not being called. Then put in calls during your address population loop, and see how the view looks.

      1 Reply Last reply
      0
      • Carlos DiazC Carlos Diaz

        Hi

        I'm doing a toy project to understand the QAbstractTableModel and display it's data into a tableView widget. I have been reading some of the old posts here but most of them aren't solved.

        Expected:
        At the begginning i expect the string '0x0800C000' being displayed on column 0, row 0, after pressing the button I remove all the rows to clean the view and after that have the following list displayed on column 0, each element on it's own row: '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014'.

        What I get:
        The first string is properly displayed, the rows are being removed but the view isn't being updated.

        Here's what I have tried so far:

        #!/usr/bin/env python3
        
        from fbs_runtime.application_context.PySide2 import ApplicationContext
        
        from PySide2.QtCore import *
        from PySide2.QtWidgets import *
        from PySide2.QtGui import QIntValidator
        from PySide2.QtUiTools import QUiLoader
        
        import sys
        
        class TestModel(QAbstractTableModel):
            def __init__(self):
                QAbstractTableModel.__init__(self)
                
                # Here we keep the data
                self.display = []
        
            def rowCount(self, parent=QModelIndex()):
                return len(self.display)
        
            def columnCount(self, parent=QModelIndex()):
                return 1
        
            def setData(self, index, value, role=Qt.EditRole):
                '''
                Adjust the data (set it to value <value>) depending on the given index
                and role
                '''
        
                if role != Qt.EditRole:
                    return False
        
                if index.isValid() and 0 <= index.row():
                    print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column{index.column()}')
                    if index.column() == 0:
                        self.display.append(value)
                    else:
                        return False
                    
                    print(f'data changed signal')
                    # Let Qt know there's new data to be displayed
                    self.dataChanged.emit(index, index)
                    return True
        
                return False
        
            def flags(self, index):
                '''
                Set the item flags at the given index. Seems like we're implementing
                this function just to see ho it's done, as we manually adjust each
                tableView to have NoEditTriggers.
                '''
                if not index.isValid():
                    return Qt.ItemIsEnabled
                return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
        
            def insertRows(self, position, rows=1, index=QModelIndex()):
                '''
                Insert a row from the model.
                '''
                
                self.beginInsertRows(QModelIndex(), position, position + rows - 1)
        
                self.endInsertRows()
        
                return True
        
            def removeRows(self, position, rows=1, index=QModelIndex()):
                '''
                Remove a row from the model.
                '''
                
                self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
        
                print(self.display)
                
                print(f'Removing {rows} rows from {position} to {position+rows}')
                del self.display[position:position+rows]
        
                print(self.display)
        
                self.endRemoveRows()
        
                return True
        
            def insertColumns(self, column, count, parent):
                pass
        
            def removeColumns(self):
                pass
        
            def data(self, index, role=Qt.DisplayRole):
        
                if not index.isValid():
                    return None
                
                if role != Qt.DisplayRole and role != Qt.EditRole:
                    return None
        
                column = index.column()
                row = index.row()
        
                print(f'[DATA] Column: {column}; Row: {row}')
                
                if column == 0:
                    return self.display[index.row()]
                else:
                    return None
        
            def headerData(self, section, orientation, role):
                if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                    if section == 0:
                        return 'Address'
        
        class AppContext(ApplicationContext):
            def run(self):
        
                self.app.setStyle('Fusion')
        
                ui_file = self.get_resource("mainwindow.ui")
                self.file = QFile(ui_file)
                self.file.open(QFile.ReadOnly)
                self.loader = QUiLoader()
                self.window = self.loader.load(self.file)
        
                self.window.updateView.clicked.connect(self.onUpdateView)
        
                self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
        
                self.model = TestModel()
        
                first_index = self.model.createIndex(0, 0)
        
                self.model.setData(first_index, self.address_list[0], Qt.EditRole)
        
                self.window.tableView.setModel(self.model)
                self.window.tableView.show()
                
                print(self.model.rowCount())
        
                # Show the application to the user        
                self.window.show()
                return self.app.exec_()
        
            def onUpdateView(self):
        
                current_rows = self.model.rowCount()
        
                print(f'Updating view, removing {current_rows} rows')
                self.model.removeRows(0, current_rows)
        
                current_rows = self.model.rowCount()
                print(f'Currently we have {current_rows} rows')
                
                row = 0
                for address in self.address_list:
                    idx = self.model.createIndex(row, 0)
                    self.model.setData(idx, address, Qt.EditRole)
                    row += 1
                
                current_rows = self.model.rowCount()
                print(f'Currently we have {current_rows} rows')
        
        if __name__ == '__main__':
            appctxt = AppContext()
            exit_code = appctxt.run()
            sys.exit(exit_code)
        

        The tableView starts like this:
        Table view when launching the application: https://imgur.com/eIfwwxm

        After pressing the button i get the following log data:

        [SET_DATA] DATA: 0x0800C000 index row: 0; column0
        data changed signal
        [SET_DATA] DATA: 0x0800C004 index row: 1; column0
        data changed signal
        [SET_DATA] DATA: 0x0800C008 index row: 2; column0
        data changed signal
        [SET_DATA] DATA: 0x0800C00C index row: 3; column0
        data changed signal
        [SET_DATA] DATA: 0x0800C010 index row: 4; column0
        data changed signal
        [SET_DATA] DATA: 0x0800C014 index row: 5; column0
        data changed signal
        Currently we have 6 rows
        

        So the data is being inserted in the self.display list.
        But the widget looks still empty: https://imgur.com/moPD7x3

        You can find the complete repo here, I'm using fbs for the application so you should clone the repo, enter the cloned directory and do fbs run to get it running.

        Regards

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #2

        @Carlos-Diaz said in tableView not updated after calling dataChanged:

                current_rows = self.model.rowCount()
        
                print(f'Updating view, removing {current_rows} rows')
                self.model.removeRows(0, current_rows)
        
                current_rows = self.model.rowCount()
                print(f'Currently we have {current_rows} rows')
                
                row = 0
                for address in self.address_list:
                    idx = self.model.createIndex(row, 0)
                    self.model.setData(idx, address, Qt.EditRole)
                    row += 1
        

        Why doesn't your output show those print lines?

        Don't they show that after removing all rows from the model, you just go setData() over all the rows which no longer exist? What does the bool returned by your self.model.setData() return?

        1 Reply Last reply
        0
        • Carlos DiazC Offline
          Carlos DiazC Offline
          Carlos Diaz
          wrote on last edited by
          #3

          After taking a closer look at the log we can see the method data isn't being called after setData.

          [SET_DATA] DATA: 0x0800C000 index row: 0; column 0 # Here i load the first item of the list into the model
          data changed signal
          ['0x0800C000']
          Setting model
          Showing model
          [DATA] Column: 0; Row: 0 # Here the data method is being called
          0x0800C000
          [DATA] Column: 0; Row: 0
          0x0800C000
          Updating view, removing 1 rows
          ['0x0800C000']
          Removing 1 rows from 0 to 1
          []
          Currently we have 0 rows
          [SET_DATA] DATA: 0x0800C000 index row: 0; column 0 # Updating the data in the model, but the data method isn't being called after this
          data changed signal
          ['0x0800C000']
          [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
          data changed signal
          ['0x0800C000', '0x0800C004']
          [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
          data changed signal
          ['0x0800C000', '0x0800C004', '0x0800C008']
          [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
          data changed signal
          ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
          [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
          data changed signal
          ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
          [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
          data changed signal
          ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
          Currently we have 6 rows
          
          JonBJ 1 Reply Last reply
          0
          • Carlos DiazC Carlos Diaz

            After taking a closer look at the log we can see the method data isn't being called after setData.

            [SET_DATA] DATA: 0x0800C000 index row: 0; column 0 # Here i load the first item of the list into the model
            data changed signal
            ['0x0800C000']
            Setting model
            Showing model
            [DATA] Column: 0; Row: 0 # Here the data method is being called
            0x0800C000
            [DATA] Column: 0; Row: 0
            0x0800C000
            Updating view, removing 1 rows
            ['0x0800C000']
            Removing 1 rows from 0 to 1
            []
            Currently we have 0 rows
            [SET_DATA] DATA: 0x0800C000 index row: 0; column 0 # Updating the data in the model, but the data method isn't being called after this
            data changed signal
            ['0x0800C000']
            [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
            data changed signal
            ['0x0800C000', '0x0800C004']
            [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
            data changed signal
            ['0x0800C000', '0x0800C004', '0x0800C008']
            [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
            data changed signal
            ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
            [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
            data changed signal
            ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
            [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
            data changed signal
            ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
            Currently we have 6 rows
            
            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #4

            @Carlos-Diaz
            As I said above.

            I believe you will find your problem is because: having removed all rows via removeRows() you simply use setData() to put stuff into the model rows. You do not call insertRows(). If that is not called, the view won't get the signal and know there are any new rows.

            Put a debug in to show it's not being called. Then put in calls during your address population loop, and see how the view looks.

            1 Reply Last reply
            0
            • Carlos DiazC Offline
              Carlos DiazC Offline
              Carlos Diaz
              wrote on last edited by
              #5

              Hi @JonB,

              Here's the updated test code with the print statements updated:

              #!/usr/bin/env python3
              
              from fbs_runtime.application_context.PySide2 import ApplicationContext
              
              from PySide2.QtCore import *
              from PySide2.QtWidgets import *
              from PySide2.QtGui import QIntValidator
              from PySide2.QtUiTools import QUiLoader
              
              import sys
              
              class TestModel(QAbstractTableModel):
                  def __init__(self):
                      QAbstractTableModel.__init__(self)
                      
                      # Here we keep the data
                      self.display = []
              
                  def rowCount(self, parent=QModelIndex()):
                      return len(self.display)
              
                  def columnCount(self, parent=QModelIndex()):
                      COLUMNS_WIDTH_SIZE = 1
                      return COLUMNS_WIDTH_SIZE
              
                  def setData(self, index, value, role=Qt.EditRole):
                      '''
                      Adjust the data (set it to value <value>) depending on the given index
                      and role
                      '''
              
                      if role != Qt.EditRole:
                          return False
              
                      if index.isValid() and 0 <= index.row(): # < len(self.addresses):
                          
                          print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                          if index.column() == 0:
                              self.display.append(value)
                          else:
                              return False
                          
                          print(f'data changed signal')
                          print(self.display)
                          # self.layoutChanged.emit()
                          self.dataChanged.emit(index, index)
                          return True
              
                      return False
              
                  def flags(self, index):
                      '''
                      Set the item flags at the given index. Seems like we're implementing
                      this function just to see ho it's done, as we manually adjust each
                      tableView to have NoEditTriggers.
                      '''
              
                      if not index.isValid():
                          return Qt.ItemIsEnabled
                      return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
              
                  def insertRows(self, position, rows=1, index=QModelIndex()):
                      '''
                      Insert a row from the model.
                      '''
                      
                      self.beginInsertRows(QModelIndex(), position, position + rows - 1)
              
                      self.display.append(' ')
                      print(f'insert {rows} rows at {position}')
              
                      self.endInsertRows()
              
                      return True
              
                  def removeRows(self, position, rows=1, index=QModelIndex()):
                      '''
                      Remove a row from the model.
                      '''
                      
                      self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
              
                      print(self.display)
                      
                      print(f'Removing {rows} rows from {position} to {position+rows}')
                      del self.display[position:position+rows]
              
                      print(self.display)
              
                      self.endRemoveRows()
              
                      return True
              
                  def insertColumns(self, column, count, parent):
                      print(f'insert {count} columns at {column}')
              
                  def removeColumns(self):
                      pass
              
                  def data(self, index, role=Qt.DisplayRole):
              
                      if not index.isValid():
                          print(f'invalid index {index}')
                          return None
                      
                      if role != Qt.DisplayRole and role != Qt.EditRole:
                          # print(f'invalid role {role}')
                          return None
              
                      column = index.column()
                      row = index.row()
              
                      print(f'[DATA] Column: {column}; Row: {row}')
                      
                      if column == 0:
                          tmp = self.display[index.row()]
                          print(tmp)
                          return tmp
                      else:
                          return None
              
                  def headerData(self, section, orientation, role):
                      if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                          if section == 0:
                              return 'Address'
              
              class AppContext(ApplicationContext):
                  def run(self):
              
                      self.app.setStyle('Fusion')
              
                      ui_file = self.get_resource("mainwindow.ui")
                      self.file = QFile(ui_file)
                      self.file.open(QFile.ReadOnly)
                      self.loader = QUiLoader()
                      self.window = self.loader.load(self.file)
              
                      self.window.updateView.clicked.connect(self.onUpdateView)
              
                      self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
              
                      self.model = TestModel()
              
                      first_index = self.model.createIndex(0, 0)
              
                      self.model.setData(first_index, self.address_list[0], Qt.EditRole)
              
                      print(f'Setting model')
                      self.window.tableView.setModel(self.model)
                      print(f'Showing model')
                      self.window.tableView.show()
                      
                      # Show the application to the user        
                      self.window.show()
                      return self.app.exec_()
              
                  def onUpdateView(self):
              
                      current_rows = self.model.rowCount()
              
                      print(f'Updating view, removing {current_rows} rows')
                      self.model.removeRows(0, current_rows)
              
                      current_rows = self.model.rowCount()
                      print(f'Currently we have {current_rows} rows')
                      
                      for row, address in enumerate(self.address_list):
                          idx = self.model.createIndex(row, 0)
                          tmp = self.model.setData(idx, address, Qt.EditRole)
                          print(f'Result of setData: {tmp}')
                      
                      current_rows = self.model.rowCount()
                      print(f'Currently we have {current_rows} rows')
              
              if __name__ == '__main__':
                  appctxt = AppContext()
                  exit_code = appctxt.run()
                  sys.exit(exit_code)
              

              The return value from setData is True, here's the log output:

              [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
              data changed signal
              ['0x0800C000']
              Setting model
              Showing model
              [DATA] Column: 0; Row: 0
              0x0800C000
              [DATA] Column: 0; Row: 0
              0x0800C000
              Updating view, removing 1 rows
              ['0x0800C000']
              Removing 1 rows from 0 to 1
              []
              Currently we have 0 rows
              [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
              data changed signal
              ['0x0800C000']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
              data changed signal
              ['0x0800C000', '0x0800C004']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
              Result of setData: True
              Currently we have 6 rows
              

              If in setData we uncomment the self.layoutChanged.emit() line the view works as expected:

                  def setData(self, index, value, role=Qt.EditRole):
                      '''
                      Adjust the data (set it to value <value>) depending on the given index
                      and role
                      '''
              
                      if role != Qt.EditRole:
                          return False
              
                      if index.isValid() and 0 <= index.row(): # < len(self.addresses):
                          
                          print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                          if index.column() == 0:
                              self.display.append(value)
                          else:
                              return False
                          
                          print(f'data changed signal')
                          print(self.display)
                          self.layoutChanged.emit()
                          self.dataChanged.emit(index, index)
                          return True
              
                      return False
              

              log:

              [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
              data changed signal
              ['0x0800C000']
              Setting model
              Showing model
              [DATA] Column: 0; Row: 0
              0x0800C000
              [DATA] Column: 0; Row: 0
              0x0800C000
              Updating view, removing 1 rows
              ['0x0800C000']
              Removing 1 rows from 0 to 1
              []
              Currently we have 0 rows
              [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
              data changed signal
              ['0x0800C000']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
              data changed signal
              ['0x0800C000', '0x0800C004']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
              Result of setData: True
              [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
              data changed signal
              ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
              Result of setData: True
              Currently we have 6 rows
              [DATA] Column: 0; Row: 0
              0x0800C000
              [DATA] Column: 0; Row: 1
              0x0800C004
              [DATA] Column: 0; Row: 2
              0x0800C008
              [DATA] Column: 0; Row: 3
              0x0800C00C
              [DATA] Column: 0; Row: 4
              0x0800C010
              [DATA] Column: 0; Row: 5
              0x0800C014
              

              Updated tableView: https://imgur.com/zvQgS1s

              I guess adding self.layoutChanged.emit() is what i was missing or it isn't the proper way to solve it?

              JonBJ 2 Replies Last reply
              0
              • Carlos DiazC Carlos Diaz

                Hi @JonB,

                Here's the updated test code with the print statements updated:

                #!/usr/bin/env python3
                
                from fbs_runtime.application_context.PySide2 import ApplicationContext
                
                from PySide2.QtCore import *
                from PySide2.QtWidgets import *
                from PySide2.QtGui import QIntValidator
                from PySide2.QtUiTools import QUiLoader
                
                import sys
                
                class TestModel(QAbstractTableModel):
                    def __init__(self):
                        QAbstractTableModel.__init__(self)
                        
                        # Here we keep the data
                        self.display = []
                
                    def rowCount(self, parent=QModelIndex()):
                        return len(self.display)
                
                    def columnCount(self, parent=QModelIndex()):
                        COLUMNS_WIDTH_SIZE = 1
                        return COLUMNS_WIDTH_SIZE
                
                    def setData(self, index, value, role=Qt.EditRole):
                        '''
                        Adjust the data (set it to value <value>) depending on the given index
                        and role
                        '''
                
                        if role != Qt.EditRole:
                            return False
                
                        if index.isValid() and 0 <= index.row(): # < len(self.addresses):
                            
                            print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                            if index.column() == 0:
                                self.display.append(value)
                            else:
                                return False
                            
                            print(f'data changed signal')
                            print(self.display)
                            # self.layoutChanged.emit()
                            self.dataChanged.emit(index, index)
                            return True
                
                        return False
                
                    def flags(self, index):
                        '''
                        Set the item flags at the given index. Seems like we're implementing
                        this function just to see ho it's done, as we manually adjust each
                        tableView to have NoEditTriggers.
                        '''
                
                        if not index.isValid():
                            return Qt.ItemIsEnabled
                        return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
                
                    def insertRows(self, position, rows=1, index=QModelIndex()):
                        '''
                        Insert a row from the model.
                        '''
                        
                        self.beginInsertRows(QModelIndex(), position, position + rows - 1)
                
                        self.display.append(' ')
                        print(f'insert {rows} rows at {position}')
                
                        self.endInsertRows()
                
                        return True
                
                    def removeRows(self, position, rows=1, index=QModelIndex()):
                        '''
                        Remove a row from the model.
                        '''
                        
                        self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
                
                        print(self.display)
                        
                        print(f'Removing {rows} rows from {position} to {position+rows}')
                        del self.display[position:position+rows]
                
                        print(self.display)
                
                        self.endRemoveRows()
                
                        return True
                
                    def insertColumns(self, column, count, parent):
                        print(f'insert {count} columns at {column}')
                
                    def removeColumns(self):
                        pass
                
                    def data(self, index, role=Qt.DisplayRole):
                
                        if not index.isValid():
                            print(f'invalid index {index}')
                            return None
                        
                        if role != Qt.DisplayRole and role != Qt.EditRole:
                            # print(f'invalid role {role}')
                            return None
                
                        column = index.column()
                        row = index.row()
                
                        print(f'[DATA] Column: {column}; Row: {row}')
                        
                        if column == 0:
                            tmp = self.display[index.row()]
                            print(tmp)
                            return tmp
                        else:
                            return None
                
                    def headerData(self, section, orientation, role):
                        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                            if section == 0:
                                return 'Address'
                
                class AppContext(ApplicationContext):
                    def run(self):
                
                        self.app.setStyle('Fusion')
                
                        ui_file = self.get_resource("mainwindow.ui")
                        self.file = QFile(ui_file)
                        self.file.open(QFile.ReadOnly)
                        self.loader = QUiLoader()
                        self.window = self.loader.load(self.file)
                
                        self.window.updateView.clicked.connect(self.onUpdateView)
                
                        self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                
                        self.model = TestModel()
                
                        first_index = self.model.createIndex(0, 0)
                
                        self.model.setData(first_index, self.address_list[0], Qt.EditRole)
                
                        print(f'Setting model')
                        self.window.tableView.setModel(self.model)
                        print(f'Showing model')
                        self.window.tableView.show()
                        
                        # Show the application to the user        
                        self.window.show()
                        return self.app.exec_()
                
                    def onUpdateView(self):
                
                        current_rows = self.model.rowCount()
                
                        print(f'Updating view, removing {current_rows} rows')
                        self.model.removeRows(0, current_rows)
                
                        current_rows = self.model.rowCount()
                        print(f'Currently we have {current_rows} rows')
                        
                        for row, address in enumerate(self.address_list):
                            idx = self.model.createIndex(row, 0)
                            tmp = self.model.setData(idx, address, Qt.EditRole)
                            print(f'Result of setData: {tmp}')
                        
                        current_rows = self.model.rowCount()
                        print(f'Currently we have {current_rows} rows')
                
                if __name__ == '__main__':
                    appctxt = AppContext()
                    exit_code = appctxt.run()
                    sys.exit(exit_code)
                

                The return value from setData is True, here's the log output:

                [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                data changed signal
                ['0x0800C000']
                Setting model
                Showing model
                [DATA] Column: 0; Row: 0
                0x0800C000
                [DATA] Column: 0; Row: 0
                0x0800C000
                Updating view, removing 1 rows
                ['0x0800C000']
                Removing 1 rows from 0 to 1
                []
                Currently we have 0 rows
                [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                data changed signal
                ['0x0800C000']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                data changed signal
                ['0x0800C000', '0x0800C004']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                Result of setData: True
                Currently we have 6 rows
                

                If in setData we uncomment the self.layoutChanged.emit() line the view works as expected:

                    def setData(self, index, value, role=Qt.EditRole):
                        '''
                        Adjust the data (set it to value <value>) depending on the given index
                        and role
                        '''
                
                        if role != Qt.EditRole:
                            return False
                
                        if index.isValid() and 0 <= index.row(): # < len(self.addresses):
                            
                            print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                            if index.column() == 0:
                                self.display.append(value)
                            else:
                                return False
                            
                            print(f'data changed signal')
                            print(self.display)
                            self.layoutChanged.emit()
                            self.dataChanged.emit(index, index)
                            return True
                
                        return False
                

                log:

                [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                data changed signal
                ['0x0800C000']
                Setting model
                Showing model
                [DATA] Column: 0; Row: 0
                0x0800C000
                [DATA] Column: 0; Row: 0
                0x0800C000
                Updating view, removing 1 rows
                ['0x0800C000']
                Removing 1 rows from 0 to 1
                []
                Currently we have 0 rows
                [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                data changed signal
                ['0x0800C000']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                data changed signal
                ['0x0800C000', '0x0800C004']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
                Result of setData: True
                [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                data changed signal
                ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                Result of setData: True
                Currently we have 6 rows
                [DATA] Column: 0; Row: 0
                0x0800C000
                [DATA] Column: 0; Row: 1
                0x0800C004
                [DATA] Column: 0; Row: 2
                0x0800C008
                [DATA] Column: 0; Row: 3
                0x0800C00C
                [DATA] Column: 0; Row: 4
                0x0800C010
                [DATA] Column: 0; Row: 5
                0x0800C014
                

                Updated tableView: https://imgur.com/zvQgS1s

                I guess adding self.layoutChanged.emit() is what i was missing or it isn't the proper way to solve it?

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #6

                @Carlos-Diaz
                Our posts keep crossing! Please read the answer I have just posted above your new post! I hope you will find it is the reason/solution.

                Carlos DiazC 1 Reply Last reply
                0
                • Carlos DiazC Carlos Diaz

                  Hi @JonB,

                  Here's the updated test code with the print statements updated:

                  #!/usr/bin/env python3
                  
                  from fbs_runtime.application_context.PySide2 import ApplicationContext
                  
                  from PySide2.QtCore import *
                  from PySide2.QtWidgets import *
                  from PySide2.QtGui import QIntValidator
                  from PySide2.QtUiTools import QUiLoader
                  
                  import sys
                  
                  class TestModel(QAbstractTableModel):
                      def __init__(self):
                          QAbstractTableModel.__init__(self)
                          
                          # Here we keep the data
                          self.display = []
                  
                      def rowCount(self, parent=QModelIndex()):
                          return len(self.display)
                  
                      def columnCount(self, parent=QModelIndex()):
                          COLUMNS_WIDTH_SIZE = 1
                          return COLUMNS_WIDTH_SIZE
                  
                      def setData(self, index, value, role=Qt.EditRole):
                          '''
                          Adjust the data (set it to value <value>) depending on the given index
                          and role
                          '''
                  
                          if role != Qt.EditRole:
                              return False
                  
                          if index.isValid() and 0 <= index.row(): # < len(self.addresses):
                              
                              print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                              if index.column() == 0:
                                  self.display.append(value)
                              else:
                                  return False
                              
                              print(f'data changed signal')
                              print(self.display)
                              # self.layoutChanged.emit()
                              self.dataChanged.emit(index, index)
                              return True
                  
                          return False
                  
                      def flags(self, index):
                          '''
                          Set the item flags at the given index. Seems like we're implementing
                          this function just to see ho it's done, as we manually adjust each
                          tableView to have NoEditTriggers.
                          '''
                  
                          if not index.isValid():
                              return Qt.ItemIsEnabled
                          return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
                  
                      def insertRows(self, position, rows=1, index=QModelIndex()):
                          '''
                          Insert a row from the model.
                          '''
                          
                          self.beginInsertRows(QModelIndex(), position, position + rows - 1)
                  
                          self.display.append(' ')
                          print(f'insert {rows} rows at {position}')
                  
                          self.endInsertRows()
                  
                          return True
                  
                      def removeRows(self, position, rows=1, index=QModelIndex()):
                          '''
                          Remove a row from the model.
                          '''
                          
                          self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
                  
                          print(self.display)
                          
                          print(f'Removing {rows} rows from {position} to {position+rows}')
                          del self.display[position:position+rows]
                  
                          print(self.display)
                  
                          self.endRemoveRows()
                  
                          return True
                  
                      def insertColumns(self, column, count, parent):
                          print(f'insert {count} columns at {column}')
                  
                      def removeColumns(self):
                          pass
                  
                      def data(self, index, role=Qt.DisplayRole):
                  
                          if not index.isValid():
                              print(f'invalid index {index}')
                              return None
                          
                          if role != Qt.DisplayRole and role != Qt.EditRole:
                              # print(f'invalid role {role}')
                              return None
                  
                          column = index.column()
                          row = index.row()
                  
                          print(f'[DATA] Column: {column}; Row: {row}')
                          
                          if column == 0:
                              tmp = self.display[index.row()]
                              print(tmp)
                              return tmp
                          else:
                              return None
                  
                      def headerData(self, section, orientation, role):
                          if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                              if section == 0:
                                  return 'Address'
                  
                  class AppContext(ApplicationContext):
                      def run(self):
                  
                          self.app.setStyle('Fusion')
                  
                          ui_file = self.get_resource("mainwindow.ui")
                          self.file = QFile(ui_file)
                          self.file.open(QFile.ReadOnly)
                          self.loader = QUiLoader()
                          self.window = self.loader.load(self.file)
                  
                          self.window.updateView.clicked.connect(self.onUpdateView)
                  
                          self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                  
                          self.model = TestModel()
                  
                          first_index = self.model.createIndex(0, 0)
                  
                          self.model.setData(first_index, self.address_list[0], Qt.EditRole)
                  
                          print(f'Setting model')
                          self.window.tableView.setModel(self.model)
                          print(f'Showing model')
                          self.window.tableView.show()
                          
                          # Show the application to the user        
                          self.window.show()
                          return self.app.exec_()
                  
                      def onUpdateView(self):
                  
                          current_rows = self.model.rowCount()
                  
                          print(f'Updating view, removing {current_rows} rows')
                          self.model.removeRows(0, current_rows)
                  
                          current_rows = self.model.rowCount()
                          print(f'Currently we have {current_rows} rows')
                          
                          for row, address in enumerate(self.address_list):
                              idx = self.model.createIndex(row, 0)
                              tmp = self.model.setData(idx, address, Qt.EditRole)
                              print(f'Result of setData: {tmp}')
                          
                          current_rows = self.model.rowCount()
                          print(f'Currently we have {current_rows} rows')
                  
                  if __name__ == '__main__':
                      appctxt = AppContext()
                      exit_code = appctxt.run()
                      sys.exit(exit_code)
                  

                  The return value from setData is True, here's the log output:

                  [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                  data changed signal
                  ['0x0800C000']
                  Setting model
                  Showing model
                  [DATA] Column: 0; Row: 0
                  0x0800C000
                  [DATA] Column: 0; Row: 0
                  0x0800C000
                  Updating view, removing 1 rows
                  ['0x0800C000']
                  Removing 1 rows from 0 to 1
                  []
                  Currently we have 0 rows
                  [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                  data changed signal
                  ['0x0800C000']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                  Result of setData: True
                  Currently we have 6 rows
                  

                  If in setData we uncomment the self.layoutChanged.emit() line the view works as expected:

                      def setData(self, index, value, role=Qt.EditRole):
                          '''
                          Adjust the data (set it to value <value>) depending on the given index
                          and role
                          '''
                  
                          if role != Qt.EditRole:
                              return False
                  
                          if index.isValid() and 0 <= index.row(): # < len(self.addresses):
                              
                              print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                              if index.column() == 0:
                                  self.display.append(value)
                              else:
                                  return False
                              
                              print(f'data changed signal')
                              print(self.display)
                              self.layoutChanged.emit()
                              self.dataChanged.emit(index, index)
                              return True
                  
                          return False
                  

                  log:

                  [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                  data changed signal
                  ['0x0800C000']
                  Setting model
                  Showing model
                  [DATA] Column: 0; Row: 0
                  0x0800C000
                  [DATA] Column: 0; Row: 0
                  0x0800C000
                  Updating view, removing 1 rows
                  ['0x0800C000']
                  Removing 1 rows from 0 to 1
                  []
                  Currently we have 0 rows
                  [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                  data changed signal
                  ['0x0800C000']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
                  Result of setData: True
                  [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                  data changed signal
                  ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                  Result of setData: True
                  Currently we have 6 rows
                  [DATA] Column: 0; Row: 0
                  0x0800C000
                  [DATA] Column: 0; Row: 1
                  0x0800C004
                  [DATA] Column: 0; Row: 2
                  0x0800C008
                  [DATA] Column: 0; Row: 3
                  0x0800C00C
                  [DATA] Column: 0; Row: 4
                  0x0800C010
                  [DATA] Column: 0; Row: 5
                  0x0800C014
                  

                  Updated tableView: https://imgur.com/zvQgS1s

                  I guess adding self.layoutChanged.emit() is what i was missing or it isn't the proper way to solve it?

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #7

                  @Carlos-Diaz said in tableView not updated after calling dataChanged:

                  if index.isValid() and 0 <= index.row(): # < len(self.addresses):

                  I think your commented-out bit suggests you were onto the problem :) I admit I don't know why the index is valid, but you should check its row is less than the number of items/rows currently in the model. Then I think it would return false, the setData()s would fail, and you will have to call insertRows() as you should? And then it all works :) ?

                  1 Reply Last reply
                  0
                  • JonBJ JonB

                    @Carlos-Diaz
                    Our posts keep crossing! Please read the answer I have just posted above your new post! I hope you will find it is the reason/solution.

                    Carlos DiazC Offline
                    Carlos DiazC Offline
                    Carlos Diaz
                    wrote on last edited by Carlos Diaz
                    #8

                    @JonB

                    Sorry about that, I also was going to mention our posts were crossing. I now cleaned up the code, I have been working with it for a couple of days and kept garbage code.

                    I did a tiny experiment by removing the line that remove rows on the table and:

                    1. Keeping the line self.layoutChanged.emit()
                    2. Removing the line self.layoutChanged.emit()

                    Option 1 the tableView works as expected, i can see the rows being updated.
                    Option 2 the tableView is not being updated.

                    So I ended up with the following working code:

                    #!/usr/bin/env python3
                    
                    from fbs_runtime.application_context.PySide2 import ApplicationContext
                    
                    from PySide2.QtCore import *
                    from PySide2.QtWidgets import *
                    from PySide2.QtGui import QIntValidator
                    from PySide2.QtUiTools import QUiLoader
                    
                    import sys
                    
                    class TestModel(QAbstractTableModel):
                        def __init__(self):
                            QAbstractTableModel.__init__(self)
                            
                            # Here we keep the data
                            self.display = []
                    
                        def rowCount(self, parent=QModelIndex()):
                            return len(self.display)
                    
                        def columnCount(self, parent=QModelIndex()):
                            COLUMNS_WIDTH_SIZE = 1
                            return COLUMNS_WIDTH_SIZE
                    
                        def setData(self, index, value, role=Qt.EditRole):
                            '''
                            Adjust the data (set it to value <value>) depending on the given index
                            and role
                            '''
                    
                            if role != Qt.EditRole:
                                return False
                    
                            if index.isValid() and 0 <= index.row():
                                
                                print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                                if index.column() == 0:
                                    self.display.append(value)
                                else:
                                    return False
                                
                                print(f'data changed signal')
                                print(self.display)
                                self.layoutChanged.emit()
                                self.dataChanged.emit(index, index)
                                return True
                    
                            return False
                    
                        def flags(self, index):
                            '''
                            Set the item flags at the given index. Seems like we're implementing
                            this function just to see ho it's done, as we manually adjust each
                            tableView to have NoEditTriggers.
                            '''
                    
                            if not index.isValid():
                                return Qt.ItemIsEnabled
                            return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
                    
                        def insertRows(self, position, rows=1, index=QModelIndex()):
                            '''
                            Insert a row from the model.
                            '''
                            
                            self.beginInsertRows(QModelIndex(), position, position + rows - 1)
                    
                            self.display.append(' ')
                            print(f'insert {rows} rows at {position}')
                    
                            self.endInsertRows()
                    
                            return True
                    
                        def removeRows(self, position, rows=1, index=QModelIndex()):
                            '''
                            Remove a row from the model.
                            '''
                            
                            self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
                    
                            print(self.display)
                            
                            print(f'Removing {rows} rows from {position} to {position+rows}')
                            del self.display[position:position+rows]
                    
                            print(self.display)
                    
                            self.endRemoveRows()
                    
                            return True
                    
                        def insertColumns(self, column, count, parent):
                            print(f'insert {count} columns at {column}')
                    
                        def removeColumns(self):
                            pass
                    
                        def data(self, index, role=Qt.DisplayRole):
                    
                            if not index.isValid():
                                print(f'invalid index {index}')
                                return None
                            
                            if role != Qt.DisplayRole and role != Qt.EditRole:
                                # print(f'invalid role {role}')
                                return None
                    
                            column = index.column()
                            row = index.row()
                    
                            print(f'[DATA] Column: {column}; Row: {row}')
                            
                            if column == 0:
                                tmp = self.display[index.row()]
                                print(tmp)
                                return tmp
                            else:
                                return None
                    
                        def headerData(self, section, orientation, role):
                            if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                                if section == 0:
                                    return 'Address'
                    
                    class AppContext(ApplicationContext):
                        def run(self):
                    
                            self.app.setStyle('Fusion')
                    
                            ui_file = self.get_resource("mainwindow.ui")
                            self.file = QFile(ui_file)
                            self.file.open(QFile.ReadOnly)
                            self.loader = QUiLoader()
                            self.window = self.loader.load(self.file)
                    
                            self.window.updateView.clicked.connect(self.onUpdateView)
                    
                            self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                    
                            self.model = TestModel()
                    
                            first_index = self.model.createIndex(0, 0)
                    
                            self.model.setData(first_index, self.address_list[0], Qt.EditRole)
                    
                            print(f'Setting model')
                            self.window.tableView.setModel(self.model)
                            print(f'Showing model')
                            self.window.tableView.show()
                            
                            # Show the application to the user        
                            self.window.show()
                            return self.app.exec_()
                    
                        def onUpdateView(self):
                    
                            current_rows = self.model.rowCount()
                            print(f'Currently we have {current_rows} rows')
                            
                            for row, address in enumerate(self.address_list):
                                idx = self.model.createIndex(row, 0)
                                tmp = self.model.setData(idx, address, Qt.EditRole)
                                print(f'Result of setData: {tmp}')
                            
                            current_rows = self.model.rowCount()
                            print(f'Currently we have {current_rows} rows')
                    
                    if __name__ == '__main__':
                        appctxt = AppContext()
                        exit_code = appctxt.run()
                        sys.exit(exit_code)
                    
                    

                    Working log:

                    [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                    data changed signal
                    ['0x0800C000']
                    Setting model
                    Showing model
                    [DATA] Column: 0; Row: 0
                    0x0800C000
                    [DATA] Column: 0; Row: 0
                    0x0800C000
                    Currently we have 1 rows
                    [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                    data changed signal
                    ['0x0800C000', '0x0800C000']
                    Result of setData: True
                    [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                    data changed signal
                    ['0x0800C000', '0x0800C000', '0x0800C004']
                    Result of setData: True
                    [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                    data changed signal
                    ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008']
                    Result of setData: True
                    [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                    data changed signal
                    ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
                    Result of setData: True
                    [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                    data changed signal
                    ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
                    Result of setData: True
                    [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                    data changed signal
                    ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                    Result of setData: True
                    Currently we have 7 rows
                    [DATA] Column: 0; Row: 0
                    0x0800C000
                    [DATA] Column: 0; Row: 1
                    0x0800C000
                    [DATA] Column: 0; Row: 2
                    0x0800C004
                    [DATA] Column: 0; Row: 3
                    0x0800C008
                    [DATA] Column: 0; Row: 4
                    0x0800C00C
                    [DATA] Column: 0; Row: 5
                    0x0800C010
                    [DATA] Column: 0; Row: 6
                    0x0800C014
                    

                    We can see the data function is being called and returning valid data so the view is updated. Updated tableView: https://imgur.com/zvQgS1s

                    JonBJ 1 Reply Last reply
                    0
                    • Carlos DiazC Carlos Diaz

                      @JonB

                      Sorry about that, I also was going to mention our posts were crossing. I now cleaned up the code, I have been working with it for a couple of days and kept garbage code.

                      I did a tiny experiment by removing the line that remove rows on the table and:

                      1. Keeping the line self.layoutChanged.emit()
                      2. Removing the line self.layoutChanged.emit()

                      Option 1 the tableView works as expected, i can see the rows being updated.
                      Option 2 the tableView is not being updated.

                      So I ended up with the following working code:

                      #!/usr/bin/env python3
                      
                      from fbs_runtime.application_context.PySide2 import ApplicationContext
                      
                      from PySide2.QtCore import *
                      from PySide2.QtWidgets import *
                      from PySide2.QtGui import QIntValidator
                      from PySide2.QtUiTools import QUiLoader
                      
                      import sys
                      
                      class TestModel(QAbstractTableModel):
                          def __init__(self):
                              QAbstractTableModel.__init__(self)
                              
                              # Here we keep the data
                              self.display = []
                      
                          def rowCount(self, parent=QModelIndex()):
                              return len(self.display)
                      
                          def columnCount(self, parent=QModelIndex()):
                              COLUMNS_WIDTH_SIZE = 1
                              return COLUMNS_WIDTH_SIZE
                      
                          def setData(self, index, value, role=Qt.EditRole):
                              '''
                              Adjust the data (set it to value <value>) depending on the given index
                              and role
                              '''
                      
                              if role != Qt.EditRole:
                                  return False
                      
                              if index.isValid() and 0 <= index.row():
                                  
                                  print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                                  if index.column() == 0:
                                      self.display.append(value)
                                  else:
                                      return False
                                  
                                  print(f'data changed signal')
                                  print(self.display)
                                  self.layoutChanged.emit()
                                  self.dataChanged.emit(index, index)
                                  return True
                      
                              return False
                      
                          def flags(self, index):
                              '''
                              Set the item flags at the given index. Seems like we're implementing
                              this function just to see ho it's done, as we manually adjust each
                              tableView to have NoEditTriggers.
                              '''
                      
                              if not index.isValid():
                                  return Qt.ItemIsEnabled
                              return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
                      
                          def insertRows(self, position, rows=1, index=QModelIndex()):
                              '''
                              Insert a row from the model.
                              '''
                              
                              self.beginInsertRows(QModelIndex(), position, position + rows - 1)
                      
                              self.display.append(' ')
                              print(f'insert {rows} rows at {position}')
                      
                              self.endInsertRows()
                      
                              return True
                      
                          def removeRows(self, position, rows=1, index=QModelIndex()):
                              '''
                              Remove a row from the model.
                              '''
                              
                              self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
                      
                              print(self.display)
                              
                              print(f'Removing {rows} rows from {position} to {position+rows}')
                              del self.display[position:position+rows]
                      
                              print(self.display)
                      
                              self.endRemoveRows()
                      
                              return True
                      
                          def insertColumns(self, column, count, parent):
                              print(f'insert {count} columns at {column}')
                      
                          def removeColumns(self):
                              pass
                      
                          def data(self, index, role=Qt.DisplayRole):
                      
                              if not index.isValid():
                                  print(f'invalid index {index}')
                                  return None
                              
                              if role != Qt.DisplayRole and role != Qt.EditRole:
                                  # print(f'invalid role {role}')
                                  return None
                      
                              column = index.column()
                              row = index.row()
                      
                              print(f'[DATA] Column: {column}; Row: {row}')
                              
                              if column == 0:
                                  tmp = self.display[index.row()]
                                  print(tmp)
                                  return tmp
                              else:
                                  return None
                      
                          def headerData(self, section, orientation, role):
                              if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                                  if section == 0:
                                      return 'Address'
                      
                      class AppContext(ApplicationContext):
                          def run(self):
                      
                              self.app.setStyle('Fusion')
                      
                              ui_file = self.get_resource("mainwindow.ui")
                              self.file = QFile(ui_file)
                              self.file.open(QFile.ReadOnly)
                              self.loader = QUiLoader()
                              self.window = self.loader.load(self.file)
                      
                              self.window.updateView.clicked.connect(self.onUpdateView)
                      
                              self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                      
                              self.model = TestModel()
                      
                              first_index = self.model.createIndex(0, 0)
                      
                              self.model.setData(first_index, self.address_list[0], Qt.EditRole)
                      
                              print(f'Setting model')
                              self.window.tableView.setModel(self.model)
                              print(f'Showing model')
                              self.window.tableView.show()
                              
                              # Show the application to the user        
                              self.window.show()
                              return self.app.exec_()
                      
                          def onUpdateView(self):
                      
                              current_rows = self.model.rowCount()
                              print(f'Currently we have {current_rows} rows')
                              
                              for row, address in enumerate(self.address_list):
                                  idx = self.model.createIndex(row, 0)
                                  tmp = self.model.setData(idx, address, Qt.EditRole)
                                  print(f'Result of setData: {tmp}')
                              
                              current_rows = self.model.rowCount()
                              print(f'Currently we have {current_rows} rows')
                      
                      if __name__ == '__main__':
                          appctxt = AppContext()
                          exit_code = appctxt.run()
                          sys.exit(exit_code)
                      
                      

                      Working log:

                      [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                      data changed signal
                      ['0x0800C000']
                      Setting model
                      Showing model
                      [DATA] Column: 0; Row: 0
                      0x0800C000
                      [DATA] Column: 0; Row: 0
                      0x0800C000
                      Currently we have 1 rows
                      [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                      data changed signal
                      ['0x0800C000', '0x0800C000']
                      Result of setData: True
                      [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                      data changed signal
                      ['0x0800C000', '0x0800C000', '0x0800C004']
                      Result of setData: True
                      [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                      data changed signal
                      ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008']
                      Result of setData: True
                      [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                      data changed signal
                      ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C']
                      Result of setData: True
                      [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                      data changed signal
                      ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010']
                      Result of setData: True
                      [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                      data changed signal
                      ['0x0800C000', '0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                      Result of setData: True
                      Currently we have 7 rows
                      [DATA] Column: 0; Row: 0
                      0x0800C000
                      [DATA] Column: 0; Row: 1
                      0x0800C000
                      [DATA] Column: 0; Row: 2
                      0x0800C004
                      [DATA] Column: 0; Row: 3
                      0x0800C008
                      [DATA] Column: 0; Row: 4
                      0x0800C00C
                      [DATA] Column: 0; Row: 5
                      0x0800C010
                      [DATA] Column: 0; Row: 6
                      0x0800C014
                      

                      We can see the data function is being called and returning valid data so the view is updated. Updated tableView: https://imgur.com/zvQgS1s

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #9

                      @Carlos-Diaz said in tableView not updated after calling dataChanged:

                      print(f'insert {rows} rows at {position}')

                      Where is that called in the output? You are not calling insertRows(). Your code for setData() is wrong. As I have said in above posts.

                      Your call to index.isValid() is insufficient. That only says:

                      Returns true if this model index is valid; otherwise returns false.

                      A valid index belongs to a model, and has non-negative row and column numbers.That's what I think. It would be interesting to hear your comment?

                      You have to check for number of rows in model in setData(), your line needs to be:

                       if index.isValid() and 0 <= index.row() < self.rowCount():
                      

                      Your self.layoutChanged.emit() hides the incorrect code by causing the whole view to refresh.

                      I really think that is your problem. It would be nice to hear your comment on this specific area?

                      Carlos DiazC 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @Carlos-Diaz said in tableView not updated after calling dataChanged:

                        print(f'insert {rows} rows at {position}')

                        Where is that called in the output? You are not calling insertRows(). Your code for setData() is wrong. As I have said in above posts.

                        Your call to index.isValid() is insufficient. That only says:

                        Returns true if this model index is valid; otherwise returns false.

                        A valid index belongs to a model, and has non-negative row and column numbers.That's what I think. It would be interesting to hear your comment?

                        You have to check for number of rows in model in setData(), your line needs to be:

                         if index.isValid() and 0 <= index.row() < self.rowCount():
                        

                        Your self.layoutChanged.emit() hides the incorrect code by causing the whole view to refresh.

                        I really think that is your problem. It would be nice to hear your comment on this specific area?

                        Carlos DiazC Offline
                        Carlos DiazC Offline
                        Carlos Diaz
                        wrote on last edited by
                        #10

                        @JonB Thanks for being so patient with my mistakes.

                        I think I had added everything you suggested and removed the self.layoutChanged.emit() call and the view keeps working!

                        I don't know if it's possible to add the new rows inside the setData function, so it's not handled on the application level?

                        Here's the updated code:

                        #!/usr/bin/env python3
                        
                        from fbs_runtime.application_context.PySide2 import ApplicationContext
                        
                        from PySide2.QtCore import *
                        from PySide2.QtWidgets import *
                        from PySide2.QtGui import QIntValidator
                        from PySide2.QtUiTools import QUiLoader
                        
                        import sys
                        
                        '''
                        QAbstractTableModel provides a standard interface for models that represent their
                        data as a two-dimensional array of items. It is not used directly, but must be
                        subclassed.
                        
                        Since the model provides a more especialized interface than QAbstractItemModel,
                        it is not suitable for use with tree views, although it can be used to provide
                        data to a QListView.
                        If you need to represent a simple list of items, and only need a model to contain
                        a single column of data, subclassing the QAbstractListModel may be more appropiate.
                        
                        The rowCount() and columnCount() functions return the dimensions of the table.
                        To retrieve a model index corresponding to an item in the model, use index()
                        and provide only the row and column numbers.
                        
                        Editable models need to implement setData(), and implement flags() to return a value
                        containing ItemsIsEditable.
                        
                        Models that provide interfaces to resizable data structures can provide implementations of:
                         - insertRows()
                         - removeRows()
                         - insertColumns()
                         - removeColumns()
                         
                        When implementing these functions, it is important to call the appropiate functions
                        so that all connected views are aware of any changes.
                        
                        Role enum:
                        https://doc.qt.io/qt-5/qt.html#ItemDataRole-enum
                        
                        Useful links:
                        https://doc.qt.io/qtforpython/PySide2/QtCore/QAbstractTableModel.html
                        https://doc.qt.io/qtforpython/tutorials/datavisualize/index.html
                        https://stackoverflow.com/questions/50391050/how-to-remove-row-from-qtreeview-using-qabstractitemmodel
                        https://github.com/pyside/Examples/blob/master/examples/itemviews/editabletreemodel/editabletreemodel.py
                        '''
                        class TestModel(QAbstractTableModel):
                            def __init__(self):
                                QAbstractTableModel.__init__(self)
                                
                                # Here we keep the data
                                self.display = []
                        
                            def rowCount(self, parent=QModelIndex()):
                                return len(self.display)
                        
                            def columnCount(self, parent=QModelIndex()):
                                COLUMNS_WIDTH_SIZE = 1
                                return COLUMNS_WIDTH_SIZE
                        
                            def setData(self, index, value, role=Qt.EditRole):
                                '''
                                Adjust the data (set it to value <value>) depending on the given index
                                and role
                                '''
                        
                                if role != Qt.EditRole:
                                    print(f'[SET_DATA] Role is not EditRole')
                                    return False
                        
                                # We must be sure we add the new value into a valid index of the model
                                # So we validate the index, we make sure the index row isn't 0 or less
                                # and that the amount of current rows is more than the index row we are
                                # adding the value to.
                                if index.isValid() and 0 <= index.row() < self.rowCount():
                                    
                                    print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                                    if index.column() == 0:
                                        print(f'Before setting the new value {self.display}')
                                        self.display[index.row()] = value
                                        print(f'After setting the new value {self.display}')
                                    else:
                                        return False
                                    
                                    self.dataChanged.emit(index, index)
                                    return True
                        
                                return False
                        
                            def flags(self, index):
                                '''
                                Set the item flags at the given index. Seems like we're implementing
                                this function just to see ho it's done, as we manually adjust each
                                tableView to have NoEditTriggers.
                                '''
                        
                                if not index.isValid():
                                    return Qt.ItemIsEnabled
                                return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
                        
                            def insertRows(self, position, rows=1, index=QModelIndex()):
                                '''
                                Insert a row from the model.
                                '''
                                
                                self.beginInsertRows(QModelIndex(), position, position + rows - 1)
                        
                                print(f'Inserting {rows} rows at {position}')
                        
                                # We extend the list with rows elements
                                self.display.extend([''] * rows)
                        
                                self.endInsertRows()
                        
                                return True
                        
                            def removeRows(self, position, rows=1, index=QModelIndex()):
                                '''
                                Remove a row from the model.
                                '''
                                
                                self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
                        
                                print(self.display)
                                
                                print(f'Removing {rows} rows from {position} to {position+rows}')
                                del self.display[position:position+rows]
                        
                                print(self.display)
                        
                                self.endRemoveRows()
                        
                                return True
                        
                            def insertColumns(self, column, count, parent):
                                print(f'insert {count} columns at {column}')
                        
                            def removeColumns(self):
                                pass
                        
                            def data(self, index, role=Qt.DisplayRole):
                        
                                if not index.isValid():
                                    print(f'invalid index {index}')
                                    return None
                                
                                if role != Qt.DisplayRole and role != Qt.EditRole:
                                    return None
                        
                                column = index.column()
                                row = index.row()
                        
                                print(f'Fetching data from column: {column}; row: {row}')
                                
                                if column == 0:
                                    tmp = self.display[index.row()]
                                    print(f'Data: {tmp}')
                                    return tmp
                                else:
                                    return None
                        
                            def headerData(self, section, orientation, role):
                                if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                                    if section == 0:
                                        return 'Address'
                        
                        class AppContext(ApplicationContext):
                            def run(self):
                        
                                self.app.setStyle('Fusion')
                        
                                ui_file = self.get_resource("mainwindow.ui")
                                self.file = QFile(ui_file)
                                self.file.open(QFile.ReadOnly)
                                self.loader = QUiLoader()
                                self.window = self.loader.load(self.file)
                        
                                self.window.updateView.clicked.connect(self.onUpdateView)
                        
                                self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                        
                                self.model = TestModel()
                                self.window.tableView.setModel(self.model)
                        
                                # Add a row for the default data..
                                self.model.insertRows(0)
                                first_index = self.model.createIndex(0, 0)
                                self.model.setData(first_index, self.address_list[0], Qt.EditRole)
                                
                                self.window.tableView.show()
                                
                                # Show the application to the user        
                                self.window.show()
                                return self.app.exec_()
                        
                            def onUpdateView(self):
                                print(f'Updating view...')
                                
                                print(f'We have {self.model.rowCount()} rows')
                        
                                # Insert rows for new data
                                rows_to_add = len(self.address_list)
                                current_rows = self.model.rowCount()
                        
                                rows_to_add -= current_rows
                                print(f'Inserting {rows_to_add} new rows for the new data')
                                self.model.insertRows(0, rows_to_add)
                                print(f'We now have {self.model.rowCount()} rows')
                        
                                print(f'Inserting new data into the model...')
                                for row, address in enumerate(self.address_list):
                                    column = 0
                                    idx = self.model.createIndex(row, column)
                                    tmp = self.model.setData(idx, address, Qt.EditRole)
                                    print(f'Result of setData: {tmp}')
                        
                                print('Done')
                        
                        if __name__ == '__main__':
                            appctxt = AppContext()
                            exit_code = appctxt.run()
                            sys.exit(exit_code)
                        

                        Output log:

                        Inserting 1 rows at 0
                        [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                        Before setting the new value ['']
                        After setting the new value ['0x0800C000']
                        Fetching data from column: 0; row: 0
                        Data: 0x0800C000
                        Fetching data from column: 0; row: 0
                        Data: 0x0800C000
                        Updating view...
                        We have 1 rows
                        Inserting 5 new rows for the new data
                        Inserting 5 rows at 0
                        We now have 6 rows
                        Inserting new data into the model...
                        [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                        Before setting the new value ['0x0800C000', '', '', '', '', '']
                        After setting the new value ['0x0800C000', '', '', '', '', '']
                        Result of setData: True
                        [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                        Before setting the new value ['0x0800C000', '', '', '', '', '']
                        After setting the new value ['0x0800C000', '0x0800C004', '', '', '', '']
                        Result of setData: True
                        [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                        Before setting the new value ['0x0800C000', '0x0800C004', '', '', '', '']
                        After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '', '', '']
                        Result of setData: True
                        [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                        Before setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '', '', '']
                        After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '', '']
                        Result of setData: True
                        [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                        Before setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '', '']
                        After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '']
                        Result of setData: True
                        [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                        Before setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '']
                        After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                        Result of setData: True
                        Done
                        Fetching data from column: 0; row: 0
                        Data: 0x0800C000
                        Fetching data from column: 0; row: 1
                        Data: 0x0800C004
                        Fetching data from column: 0; row: 2
                        Data: 0x0800C008
                        Fetching data from column: 0; row: 3
                        Data: 0x0800C00C
                        Fetching data from column: 0; row: 4
                        Data: 0x0800C010
                        Fetching data from column: 0; row: 5
                        Data: 0x0800C014
                        

                        Current tableView: https://imgur.com/5HMxhrx

                        What do you think?

                        JonBJ 1 Reply Last reply
                        1
                        • Carlos DiazC Carlos Diaz

                          @JonB Thanks for being so patient with my mistakes.

                          I think I had added everything you suggested and removed the self.layoutChanged.emit() call and the view keeps working!

                          I don't know if it's possible to add the new rows inside the setData function, so it's not handled on the application level?

                          Here's the updated code:

                          #!/usr/bin/env python3
                          
                          from fbs_runtime.application_context.PySide2 import ApplicationContext
                          
                          from PySide2.QtCore import *
                          from PySide2.QtWidgets import *
                          from PySide2.QtGui import QIntValidator
                          from PySide2.QtUiTools import QUiLoader
                          
                          import sys
                          
                          '''
                          QAbstractTableModel provides a standard interface for models that represent their
                          data as a two-dimensional array of items. It is not used directly, but must be
                          subclassed.
                          
                          Since the model provides a more especialized interface than QAbstractItemModel,
                          it is not suitable for use with tree views, although it can be used to provide
                          data to a QListView.
                          If you need to represent a simple list of items, and only need a model to contain
                          a single column of data, subclassing the QAbstractListModel may be more appropiate.
                          
                          The rowCount() and columnCount() functions return the dimensions of the table.
                          To retrieve a model index corresponding to an item in the model, use index()
                          and provide only the row and column numbers.
                          
                          Editable models need to implement setData(), and implement flags() to return a value
                          containing ItemsIsEditable.
                          
                          Models that provide interfaces to resizable data structures can provide implementations of:
                           - insertRows()
                           - removeRows()
                           - insertColumns()
                           - removeColumns()
                           
                          When implementing these functions, it is important to call the appropiate functions
                          so that all connected views are aware of any changes.
                          
                          Role enum:
                          https://doc.qt.io/qt-5/qt.html#ItemDataRole-enum
                          
                          Useful links:
                          https://doc.qt.io/qtforpython/PySide2/QtCore/QAbstractTableModel.html
                          https://doc.qt.io/qtforpython/tutorials/datavisualize/index.html
                          https://stackoverflow.com/questions/50391050/how-to-remove-row-from-qtreeview-using-qabstractitemmodel
                          https://github.com/pyside/Examples/blob/master/examples/itemviews/editabletreemodel/editabletreemodel.py
                          '''
                          class TestModel(QAbstractTableModel):
                              def __init__(self):
                                  QAbstractTableModel.__init__(self)
                                  
                                  # Here we keep the data
                                  self.display = []
                          
                              def rowCount(self, parent=QModelIndex()):
                                  return len(self.display)
                          
                              def columnCount(self, parent=QModelIndex()):
                                  COLUMNS_WIDTH_SIZE = 1
                                  return COLUMNS_WIDTH_SIZE
                          
                              def setData(self, index, value, role=Qt.EditRole):
                                  '''
                                  Adjust the data (set it to value <value>) depending on the given index
                                  and role
                                  '''
                          
                                  if role != Qt.EditRole:
                                      print(f'[SET_DATA] Role is not EditRole')
                                      return False
                          
                                  # We must be sure we add the new value into a valid index of the model
                                  # So we validate the index, we make sure the index row isn't 0 or less
                                  # and that the amount of current rows is more than the index row we are
                                  # adding the value to.
                                  if index.isValid() and 0 <= index.row() < self.rowCount():
                                      
                                      print(f'[SET_DATA] DATA: {value} index row: {index.row()}; column {index.column()}')
                                      if index.column() == 0:
                                          print(f'Before setting the new value {self.display}')
                                          self.display[index.row()] = value
                                          print(f'After setting the new value {self.display}')
                                      else:
                                          return False
                                      
                                      self.dataChanged.emit(index, index)
                                      return True
                          
                                  return False
                          
                              def flags(self, index):
                                  '''
                                  Set the item flags at the given index. Seems like we're implementing
                                  this function just to see ho it's done, as we manually adjust each
                                  tableView to have NoEditTriggers.
                                  '''
                          
                                  if not index.isValid():
                                      return Qt.ItemIsEnabled
                                  return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsEditable)
                          
                              def insertRows(self, position, rows=1, index=QModelIndex()):
                                  '''
                                  Insert a row from the model.
                                  '''
                                  
                                  self.beginInsertRows(QModelIndex(), position, position + rows - 1)
                          
                                  print(f'Inserting {rows} rows at {position}')
                          
                                  # We extend the list with rows elements
                                  self.display.extend([''] * rows)
                          
                                  self.endInsertRows()
                          
                                  return True
                          
                              def removeRows(self, position, rows=1, index=QModelIndex()):
                                  '''
                                  Remove a row from the model.
                                  '''
                                  
                                  self.beginRemoveRows(QModelIndex(), position, position + rows - 1)
                          
                                  print(self.display)
                                  
                                  print(f'Removing {rows} rows from {position} to {position+rows}')
                                  del self.display[position:position+rows]
                          
                                  print(self.display)
                          
                                  self.endRemoveRows()
                          
                                  return True
                          
                              def insertColumns(self, column, count, parent):
                                  print(f'insert {count} columns at {column}')
                          
                              def removeColumns(self):
                                  pass
                          
                              def data(self, index, role=Qt.DisplayRole):
                          
                                  if not index.isValid():
                                      print(f'invalid index {index}')
                                      return None
                                  
                                  if role != Qt.DisplayRole and role != Qt.EditRole:
                                      return None
                          
                                  column = index.column()
                                  row = index.row()
                          
                                  print(f'Fetching data from column: {column}; row: {row}')
                                  
                                  if column == 0:
                                      tmp = self.display[index.row()]
                                      print(f'Data: {tmp}')
                                      return tmp
                                  else:
                                      return None
                          
                              def headerData(self, section, orientation, role):
                                  if role == Qt.DisplayRole and orientation == Qt.Horizontal:
                                      if section == 0:
                                          return 'Address'
                          
                          class AppContext(ApplicationContext):
                              def run(self):
                          
                                  self.app.setStyle('Fusion')
                          
                                  ui_file = self.get_resource("mainwindow.ui")
                                  self.file = QFile(ui_file)
                                  self.file.open(QFile.ReadOnly)
                                  self.loader = QUiLoader()
                                  self.window = self.loader.load(self.file)
                          
                                  self.window.updateView.clicked.connect(self.onUpdateView)
                          
                                  self.address_list = ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                          
                                  self.model = TestModel()
                                  self.window.tableView.setModel(self.model)
                          
                                  # Add a row for the default data..
                                  self.model.insertRows(0)
                                  first_index = self.model.createIndex(0, 0)
                                  self.model.setData(first_index, self.address_list[0], Qt.EditRole)
                                  
                                  self.window.tableView.show()
                                  
                                  # Show the application to the user        
                                  self.window.show()
                                  return self.app.exec_()
                          
                              def onUpdateView(self):
                                  print(f'Updating view...')
                                  
                                  print(f'We have {self.model.rowCount()} rows')
                          
                                  # Insert rows for new data
                                  rows_to_add = len(self.address_list)
                                  current_rows = self.model.rowCount()
                          
                                  rows_to_add -= current_rows
                                  print(f'Inserting {rows_to_add} new rows for the new data')
                                  self.model.insertRows(0, rows_to_add)
                                  print(f'We now have {self.model.rowCount()} rows')
                          
                                  print(f'Inserting new data into the model...')
                                  for row, address in enumerate(self.address_list):
                                      column = 0
                                      idx = self.model.createIndex(row, column)
                                      tmp = self.model.setData(idx, address, Qt.EditRole)
                                      print(f'Result of setData: {tmp}')
                          
                                  print('Done')
                          
                          if __name__ == '__main__':
                              appctxt = AppContext()
                              exit_code = appctxt.run()
                              sys.exit(exit_code)
                          

                          Output log:

                          Inserting 1 rows at 0
                          [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                          Before setting the new value ['']
                          After setting the new value ['0x0800C000']
                          Fetching data from column: 0; row: 0
                          Data: 0x0800C000
                          Fetching data from column: 0; row: 0
                          Data: 0x0800C000
                          Updating view...
                          We have 1 rows
                          Inserting 5 new rows for the new data
                          Inserting 5 rows at 0
                          We now have 6 rows
                          Inserting new data into the model...
                          [SET_DATA] DATA: 0x0800C000 index row: 0; column 0
                          Before setting the new value ['0x0800C000', '', '', '', '', '']
                          After setting the new value ['0x0800C000', '', '', '', '', '']
                          Result of setData: True
                          [SET_DATA] DATA: 0x0800C004 index row: 1; column 0
                          Before setting the new value ['0x0800C000', '', '', '', '', '']
                          After setting the new value ['0x0800C000', '0x0800C004', '', '', '', '']
                          Result of setData: True
                          [SET_DATA] DATA: 0x0800C008 index row: 2; column 0
                          Before setting the new value ['0x0800C000', '0x0800C004', '', '', '', '']
                          After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '', '', '']
                          Result of setData: True
                          [SET_DATA] DATA: 0x0800C00C index row: 3; column 0
                          Before setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '', '', '']
                          After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '', '']
                          Result of setData: True
                          [SET_DATA] DATA: 0x0800C010 index row: 4; column 0
                          Before setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '', '']
                          After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '']
                          Result of setData: True
                          [SET_DATA] DATA: 0x0800C014 index row: 5; column 0
                          Before setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '']
                          After setting the new value ['0x0800C000', '0x0800C004', '0x0800C008', '0x0800C00C', '0x0800C010', '0x0800C014']
                          Result of setData: True
                          Done
                          Fetching data from column: 0; row: 0
                          Data: 0x0800C000
                          Fetching data from column: 0; row: 1
                          Data: 0x0800C004
                          Fetching data from column: 0; row: 2
                          Data: 0x0800C008
                          Fetching data from column: 0; row: 3
                          Data: 0x0800C00C
                          Fetching data from column: 0; row: 4
                          Data: 0x0800C010
                          Fetching data from column: 0; row: 5
                          Data: 0x0800C014
                          

                          Current tableView: https://imgur.com/5HMxhrx

                          What do you think?

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #11

                          @Carlos-Diaz
                          Please no more log output, it's not telling us anything! :)

                          You need have the following:

                          In setData() you must return False if the row is greater than the number of rows currently in the model:

                          if index.isValid() and 0 <= index.row() < self.rowCount():
                              ....
                          else:
                              return False
                          

                          I see you have that now.

                          In onUpdateView you must call insertRows(), either to insert at the start or at the end or the existing rows, and then setData() on each of the newly inserted rows.

                          You also seem to have that now.

                          So I would say what you have looks correct!

                          It may or may not be possible to call the insertRows() from within setData(), but I don't think that is setData()'s job anyway. It is correct that it should instead return False, and the coder must explicitly call insertRows() outside himself to add new rows. This is the way the model is designed to behave. That is why you are now able to say

                          removed the self.layoutChanged.emit() call and the view keeps working!

                          :)

                          Carlos DiazC 1 Reply Last reply
                          0
                          • JonBJ JonB

                            @Carlos-Diaz
                            Please no more log output, it's not telling us anything! :)

                            You need have the following:

                            In setData() you must return False if the row is greater than the number of rows currently in the model:

                            if index.isValid() and 0 <= index.row() < self.rowCount():
                                ....
                            else:
                                return False
                            

                            I see you have that now.

                            In onUpdateView you must call insertRows(), either to insert at the start or at the end or the existing rows, and then setData() on each of the newly inserted rows.

                            You also seem to have that now.

                            So I would say what you have looks correct!

                            It may or may not be possible to call the insertRows() from within setData(), but I don't think that is setData()'s job anyway. It is correct that it should instead return False, and the coder must explicitly call insertRows() outside himself to add new rows. This is the way the model is designed to behave. That is why you are now able to say

                            removed the self.layoutChanged.emit() call and the view keeps working!

                            :)

                            Carlos DiazC Offline
                            Carlos DiazC Offline
                            Carlos Diaz
                            wrote on last edited by
                            #12

                            @JonB Thanks for the help, now I need to migrate this into the final application.
                            I will mark the issue as solved.

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved