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. Custom QAbstractTableModel class updating QTableView

Custom QAbstractTableModel class updating QTableView

Scheduled Pinned Locked Moved Solved General and Desktop
qabstracttablemqtableviewc++datachangedqt5
13 Posts 2 Posters 5.8k 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.
  • S Sebbo

    Hi raven-worx,

    thanks for your reply!!
    The loadFromFile() method looks as follows:

    bool QCsvTableModel::loadFromFile(const QString &fileName, const QChar &delim)
    {
        csvMatrix.clear();
        QChar delimiter;
        QFile file(fileName);
    
        if (delim == 0) {
            QString extension = QFileInfo(file).completeSuffix();
            if (extension.toLower() == "csv")
                delimiter = QChar(';');
        }
        else if (delim == QChar('"'))
                return false; // The only invalid delimiter is double quote (")
        else
            delimiter = delim;
        if (!file.isOpen())
            if (!file.open(QFile::ReadOnly|QFile::Text))
                return false;
    
        QString temp;
        QChar lastCharacter;
        QTextStream in(&file);
        QList<QString> row;
    
        while (true) {
            QChar character;
            in >> character;
            if (in.atEnd()) {
                if (lastCharacter == delimiter) // Cases where last character is equal to the delimiter
                    temp = "";
                checkString(temp, row, csvMatrix, delimiter, QChar('\n'));
                break;
            } else if (character == delimiter || character == QChar('\n'))
                checkString(temp, row, csvMatrix, delimiter, character);
            else {
                temp.append(character);
                lastCharacter = character;
            }
        }
    
        /*
        int row1 = csvMatrix.rowCount();
        QModelIndex index;
        beginInsertRows(QModelIndex(), row1, row1 + index.row() - 1);
        QModelIndex transposedIndex = createIndex(index.column(), index.row());
        emit dataChanged(transposedIndex, transposedIndex);
        emit layoutChanged();
        endInsertRows();
        */
    
        file.close();
        in.flush();
        in.reset();
    
        return true;
    }
    

    As you can see I already tried to emit the dataChanged signal from there but nothing happened.

    raven-worxR Offline
    raven-worxR Offline
    raven-worx
    Moderators
    wrote on last edited by raven-worx
    #4

    @Sebbo
    First please make sure that the connect() call returns true. If not check the console output for the cause.

    Also no line of this code makes any (functional) sense:

    int row1 = csvMatrix.rowCount();
    QModelIndex index;
    beginInsertRows(QModelIndex(), row1, row1 + index.row() - 1);
    QModelIndex transposedIndex = createIndex(index.column(), index.row());
    emit dataChanged(transposedIndex, transposedIndex);
    emit layoutChanged();
    endInsertRows();
    

    As i said the correct approach for the loadFromFile() method would be to call beginRestModel() at the beginning of the method and endRestModel() at the end of the method. No dataChanged(), no beginInsertRows(), no layoutChanged(), etc. signals ...

    The dataChanged() signal should only called for already existing indexes.

    --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
    If you have a question please use the forum so others can benefit from the solution in the future

    1 Reply Last reply
    0
    • S Offline
      S Offline
      Sebbo
      wrote on last edited by
      #5

      @raven-worx

      I forgot to tell that I tested the method with beginResetModel() and endResetModel() as well (without trying to emit all the signals) which didn't do the trick. My apologies.

      The connect() call returns true.

      raven-worxR 1 Reply Last reply
      0
      • S Sebbo

        @raven-worx

        I forgot to tell that I tested the method with beginResetModel() and endResetModel() as well (without trying to emit all the signals) which didn't do the trick. My apologies.

        The connect() call returns true.

        raven-worxR Offline
        raven-worxR Offline
        raven-worx
        Moderators
        wrote on last edited by raven-worx
        #6

        @Sebbo
        but to make sure i didn't mean that the beginResetModel()/endResetModel() signals do internally emit the dataChanged() singal! Instead they emit modelAboutToBeReset() and modelReset() respectively.

        Whats do you actually want to achieve in the onModelsDataChanged() slot?

        --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
        If you have a question please use the forum so others can benefit from the solution in the future

        1 Reply Last reply
        0
        • S Offline
          S Offline
          Sebbo
          wrote on last edited by
          #7

          @raven-worx
          Thank you for the effort!!

          For testing purposes I've added a pushbutton which adds a row with some foo-text to the csv file. But since I wasn't able to show the newly stored data inside the qtableview I wanted to see whether the dataChanged() signal is emitted and calls the method with just a console output.
          What I've done in first place was to repaint() / update() the tableview inside the onModelsDataChanged() method.

          raven-worxR 1 Reply Last reply
          0
          • S Sebbo

            @raven-worx
            Thank you for the effort!!

            For testing purposes I've added a pushbutton which adds a row with some foo-text to the csv file. But since I wasn't able to show the newly stored data inside the qtableview I wanted to see whether the dataChanged() signal is emitted and calls the method with just a console output.
            What I've done in first place was to repaint() / update() the tableview inside the onModelsDataChanged() method.

            raven-worxR Offline
            raven-worxR Offline
            raven-worx
            Moderators
            wrote on last edited by raven-worx
            #8

            @Sebbo
            ok here are my thoughts:

            The simplest approach is the "static" one. It just displays the contents of the csv file at the time it is opened:

            • in the loadFromFile() method do like i said and use the reset mechanism; the reset tells the view that it should forget all about what it knows from the model and that it should get all the data again

            The disadvantage of the rest-method is that the view looses it's selection, scroll position, current index, etc.

            For a more "dynamic" approach you need to do this:

            1. implement the same loadFromFile() method like for the "static" approach. But additionally you also install an QFileSystemWatcher on that file and connect it's fileChanged() signal to a new slot called something like "csvFileContentsChanged"
            2. in the loadFromFile() method you need to uninstall the old QFileSystemWatcher everytime a new/different file is set
            3. also save the count of lineNumbers read from the csv file
            4. in the new csvFileContentsChanged slot read the csv file line by line and compare the new line count to the previously stored one. If the new line count is higher you need to call beginInsertRows()/endInsertRows() signals, if the new count is smaller you need to call beginRemoveRows()/endRemoveRows(). And dataChanged() for the rest of the indexes which are already there.

            Pseudo code:

            void csvFileContentsChanged()
            {
                 // read cvs file again into a local "tmpCsvMatrix" temporary variable
            
                 int newLineCount = ...;
                 int diff = qAbs( newLineCount - oldLineCount );
            
                if( newLineCount < oldLineCount )
                {
                        beginRemoveRows( QModelindex(), newLineCount, newLineCount + diff - 1 );
                            csvMatrix = tmpCsvmatrix;
                        endRemoveRows();
                }
                else if( newLineCount > oldLineCount )
                {
                       beginInsertRows( QModelindex(), oldLineCount, oldLineCount + diff - 1 );
                            csvMatrix = tmpCsvMatrix;
                        endInsertRows();
                }
            
                // emit dataChanged for the rest of the indexes, since we do not know if their content actually has changed inside the csv file
                if( rowCount() > 0 && columnsCount() > 0 )
                      emit dataChanged( index(0, columnCount()-1), index(newLineCount-1 ,columnCount()-1) );
            }
            

            I haven't tested this though.

            --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
            If you have a question please use the forum so others can benefit from the solution in the future

            1 Reply Last reply
            1
            • S Offline
              S Offline
              Sebbo
              wrote on last edited by
              #9

              @raven-worx

              Thank you so much for your efforts and thoughts!!!
              I like the idea of your 2nd dynamic approach but I have to admit that the 1st one still doesn't work for me.

              beginResetModel();
              csvMatrix.clear();
              endResetModel();
              

              doesn't update the QTableView neither if new data is added outside Qt nor if the QPushButton is clicked which opens the file, writes into it (QTextStream) and closes it afterwards. :(

              raven-worxR 1 Reply Last reply
              0
              • S Sebbo

                @raven-worx

                Thank you so much for your efforts and thoughts!!!
                I like the idea of your 2nd dynamic approach but I have to admit that the 1st one still doesn't work for me.

                beginResetModel();
                csvMatrix.clear();
                endResetModel();
                

                doesn't update the QTableView neither if new data is added outside Qt nor if the QPushButton is clicked which opens the file, writes into it (QTextStream) and closes it afterwards. :(

                raven-worxR Offline
                raven-worxR Offline
                raven-worx
                Moderators
                wrote on last edited by raven-worx
                #10

                @Sebbo
                because is said you should trigger these signals at the beginning and the end of the loadFromFile() method. Mens the very first and very last call inside the method.
                Between those 2 signal calls you need to update your data structure.

                --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                If you have a question please use the forum so others can benefit from the solution in the future

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  Sebbo
                  wrote on last edited by
                  #11

                  @raven-worx

                  That is exactly what I'm not getting right now. Don't get me wrong I know where to put the begin/endReset members of the model but I'm embarrassingly lost on how to update the data in between....

                  raven-worxR 1 Reply Last reply
                  0
                  • S Sebbo

                    @raven-worx

                    That is exactly what I'm not getting right now. Don't get me wrong I know where to put the begin/endReset members of the model but I'm embarrassingly lost on how to update the data in between....

                    raven-worxR Offline
                    raven-worxR Offline
                    raven-worx
                    Moderators
                    wrote on last edited by raven-worx
                    #12

                    @Sebbo
                    in between these 2 signals you just need to replace your csvMatrixvariable, thats all
                    Since you take all the model data from this variable

                    --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                    If you have a question please use the forum so others can benefit from the solution in the future

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      Sebbo
                      wrote on last edited by
                      #13

                      @raven-worx
                      Jackpot! Thank you so much for your help!! Finally I did it using QFileSystemWatcher.
                      Thumbs up for you (if possible?!). :)

                      Thread marked as solved.
                      Cheers

                      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