c++qtqmltableview

How to get TableView with exapanding columns


I'm trying to get TableView (the new one from pure qml introdudced in qt5.12) with column which resize them dynamically to fill extra available space but It's not working

here is my minimal reproducible example:-

main.qml:-

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

Window {
    id: window
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    TableView {
        anchors.fill: parent
        model: KoolModel
//        columnWidthProvider: function (_) { return parent.width/3} // Method 1, Does not work
        delegate: Frame {
//            implicitWidth: parent.width/3 //Method 2, Does not work
            implicitWidth: 640/3 // works but not the solution for my problem
            Label {
                text: display
                anchors.centerIn: parent
            }
        }
    }
}

If I execute this code, I get following:-

enter image description here

it is the desired output but when I resize the window the columns should expand which does not happen due to hardcoding the implicitWidth

enter image description here

if I use columnWidthProvider: function (_) { return parent.width/3} then I get nothing, just a white window:-

enter image description here

and If I try to use binding like this implicitWidth: parent.width/3 I get following:-

enter image description here

main.cpp:-

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "models/exams.hpp"

int main(int argc, char* argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    Models::Exams exams;
    engine.rootContext()->setContextProperty("KoolModel", &exams);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    engine.load(url);

    return app.exec();
}

models/exam.cpp

#pragma once

#include <QAbstractTableModel>
#include <QString>
#include <map>

namespace Models {

class Exams : public QAbstractTableModel {

private:
    struct DS {
        QString title;
        unsigned int marks;
        int state;
        std::vector<int>* questions = nullptr;
    };

    //id and exams
    std::map<int, DS> exams;

public:
    Exams();

    // QAbstractItemModel interface
    int rowCount(const QModelIndex& parent) const override;
    int columnCount(const QModelIndex& parent) const override;
    QVariant data(const QModelIndex& index, int role) const override;

    // QAbstractItemModel interface
public:
    QHash<int, QByteArray> roleNames() const override;
};

} //end namespace Models

models/exam.cpp:-

#include "exams.hpp"

namespace Models {

Exams::Exams()
{
    for (int i = 0; i < 200; i++) { //fill garbage data for now
        DS exam {
            "Exam" + QString::number(i),
            0,
            (i * 3) / 2,
            nullptr
        };

        exams[i] = exam;
    }
    exams[2] = {
        "Exam" + QString::number(10000000324),
        0,
        10,
        nullptr
    };
}

int Exams::rowCount(const QModelIndex& parent) const
{
    return exams.size();
}

int Exams::columnCount(const QModelIndex& parent) const
{
    return 3;
}

QVariant Exams::data(const QModelIndex& index, int role) const
{
    if (role == Qt::DisplayRole) {
        if (index.column() == 0)
            return exams.at(index.row()).title;
        else if (index.column() == 1)
            return exams.at(index.row()).marks;
        else if (index.column() == 2)
            return exams.at(index.row()).state;
    }
    return QVariant();
}

QHash<int, QByteArray> Exams::roleNames() const
{
    return { { Qt::DisplayRole, "display" } };
}

} // end namepsace Models

I'm using Qt 5.15 from Archlinux repos


Solution

  • For performance reasons, TableView does not re-calculate its row height or column width unless absolutely necessary. But you can force it by calling forceLayout() whenever the width changes.

    onWidthChanged: forceLayout()