1

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.

user2962533
  • 397
  • 1
  • 5
  • 18
  • 1
    http://doc.qt.io/qt-5/qabstractitemmodel.html#layoutChanged – Dmitry Sazonov May 12 '16 at 08:05
  • @DmitrySazonov Whew, thanks. Indeed, I forgot to include a layoutChanged signal in the resize function since I connected the sourceModel's signal to the proxy's in setSourceModel. Since you solved the problem, want to post this as an answer so I can accept it? – user2962533 May 12 '16 at 08:44

2 Answers2

2

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.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Mind telling me what's so terrible and wrong about the code? Yes, I know what 'static' does, but please tell me just in case. – user2962533 May 12 '16 at 09:22
  • 1
    this logic assumes that `on_dataChanged()` is invoked specific number of times. This is defensively invalid assumption which assumes some specific implementation in other parts of code. This can't be reliable. Small change in other parts of code and this code will produce strange and hard to detect defects. Use of static variable in this context indicates that you are a newbie, what if you use this MainWindow multiple times? Or what will happen if someone else in the project will use `on_dataChanged()` based on the name of this method? – Marek R May 12 '16 at 10:49
  • Gotcha. Much appreciated. Well, I'm a newbie who tries to educate himself by coding a small program from start to end because he knows he's not quite there yet, what of it? Your arguments against using static are invalid here but I still appreciate the guidance for the long run. This is a TINY application I'm making specifically in order to learn. I was ready to make all kinds of mistakes in this code and obviously don't plan to reuse any of it. I'm also taking many liberties like tightly-coupling everything (hence allowing the rowCount as a counter and a static variable). – user2962533 May 12 '16 at 10:57
2

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

Community
  • 1
  • 1
Dmitry Sazonov
  • 8,801
  • 1
  • 35
  • 61
  • I'm in a bind right now... :| You definitely solved my problem but now there's an answer with a claimed "official way" to achieve this. Why can there only be one accepted answer, I wonder... It's like there's only one way of doing things. – user2962533 May 12 '16 at 10:40
  • I don't care about reputation at all ;). So just accept more preferable answer. I voted up Marek's answer. – Dmitry Sazonov May 12 '16 at 13:21
  • :) I did not say that because I feel bad about promising to accept your answer. I really don't know which one I should be accepting since both answers are correct. – user2962533 May 12 '16 at 13:39
  • I'm accepting your answer after all since your answer solved my immediate problem. – user2962533 May 12 '16 at 17:42