PDA

View Full Version : Switching tabs with table views , the grid does not disappear.



Dax
29th April 2019, 12:46
Hi,

I hope someone has an idea where I can look to solve the following problem.

I use a QTabWidget with 2 tabs. Each tab contains a QTableView. Each QTableView has there own custom model object assign.

When I start adding items to the model of the first table view there show up as intended. Switching to the 2nd, empty table view, no items are shown but the grid. The size of the grid is the same as in the first table view.
Setting the grid line style to different values for each table view shows that the grid will actually be redrawn. I thought maybe that is a graphic artifact. (sometimes QtCreator has some artifacts).
No matter which of the two models I add items to there show up in there table view and the other table view gets additional grid lines with no content.
The grid corrects itself when I reload the qss file with setStyleSheet on the QApplication object.

Using: Qt5.9 build from the official Qt website, Linux Mint with kernel 5.0.9 with intel graphics.

Thanks.

PS.
I can provide some screen shots if that helps. The source code is to big to post it here but if someone needs a specific snipe it should be possible to post.

d_stranz
29th April 2019, 18:49
If your custom models are returning non-zero row and column counts even if there is no data, QTableView will show empty rows and columns. If you have added the table views using Qt Designer and have set (or not changed) the default row / column counts there, then that could be the problem. You should implement the rowCount(), columnCount(), headerData(), and data() methods of your custom models to reflect the actual conditions of your model.

Dax
30th April 2019, 07:57
Thanks for the answer.

I checked the result value of rowCount(). For an empty table its 0 with one entry its 1 and so on. But even with 0 the grid is shown. The columnCount returns always 7. But maybe there is still something wrong here:



int ExtendedSignalModel::rowCount(const QModelIndex& parent) const
{
if(parent.isValid() || (m_Node == nullptr))
{
return 0;
}
int result = static_cast<int>(m_Node->ChildCount(m_SignalNodeRole));
std::cout << "rowCount: " << result << "\n";
return result;
}

int ExtendedSignalModel::columnCount(const QModelIndex& parent) const
{
if(parent.isValid())
{
return 0;
}
return 7;
}


The m_Node is a raw pointer (yes I know there should not be used anymore:confused:) which points into a tree like structure. The m_SignalNodeRole belongs to the Nodes and has nothing to do with Qt roles.

What I just realized, the grid is not shown after the application starts, but only after I added at least one line into the model.

Looking through the properties from the QTableView in the QtCreator, I could not find an entry which looks like number of rows.

Next thing I tried was removing the custom delegate objects from the QTableView objects. Nothing changed.
Btw, my custom delegate is derived from QStyledItemDelegate, the custom model from QAbstractTableModel.

Made an other test by activating the alternatingRowColors of the QTreeView. The colors are only alternating when there is actual data in a row. The "ghost" grid is not effected by this.

The only idea I have at the moment is to disable the grid. But there is the possibility that the "ghost" grid is only a symptom of an underlying bug somewhere.

d_stranz
30th April 2019, 18:14
For a problem such as this, I usually create a "sandbox" project and attempt to duplicate the issue with as little code as possible. If the toy project performs as expected, then I start looking for difference from the real project that could account for the change in behavior. Other than that, I can't offer any advice on where else to look for the source of the problem.


What I just realized, the grid is not shown after the application starts, but only after I added at least one line into the model.

Maybe some before and after screen shots would help illustrate the problem. Admittedly it is on Windows and not linux, but when I create empty table views as I am building a GUI and implement only the 4 required methods, the only thing shown is are the column headers if rowCount() returns 0 and data() returns an empty QVariant for everything. If I return 1 for rowCount(), I see an empty, one line grid of cells.

So in your case, I would confirm that rowCount() is actually returning what you think it should be. (And maybe examine the result of your call into the m_Node method before casting to int.)

Dax
2nd May 2019, 08:13
Thanks for the answer,

I checked the rowCount(). It looks ok to me. (Thats what the std::cout < .. is for.)

