Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. dataChanged signal not reaching TableView unless I add 1 line of unrelated javascript
Forum Update on Monday, May 27th 2025

dataChanged signal not reaching TableView unless I add 1 line of unrelated javascript

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 2 Posters 630 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.
  • O Offline
    O Offline
    ocgltd
    wrote on 22 Jan 2022, 16:00 last edited by ocgltd
    #1

    I am creating a simple TableView in QML, 5 col wide by 4 rows tall. This table connects to a QSortFilterProxyModel, which connects to a QAbstractTableModel. When I call the sort method of the QSFPM my table refreshes as expected and works great.

    Now, I am trying to highlight a row of my table; the row delegate just uses BLUE as the background color instead of WHITE if that row is selected.The ItemSelectionModel appears to work properly (printing the selected row).

    However, my table does not refresh (confirmed with console.log statements in the table). It's as if the dataChanged signal is not reaching my table (though calling the resort method in this same class DOES cause the table to refresh).

    As you will see in the last comment below, adding one unrelated line of Javascript causes the dataChanged signal to have the desired effect. Why?

    Source file companysortfilterproxymodel.cpp (descends from QSortFilterProxyModel):

    import QtQuick 2.15
    import QtQuick.Window 2.15
    import QtQuick.Controls 2.15
    import Qt.labs.qmlmodels 1.0
    import QtQml.Models 2.15
    
    Item {
        id: companyTable
        readonly property int minWidth: 300
        readonly property int maxWidth: 700
        property int parentWidth: parent.width
    
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        anchors.left: parent.left
    
        // Create the company sort filter proxy model only when the company table is showing
        CompanySortFilterProxyModel {
            id: companySFPM
        }
    
        // Show the company table view
        TableView {
            id: companyTableView
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.top: companyTableHeader.bottom
            anchors.bottom: parent.bottom
            clip: true
    
            // columnWidthProvider Allow for dynamic col width when screen size changes
            columnWidthProvider: function (column) { return colWidth(column) }
    
            // sets the model to be displayed in this view
            model: companySFPM
    
    
            delegate:
                DelegateChooser {
                role: "displayStyle"
                DelegateChoice {
                    roleValue: "Number"
                    delegate: Rectangle {
                        // I chose 50 as the height for each row of the table because it looks good
                        implicitHeight: 50
                        // Color every other row light gray
                        color: getColor(row)
    
                        Text {
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.right: parent.right
                            anchors.rightMargin: 10
                            // Left padding of 10
                            width: colWidth(0) - 20
                            wrapMode: Text.Wrap
                            text: model.data
                        }
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                console.log("Clicked on row - number")
                                selectRow(row);
                            }
                        }
                    }
                }
    
                // This delegate choice is used for creating all table cells that are in the company name column
                DelegateChoice {
                    roleValue: "CompanyName"
                    delegate: Rectangle {
                        // I chose 50 as the height for each row of the table because it looks good
                        implicitHeight: 50
                        // Color every other row light gray
                        color: getColor(row)
    
                        Text {
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.right: parent.right
                            anchors.rightMargin: 10
                            // Left padding of 10
                            width: colWidth(1) - 20
                            wrapMode: Text.Wrap
                            text: model.data
    
                        }
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                console.log("Clicked on row - companyName")
    
                                selectRow(row);
                            }
                        }
                    }
                }
    
                // This delegate choice is used for creating all table cells that contain checkmarks of boolean type
                DelegateChoice {
                    roleValue: "CheckMark"
                    delegate: Rectangle {
                        implicitHeight: 50
                        // Color every other row light gray
                        color: getColor(row)
    
                        Image {
                            anchors.centerIn: parent
                            visible: model.data
                            source: MediaManager.assetPath("img/black_icons/checkmark.svg", Qt.resolvedUrl("."))
                        }
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                console.log("Clicked on row - checkmark");
                                selectRow(row);
                            }
                        }
                    }
                }  // DeletgateChoice
            }  // Delegate
    
            /*
            ScrollBar.vertical: ScrollBar {
                anchors.top: companyTableView.top
                anchors.bottom: companyTableView.bottom
    
            }
            */
        }  // Tableview
    
        // Create header containing column name and up/down arrow for sort state
        HorizontalHeaderView {
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
    
            id: companyTableHeader
            syncView: companyTableView
            reuseItems: false
    
            // The column that is currently being used for sorting
            property int sortingColumn : 0
            // stores a state for each column representing whether the triangle is pointing down
            property var state_sortArrowDown : []
            // This variable holds whether a new column has been selected on the most recent click
            // This variable starts as true so that the triangle does not animate at the start of the program
            property bool newColumnSelected : true
    
            // Pass the label and column number as parameters into the header delegate
            delegate: ColumnHeader {
                label: model.display
                columnNum: index
            }
    
            // This block runs only once when headerview is created
            Component.onCompleted: {
                // Set all columns to start as sort ascending
                var index;
                for(index = 0; index < companySFPM.columnCount(); index++) {
                    state_sortArrowDown[index] = false;
                }
            }
        }
    
        ItemSelectionModel {
            id: companyTableISM
            model: companySFPM
        }
    
        function selectRow(row) {
            console.log("In selectRow row "+row);
            companyTableISM.select(companySFPM.index(row, 0), ItemSelectionModel.Current | ItemSelectionModel.Toggle);
            console.log(companyTableISM.selectedIndexes);
            console.log(companyTableISM.hasSelection);
        }
    

    (I have removed all C++ from this question, so now it's purely QML related - perhaps someone could move to QML forum)

    1 Reply Last reply
    0
    • Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 22 Jan 2022, 16:13 last edited by
      #2

      Why do you need to call dataChanged() when you select a row? Don't see a relation between a selection color and the model's data.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      O 1 Reply Last reply 22 Jan 2022, 17:33
      0
      • Christian EhrlicherC Christian Ehrlicher
        22 Jan 2022, 16:13

        Why do you need to call dataChanged() when you select a row? Don't see a relation between a selection color and the model's data.

        O Offline
        O Offline
        ocgltd
        wrote on 22 Jan 2022, 17:33 last edited by ocgltd
        #3

        @Christian-Ehrlicher When I click a row in my table I want it to be 'selected' (and shown by changing color). I do so by tracking the row selected, and in my TableView row delegate I check if THIS row is the selected one, and if so I use BLUE as the background color; otherwise I use white.

        I need some way to tell the table to redraw the row in question, to use the new color. So I want to use the datachanged signal to notify the table to redraw that row. (I assume that's the right way to achieve what I want)....

        1 Reply Last reply
        0
        • Christian EhrlicherC Online
          Christian EhrlicherC Online
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on 22 Jan 2022, 18:01 last edited by
          #4

          When the selection changes, the old selected row and the new one is redrawn automatically - otherwise you won't see a difference between a selected and unselected row. No need to store this information anywhere since the view already knows about it. The information is available in https://doc.qt.io/qt-5/qstyleoption.html#state-var in https://doc.qt.io/qt-5/qstyleditemdelegate.html#paint

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          O 1 Reply Last reply 22 Jan 2022, 19:22
          2
          • Christian EhrlicherC Christian Ehrlicher
            22 Jan 2022, 18:01

            When the selection changes, the old selected row and the new one is redrawn automatically - otherwise you won't see a difference between a selected and unselected row. No need to store this information anywhere since the view already knows about it. The information is available in https://doc.qt.io/qt-5/qstyleoption.html#state-var in https://doc.qt.io/qt-5/qstyleditemdelegate.html#paint

            O Offline
            O Offline
            ocgltd
            wrote on 22 Jan 2022, 19:22 last edited by
            #5

            @Christian-Ehrlicher I must be doing something else wrong...let me expand (and update my question). In my table delegate I have a mouse area, which passes the clicked row number to my "selectRow" method - which is now provided in the question above.

            My selectRow method toggles selection for cell 0 of the clicked row, and the onSelectionChanged slot calls my emitDataChanged method. So if the table should recolor the selection on it's own, shouldn't column 0 highlight itself?

            1 Reply Last reply
            0
            • Christian EhrlicherC Online
              Christian EhrlicherC Online
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on 22 Jan 2022, 19:27 last edited by
              #6

              Why do you want to toggle your current selection? Should column 0 not be selectable?
              Selection has nothing to do with dataChanged() so calling dataChanged() after changing a selection is not needed.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              O 1 Reply Last reply 22 Jan 2022, 19:43
              0
              • Christian EhrlicherC Christian Ehrlicher
                22 Jan 2022, 19:27

                Why do you want to toggle your current selection? Should column 0 not be selectable?
                Selection has nothing to do with dataChanged() so calling dataChanged() after changing a selection is not needed.

                O Offline
                O Offline
                ocgltd
                wrote on 22 Jan 2022, 19:43 last edited by
                #7

                @Christian-Ehrlicher My goals is to be able to select one (and only row) of the table by clicking on it. If I click the same row again I want to deselect it. Once selected, I want the background color of the row to change.

                Sounds like I'm on the wrong path. What is the right way to achieve this? As it stands now nothing changes color (even though my ItemSelectionModel says I have selected the (row,0) column clicked on.

                1 Reply Last reply
                0
                • Christian EhrlicherC Online
                  Christian EhrlicherC Online
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on 22 Jan 2022, 19:48 last edited by
                  #8

                  A normal view will draw the selected row in another color. Why it's not in your case - don't know. First remove your custom delegate.

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  O 2 Replies Last reply 22 Jan 2022, 20:32
                  0
                  • Christian EhrlicherC Christian Ehrlicher
                    22 Jan 2022, 19:48

                    A normal view will draw the selected row in another color. Why it's not in your case - don't know. First remove your custom delegate.

                    O Offline
                    O Offline
                    ocgltd
                    wrote on 22 Jan 2022, 20:32 last edited by ocgltd
                    #9
                    This post is deleted!
                    1 Reply Last reply
                    0
                    • Christian EhrlicherC Christian Ehrlicher
                      22 Jan 2022, 19:48

                      A normal view will draw the selected row in another color. Why it's not in your case - don't know. First remove your custom delegate.

                      O Offline
                      O Offline
                      ocgltd
                      wrote on 23 Jan 2022, 15:45 last edited by
                      #10
                      This post is deleted!
                      O 1 Reply Last reply 23 Jan 2022, 21:47
                      0
                      • O ocgltd
                        23 Jan 2022, 15:45

                        This post is deleted!

                        O Offline
                        O Offline
                        ocgltd
                        wrote on 23 Jan 2022, 21:47 last edited by
                        #11

                        I got it working - but can't explain why. I confirmed the dataChanged signal is being emitted and received in my class above. However, the table just does not redraw (getColor function is never called).

                        However, if I add the ONE line of code below (in getColor), then the table redraws as expected!! (Putting this line into 'getColor' results in the signal causing the table to refresh, which causes 'getColor' to execute). Why?

                        function getColor(row) {
                              console.log("In getColor");
                               var i = companyTableISM.selectedIndexes;  // <--- WHY DO I NEED THIS LINE
                               if (companyTableISM.isSelected(companySFPM.index(row, 0)))
                        
                        
                        1 Reply Last reply
                        0

                        1/11

                        22 Jan 2022, 16:00

                        • Login

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