[solved] TableView with a rowDelegate should select newly added item



  • Ive got a TableView which displays a model derived from QAbstractListModel. Im using an item and row delegates to heavily customize the appearance. To show the user the currently selected row I am drawing a rectangle around the row. My understanding of "selected" is the last row the user clicked or I set using the code tableView.selection.select(rowIndex)

    When an item is added to the model it is shown correctly in the table. However, I would like this row to become the selected row.

    I have tried to achieve this using the model's onRowsInserted signal which works in most situations. If the new new row is at the end on the model then I have a problem. Inside the onRowsInserted handler, the TableView does not yet have the new item at the end and therefore I cannot select it.

    Here is my onRowsInserted code:

        Connections {
            target: tableView.model
            onRowsInserted: {
                console.log("sessionUsers rows inserted")
    
                // row has been added to model but is not yet shown in the tableView
                // so this does NOT work when the new row is the last item in the table
    
                tableView.selection.clear()
                tableView.currentRow = last
                tableView.selection.select(last)
                tableView.activated(last) // doesnt seem to do anything
            }
        }
    

    My "selected indicator" inside the rowDelegate is set visible using visible: styleData.selected ? true : false


  • Moderators

    @KiNgFrUiT Use onRowCountChanged handler instead. In this way there will be a guarantee that new row is added. For eg:

    TableView {
         ...
         rowDelegate: Rectangle {
                color: styleData.selected ? "skyblue" : "white"
                Text {
                    anchors.fill: parent
                    text: styleData.value
                }
          }
         ...
         onRowCountChanged: {
            tableview.selection.clear()
            tableview.selection.select(rowCount-1)
         }
    }
    


  • @p3c0 Thanks for the suggestion. Using your method how can I know which is the new row? The new item can be added anywhere in the model.


  • Moderators

    @KiNgFrUiT The last one is the new one. rowCount-1 will give its index.



  • @p3c0 Thanks again. Your help got me thinking along the right lines and I now have a solution I am happy with. I am including it below to help others who may come across this page. The code has some omissions to keep it brief but everything needed to solve this problem is included. Ive also shown how I sort the items using a proxy model.

    When a row is clicked by the user, it becomes selected.
    When a row is added to the table via the model, it becomes selected.
    When a row is removed from the table via the model, the next row is selected. If this row was at the end of the table, then the previous row is selected. If the table is empty, nothing is selected.

    import org.qtproject.example 1.0 // SortFilterProxyModel
    
    TableView {
       id: tableView
       ...
       
       selectionMode: SelectionMode.SingleSelection
       
       model: SortFilterProxyModel {
          id: proxyModel
          source: userModel
    
          sortOrder: Qt.AscendingOrder
          sortCaseSensitivity: Qt.CaseInsensitive
          sortRole: tableView.getColumn(1).role
       }
                
       property int last:0 // index of the last inserted or deleted item
    
       onRowCountChanged: {
          tableView.selection.clear()
          if(tableView.rowCount > 0) {
             var index = tableView.last
    
             if(index + 1 >= tableView.rowCount) {
                index = tableView.rowCount - 1
             }
    
             tableView.currentRow = index
             tableView.selection.select(index)
             tableView.activated(index)
          }
       }
    
       Connections {
          target: tableView.model
          onModelReset: tableView.last = 0
       }
    
       Connections {
          target: tableView.model
          onRowsRemoved: tableView.last = last
       }
    
       Connections {
          target: tableView.model
          onRowsInserted: tableView.last = last
       }
       
       rowDelegate: Rectangle {
          ...
       
          MouseArea {
          anchors.fill: parent
             onClicked: {
                // clear any other selected row
                tableView.selection.clear()
    
                // select this row
                tableView.currentRow = styleData.row
                tableView.selection.select(styleData.row)
    
                // convert mouse position from delegate to tableview coordinates
                var coordinates = rowDelegate.mapToItem(tableView, mouse.x, mouse.y)
    
                // active and click the appropriate items (internal)
                var clickIndex = tableView.__listView.indexAt(0, coordinates.y + tableView.__listView.contentY)
                if (clickIndex > -1) {
                   if (tableView.__activateItemOnSingleClick) tableView.activated(clickIndex)
                   tableView.clicked(clickIndex)
                }
    
                // consume the mouse event
                mouse.accepted = true
             }
          }      
       }
    }
    

  • Moderators

    @KiNgFrUiT You're Welcome :) Thanks for sharing the complete solution. Also it would be better if you mark the post as solved so that others may know that the post has a solution.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.