user2962533
user2962533

Reputation: 396

QTableView not updating properly

I am creating a small program that takes user input into a model and then shows that input in several views that take it through filters.

When the user clicks the button that accepts the input, the program updates the amount of cells in the views and then resizes those cells as necessary so that they fit neatly in their area.

My problem is that the cell resizing doesn't seem to work for one of the views for some reason (I tried looking for differences but couldn't find a reason for what I'm experiencing).

I'm calling the cell resizing function in two places:

  1. dataChanged slot.
  2. resizeEvent slot.

If the cell resize function gets called twice inside dataChanged, then the view does update, however this involves some calculations and ui access and obviously not supposed to happen.

If I resize my window then the cells are resized properly.

I suspect that I'm always one update behind - that the view doesn't paint until the new update starts getting calculated and then that new update is on hold until the next calculation (since resize happens a lot of times in succession it might just act the same as the button but is harder/impossible to notice).

I have some dirty workarounds:

  1. As I mentioned, if I call my cell resize function again, the view updates properly.
  2. If I remove the second "if" in this next piece of code then everything works.

I thought I'd save my computer some work by only processing when the entire input had been received. My thinking was that, although dataChanged is emitted for every single item I'm inserting, I only really need to update once it is all in:

void MainWindow::on_dataChanged()
{
    static int left_to_insert = -1;

    if ( 0 > left_to_insert )
    {
        left_to_insert = m_model.rowCount() - 1;
    }

    if ( 0 == left_to_insert )
    {
        ...
            m_matrix_proxy.resize_to_fit();
            adjust_matrix_cells_sizes();
    }
    --left_to_insert
}

Is it bad to only process the last signal? Why?

I tried calling update() and/or repaint() on both the matrix and the main window.

I tried calling both of these on the viewport of the QTableView and tried calling them in succession from the matrix itself to the highest parent that didn't make my program crash. (ui->matrix->parentWidget()->parentWidget()...)

I tried qApp->processEvents().

I even resorted to emitting a resizeEvent, but this is overkill IMO as it makes some calculations be performed again.

Just in case it is somehow relevant: The data appears correctly. The only thing that's wrong is that the cells don't resize.

Upvotes: 1

Views: 2666

Answers (2)

Marek R
Marek R

Reputation: 37597

This logic in only code sample you have given is wrong. And this static keyword makes it even worse.

Actual answer:

There is ready solution delivered by Qt! See documentation of QHeaderView::ResizeMode and QHeaderView::setSectionResizeMode


Old answer:

IMO this should look like this:

void MainWindow::MainWindow()
…
{
     …
     mNeetToResizeCells = false;
     connect(this, &MainWindow::NeedUpdateCellsSizes,
             this, &MainWindow::ResizeTableCells,
             Qt::QueuedConnection); // this is imporatant
}

void MainWindow::on_dataChanged()
{
    if (!mNeetToResizeCells) {
        mNeetToResizeCells = true;
        emit NeedUpdateCellsSizes();
    }
}


void MainWindow::ResizeTableCells()
{
     mNeetToResizeCells = false;
     // update cells sizes here
     ui->tableView->resizeColumnsToContents();
     ui->tableView->resizeRowsToContents();
}

This way all data updates performed in one iteration of event loop will cause only one invocation of MainWindow::ResizeTableCells in some future iteration of event loop.

Upvotes: 2

Dmitry Sazonov
Dmitry Sazonov

Reputation: 8994

You need to emit layoutChanged signal from your model. But be care with large amounts of items, because handling of this signal may take a lot of time.

Similar questions: one, two

Upvotes: 3

Related Questions