Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QTableView using setSpan() doesn't resize as expected



  • Hello! I am relatively new to Qt and am trying to create a QTableView to display a generic Comment structure. I want the table to have 2 rows per model entry where,

    • The first row contains 2 columns, a left-aligned comment title and some right aligned text that can be added later.
    • The second row should span both of the above mentioned columns and contain the comment text.

    The problem occurs when the table width is resized to be very narrow. This causes the height of the row containing the comment text (i.e. the 2nd row per model item) to resize incorrectly. It seems to me that the underlying Qt code may not be accounting for the row spanning both columns. However, I am looking for a way around this so that the comment text only uses the minimum amount of space required to display the text fully.

    I appreciate any an all help! Below is a minimal example and some screen shots. I am using qt version 5.12.8.

    Code:

    main.cpp

    #include "MainWindow.h"
    #include "ui_MainWindow.h"
    
    #include <QWidget>
    #include <QDockWidget>
    #include <QTableView>
    #include <QHeaderView>
    
    #include <vector>
    #include <string>
    
    struct Comment
    {
        Comment(const std::string& title_, const std::string& comment_) :
            title(title_), comment(comment_)
        {
        }
        std::string title;
        std::string comment;
    };
    
    class CommentModel : public QAbstractTableModel
    {
    public:
        CommentModel(QTableView* parent = nullptr) :
            QAbstractTableModel(parent),
            _view(parent)
    
        {
        }
    
        int columnCount(const QModelIndex&) const override { return 2; }
    
        int rowCount(const QModelIndex&) const override { return static_cast<int>( _text.size() * 2); }
    
        QVariant data(const QModelIndex& idx, int role = Qt::DisplayRole) const override
        {
            if(role == Qt::DisplayRole) {
                const auto& comment = _text[idx.row() / 2];
                if(idx.row() % 2 == 0) {
                    if(idx.column() == 0)
                        return QString::fromStdString(comment.title);
                    else if(idx.column() == 1) {
                        return QString::fromStdString("Placeholder");
                    }
                } else {
                    if(idx.column() == 0)
                        return QString::fromStdString(comment.comment);
                }
            } else if(role == Qt::TextAlignmentRole) {
                if(idx.column() == 1)
                    return static_cast<int>(Qt::AlignRight | Qt::AlignVCenter);
                return static_cast<int>(Qt::AlignLeft | Qt::AlignVCenter);
            }
            return QVariant();
        }
    
        QVariant headerData(int, Qt::Orientation, int = Qt::DisplayRole) const override
        {
            return QVariant();
        }
    
        void addText(const Comment& comment)
        {
            beginResetModel();
            _text.push_back(comment);
            for(size_t i = 0; i < _text.size(); ++i)
                _view->setSpan(i*2+1, 0, 1, 2);
            endResetModel();
        }
    
    private:
        std::vector<Comment> _text;
        QTableView* _view{ nullptr };
    };
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        setWindowTitle(tr("Table Test"));
    
        QDockWidget *dock = new QDockWidget(tr("Comment Table"), this);
        auto table = new QTableView(dock);
        auto model = new CommentModel(table);
        table->setModel(model);
        table->horizontalHeader()->hide();
        table->verticalHeader()->hide();
        table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
        table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
        table->horizontalHeader()->resizeSection(1, 130);
        table->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
        table->setFixedHeight(600);
    
        model->addText(Comment("comment 1", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."));
        model->addText(Comment("comment 2", "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."));
        model->addText(Comment("comment 3", "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat "
                        "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."));
        model->addText(Comment("comment 4", "Platea dictumst quisque sagittis purus sit amet volutpat. Libero id faucibus nisl tincidunt eget nullam."));
        model->addText(Comment("comment 5", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
                               "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."));
    
        dock->setWidget(table);
        addDockWidget(Qt::TopDockWidgetArea, dock);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
    
    
        w.show();
        return a.exec();
    }
    

    Example of correct spacing:

    Good.png

    Example of undesired spacing:

    Undesired.png


  • Lifetime Qt Champion

    Please try with 5.15 - there were some changes wrt this.



  • @Christian-Ehrlicher thank you for the input! I tested with 5.15.2 and the problem is still present.


  • Lifetime Qt Champion

    Then please provide a minimal compilable example of your issue so we can take a look on it.



  • @Christian-Ehrlicher Sorry about that, this is my first time using the forum. I created the previous file using the generic Qt Creator project setup. However, I stripped down the code to one file main.cpp. Please let me know if this is still not what you are looking for.

    #include <QTableView>
    #include <QLayout>
    #include <QApplication>
    #include <QHeaderView>
    
    struct Comment
    {
        Comment(const std::string& title_, const std::string& comment_) :
            title(title_), comment(comment_)
        {
        }
        std::string title;
        std::string comment;
    };
    
    class CommentModel : public QAbstractTableModel
    {
    public:
        CommentModel(QTableView* parent = nullptr) :
            QAbstractTableModel(parent),
            _view(parent)
    
        {
        }
    
        int columnCount(const QModelIndex&) const override { return 2; }
    
        int rowCount(const QModelIndex&) const override { return static_cast<int>( _text.size() * 2); }
    
        QVariant data(const QModelIndex& idx, int role = Qt::DisplayRole) const override
        {
            if(role == Qt::DisplayRole) {
                const auto& comment = _text[idx.row() / 2];
                if(idx.row() % 2 == 0) {
                    if(idx.column() == 0)
                        return QString::fromStdString(comment.title);
                    else if(idx.column() == 1) {
                        return QString::fromStdString("Placeholder");
                    }
                } else {
                    if(idx.column() == 0)
                        return QString::fromStdString(comment.comment);
                }
            }
            return QVariant();
        }
    
        QVariant headerData(int, Qt::Orientation, int = Qt::DisplayRole) const override
        {
            return QVariant();
        }
    
        void addText(const Comment& comment)
        {
            beginResetModel();
            _text.push_back(comment);
            for(size_t i = 0; i < _text.size(); ++i)
                _view->setSpan(i*2+1, 0, 1, 2);
            endResetModel();
        }
    
    private:
        std::vector<Comment> _text;
        QTableView* _view{ nullptr };
    };
    
    class TableWidget : public QWidget
    {
    public:
        TableWidget(QWidget *parent = nullptr)
            : QWidget(parent)
        {
            setWindowTitle(tr("Table Test"));
    
            auto table = new QTableView(this);
            auto model = new CommentModel(table);
            table->setModel(model);
            table->horizontalHeader()->hide();
            table->verticalHeader()->hide();
            table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
            table->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
            table->horizontalHeader()->resizeSection(1, 130);
            table->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
            table->setFixedHeight(600);
    
            model->addText(Comment("comment 1", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."));
            model->addText(Comment("comment 2", "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."));
            model->addText(Comment("comment 3", "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat "
                            "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."));
            model->addText(Comment("comment 4", "Platea dictumst quisque sagittis purus sit amet volutpat. Libero id faucibus nisl tincidunt eget nullam."));
            model->addText(Comment("comment 5", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
                                   "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."));
    
            this->setLayout(new QVBoxLayout);
            this->layout()->addWidget(table);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        TableWidget wid;
        wid.show();
        return a.exec();
    }
    
    

  • Lifetime Qt Champion

    Thx for the reproducer and it's clear what happens - QCommonStylePrivate::viewItemSize() does (and currently can) not honor the fact that there is a span. I'll create a bug report for it later on.


  • Lifetime Qt Champion

    See https://bugreports.qt.io/browse/QTBUG-89116 . I've also already an idea how to fix it. But don't think it will go into 5.15 though (but I try)



  • Thank you @Christian-Ehrlicher, I appreciate your help!


Log in to reply