Livedaten in QTableView anzeigen lassen



  • Hallo zusammen,

    ich gebe in einer QTableView Daten aus, die ständig aktualisiert werden. Als Model habe ich ein QAbstractTableModel erstellt. Die Tabelle ist zwar nicht groß, aber da die Daten ständig aktualisiert werden, denke ich das es der Performance zu Gute kommt.
    Wenn ich statische Daten an das Model übergebe ist auch alles gut. Da ich die Daten aber durch ein Signal an einen Slot sende, der dann model->insertRows() und model->setData() aufruft, erhalte ich ja quasi in der Tabelle eine Endlosschleife. Das ist die Slot-Funktion, die ständig aufgerufen wird:

    
    QObject::connect(m_videoScreen, &VideoScreen::SendTableItems, this, &QVideoMeter::QAddTableItems);
    
    /**
    * Slot that sets the data by calling functions of QAbstractItemModel. 
    */
    void QVideoMeter::QAddTableItems(QString parameter, QString value)
    {
        if (!m_tableDataModel->GetTableItem().contains({ parameter, value })) {
            m_tableDataModel->insertRows(0, 1, QModelIndex());
            m_tableDataModel->setData(m_tableDataModel->index(0, 0, QModelIndex()), parameter, Qt::EditRole);
            m_tableDataModel->setData(m_tableDataModel->index(0, 1, QModelIndex()), value, Qt::EditRole);
        }
    }
    

    Meine Idee war erst durch den contains-Vergleich, die Daten nur einmalig anzeigen zu lassen. Gesendet werden die Daten ja aber trotzdem noch. Ich denke mal das ist kein guter Stil? Gibt es eine Möglichkeit den Transfer besser umzusetzen? Wenn ich insertRows() außerhalb des Slots aufrufe wird ja nur eine Zeile erstellt.



  • Ein QAbstractTableModel kann man nicht direkt verwenden sondern man muss eine davon abgeleitete Klasse erstellen.

    Und in dieser kannst du dann spezielle Methoden implementieren um neue Daten hinzuzufügen, statt über die generische Model-API zu gehen.

    Da du von einer nicht großen Tabelle sprichst vermute ich dass die Anzahl der möglichen Zeilen ist relativ fix und nur die Werte der Zellen sich verändern. Stimmt das?
    Und jede Zeile besteht aus zwei Spalten (parameter, value).

    Ich vermute das "parameter" ein art Key ist, welcher nur einmal in der Tabelle auftauchen soll.

    Man kann nun das ganze wie folgt implementieren (Wobei ich hier von einem readonly model ausgehe -> Die Daten sollen nicht via dem QTableView veränderbar sein):

    Das ganze zeigt nur die relevanten stellen wo es um das hinzufügen/aktualisieren der Daten geht und ist nicht getestet

    class ExampleModel : public QAbstractTableModel
    {
    public:
         QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
         {
            if (!index.isValid() || role != Qt::DisplayRole || index.colmn() >= 2 || index.row() >= dataList.size())
                return QVariant();
            
            const Data item = dataList[index.row()];
            
            const int column = index.column();
            if (column == 0)
                return item.key;
            else
                return item.value;
         }
         
         void addOrUpdateData(QString parameter, QString value)
         {
             // Check if an item with parameter as key already exists
             for (int i = 0; i < dataList.size(); ++i)
             {
                 Data& item = dataList[i];
                 if (item.key == parameter)
                 {
                     // Item exists alread update value and signal any view about changed data
                    item->value = value;
                    emit(dataChanged(createIndex(i, 1), createIndex(i, 1)));
                    return;
                 }
             }
             
            // Item was not found add it to the end
            const int currentCount = dataList->size();
            beginInsertRows(QModelIndex(), currentCount, currentCount);
    
            Data item;
            item.key = parameter;
            item.value = value;
            dataList.push_back(item);
    
            endInsertRows();
         }
         
    private:
        struct Data
        {
            QString key;
            QString value;
        };
        
        QVector<Data> dataList;
    };
    

    Relevante doku bezüglich Ableitung von Qt AbstractItemModels:
    https://doc.qt.io/qt-5/model-view-programming.html#model-subclassing-reference
    https://doc.qt.io/qt-5/model-view-programming.html#model-classes



  • Hi @firefly,

    habe mich vllt. falsch ausgedrückt. Ich habe eine eigene Model Klasse und hier implementiere ich die folgenden Funktionen:

    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
    QVariant data(const QModelIndex& index, int role) const override;
    bool insertRows(int rows, int count, const QModelIndex& parent) override;
    bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
    int rowCount(const QModelIndex& parent) const override;
    int columnCount(const QModelIndex& parent) const override;
    

    Du machst die Validierung ja schon im Model und fasst die setData und insertRows Funktionen zusammen.
    Hatte mir diverse Beispiele angeschaut und alle implementieren diese beiden Funktionen. Daher war ich mir nicht sicher ob man davon abweichen kann. Dein Beispiel finde ich auf jeden Fall verständlicher.

    Und ja es ist eine Tabelle mit zwei Spalten und ein paar Zeilen.



  • Öhm dann brauchst du nur ne methode wie meine gezeigte addOrUpdateData Methode.
    Und das ist die "spezielle Methoden implementieren um neue Daten hinzuzufügen, statt über die generische Model-API zu gehen."
    Von der ich schrieb



  • @firefly
    Funktioniert. Ich wäre tatsächlich nicht drauf gekommen im Model eine Abfrage bzgl. der doppelten Einträge zu machen...

    insertRows() und setData() benötigt man dann denke ich mal, wenn man Daten aus einer Datenbank lädt und die in der GUI editieren möchte oder?

    Danke!

    EDIT: Eins meiner Missverständnisse war das ich dachte ich brauche ein Editable Model, da die Werte in einer Spalte sich immer ändern. Aber read-only funktioniert es ja auch.



  • @makopo sagte in Livedaten in QTableView anzeigen lassen:

    insertRows() und setData() benötigt man dann denke ich mal, wenn man Daten aus einer Datenbank lädt und die in der GUI editieren möchte oder?

    die beiden methoden werden nur benötigt, wenn via einem View die Daten veränderbar sein sollen.
    Das hat nichts damit zu tun woher das model seine daten inital bekommt.

    siehe auch dass die beiden methode in der Doku https://doc.qt.io/qt-5/model-view-programming.html#model-subclassing-reference unter den sub punkten:

    • Editable items (setData)
    • Resizable models (insertRows)
      aufgelistet sind aber nicht unter "Read-Only access"

Anmelden zum Antworten