Fixing QTableView's horizontal header size does not work

32 views Asked by At

I am having trouble initializing a QTableView with fixed column header column widths.

When I display the table for the first time, the columns seem to use the default horizontalHeaderDefaultSectionSize property from the Qt Designer's property editor.

I also have the horizontalHeaderStretchLastSection property set to true.

If I double-click on each of the columns, the layout snaps to the correct width, however I have to do this for each of the columns (except the last which is set to stretch as I just described). I am not sure why the initial layout does not respect the widths in my code.

Has this something to do with sizeHints in a model for a horizontalHeader? I do not want to automatically size to the contents of the table (as the table can grow to a very large size, I just want the initial sizes to be correct).

I set up my views using a table driven approach. The table contains a sample fixed size string or a length that I use to size the header (using font metrics):

using TableSpec = std::vector<
    std::tuple<
        QTableView*,
        QStandardItemModel*,
        std::vector<TableColumnSpec>
    >
>;

Define the layout for tables in the main window.
// Views with proxy sort filters need special handling
// as the view does not directly have access to the model.
const TableSpec gTableSpecs = { {
    // Thread colored logger.
    {
        ui->logView,
        mpLogViewModel.get(),
        {
            TableColumnSpec("Time", "Timestamp", "06-09-2023 20:01:33.334"),
            TableColumnSpec("Thread", "Thread ID", "0x00000000"),
            TableColumnSpec("Level", "Severity level", "critical"),
            TableColumnSpec("Description", "Description", "description")
        }
    },
} };

The above code shows just one of my tables (the one that shows a log table). This table uses a custom delegate that is assigned as follows (I don't think the delegate is involved with laying out the initial view of the horizontal header though), I also assign the mpLogViewModel (std::unique_ptr<QStandardItemModel>) to the view from here:

// Assign item delegate to color the rows using the threadID (column1).
ui->logView->setItemDelegate(mpLogItemDelegate.get());
// Associate each model with its respective view.
ui->logView->setModel(mpLogViewModel.get());

Now that the item delegate and model have been associated with the ui->logView (QTableView), I initialize the table(s) as follows:

// Layout the main application tables & headers.
initTableHeaders(gTableSpecs);

void
initTableHeaders(const TableSpec& rTableSpec)
{
    for (const auto& [pView, pModel, colSpecs] : rTableSpec) {
        const auto fm = pView->fontMetrics();
        const auto rowHeight = fm.lineSpacing();
        pView->verticalHeader()->setDefaultSectionSize(rowHeight);
        pView->verticalHeader()->setMaximumSectionSize(rowHeight);
        pView->verticalHeader()->setMinimumSectionSize(rowHeight);
        pView->verticalHeader()->setVisible(false);
        pView->horizontalHeader()->setMinimumSectionSize(25);
        pView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
        pView->horizontalHeader()->setStretchLastSection(true);
        pView->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder);
        pView->horizontalHeader()->setSortIndicatorShown(true);
        pView->setSelectionBehavior(QAbstractItemView::SelectRows);
        for (auto col = 0; col < static_cast<int>(colSpecs.size()); ++col) {
            const auto headerLabel = new QStandardItem(colSpecs[col].mColumnTitle);
            headerLabel->setTextAlignment(colSpecs[col].mAlignment);
            pModel->setHorizontalHeaderItem(col, headerLabel);
            const auto columnWidth = std::visit(Overload{
                [&](const QString& rSampleStr)->int {
                    if (!rSampleStr.isEmpty()) {
                        return fm.horizontalAdvance(rSampleStr);
                    }
                    return fm.horizontalAdvance(colSpecs[col].mColumnTitle);
                },
                [&](const auto stringLength)->int {
                    if (stringLength > 0) {
                        return stringLength * fm.averageCharWidth();
                    }
                    return fm.horizontalAdvance(colSpecs[col].mColumnTitle);
                },
            }, colSpecs[col].mSizeInfo);
            // Add 20 to make room for the sort arrow.
            pView->setColumnWidth(col, columnWidth + 20);
        }
    }
}

The problem is that when the log is displayed, it looks like this:

enter image description here

0

There are 0 answers