To making a minimal example it will take some time to do it but its a good idea.

Here are some screen shots:

This one shows the Input tab with no row added into the model:
13109

This one shows the Output tab after adding a output row into the model:
13110

This one shows the Input tab again after adding the output row.
13111

If you take a close look you can see that the grid lines are different in both tabs.

PS.
If someone is wondering, this application is a tool to do HW configuration for our own HW. Its usually not shipped to customers.

d_stranz
2nd May 2019, 17:14
If you take a close look you can see that the grid lines are different in both tabs.
Yep. Are you sure you aren't mixing up the access to the underlying data structures somehow? If you add two rows to the Output table, do you see two ghost rows in the Input table? What happens if you remove an Output row?

Dax
9th May 2019, 15:02
(Sorry for my late response but I had to take a couple of days off.)


Are you sure you aren't mixing up the access to the underlying data structures somehow?
I have check this a couple of times. The method rowCount() returns the correct value. And the data in the table and the node tree are correct to.
See below why you are right about this.


If you add two rows to the Output table, do you see two ghost rows in the Input table?
Yes. Looks like the grid is drawn from the sum of all data rows over both tables.


What happens if you remove an Output row?
Good question, have to check it. (Need to implement this anyway.) If I remove all rows (clear all nodes) then the ghost grid is still there.

After some impl. time...

During implementing the removeRow() method, I saw a bugs in the node insert handling.
The underling Node tree structure calls a callback to inform about changes in the data. My model gets informed before and after new Nodes are inserted. The callback method in the model looks like this:


void ExtendedSignalModel::OnNodeBeforeInsert(DataChange Info a_info)
{
if(!NodeIsHandledHere(a_info.node1))
{
return;
}
beginInsertRows(QModelIndex(), a_info.row, a_info.row);
m_CallEndInsertRows = true;
}


The problem here is that the a_info.row value is not the model-row but the row (or index) in the internal Node data list which contains both, the input and output nodes.
Looks like the TableView uses the information from beginInsertRows() to draw the grid, not the rowCount().

Fixing this is not so easy, need to do some thinking.

I will comeback to you when this is done. I'm certain that this is the problem.
Thanks for all the help so far.

d_stranz
10th May 2019, 01:06
Looks like the TableView uses the information from beginInsertRows() to draw the grid, not the rowCount().

That doesn't sound right, but maybe there is some internal optimization to avoid redrawing the entire table on an insert.

ChristianEhrlicher
10th May 2019, 18:03
That doesn't sound right
Passing a wrong value to beginInsert/RemoveRows/Columns() is wrong since this triggers a lot of stuff (e.g. adjusting the persistent indexes/editors, saving the header visibility state, mapping from visible to logical columns, ...). So rowCount() must return the correct value afterwards but can't be used internally.

d_stranz
10th May 2019, 18:33
So rowCount() must return the correct value afterwards but can't be used internally.

Granted. But when is the table itself actually redrawn? During or after all the internal reorganization has been completed? Since many implementations of data() might make use of rowCount() to check the validity of the QModelIndex passed as argument and since data() is almost certainly called during the repainting, rowCount() would have to be valid at that point.

My hunch is that because the OP is using a single tree-shaped model to supply different information to different views, both views are reacting to the same begin/end signals. And as you mentioned, the row indices are probably correct only for one of the two views.

ChristianEhrlicher
10th May 2019, 18:43
The redraw happens after endInsert/RemoveRows/Columns() and then the internal data structure is used to draw the cells, rowCount() must then match the internal rowCount().

Dax
7th June 2019, 13:52
Hi everyone,

finally I found some time to work on the Qt application again.
(When customers needs new functionality then every thing else has to be put on hold.)

I fixed the bad behavior of my model implementation and now it works as intended.
This strange looking error, the grid I mean, and the real problem behind it gave me a lot
of headache (figurative).
Thanks to all of you, the problem could be solved.

Maybe some else can benefit from this thread.

Many thanks
Dax