Is QAbstractItemModel re-entrant
-
I am implementing a QAbstractItemModel descendant that interacts with a potentially slow DB. My plan for methods like 'rowCount' is to signal the DB thread to get the info, and signal back the response. While waiting for the response, the rowCount methods starts a new eventloop until the answer arrives. This keeps the thread available to do other work.
While this generally works, I'm encountering some strange behavior. (The first signal emitted does not reach the slot for 10 seconds, but other slots get their signals normally). I'm starting to wonder if the overlapping method calls in QAbstractItemModel are causing the problem? (While my eventloop waits, other QAIM methods are being called)
If these overlapping function calls are in fact the problem, is there a better/right way to fetch data from another thread? I don't see any asynchronous methods in QAIM.
-
@ocgltd Sorry but I don't understand your problem. If there are no rows yet, return 0. If you received some rows from the database, return this number. What's so complicated about this?
@Christian-Ehrlicher The MVC is very straight forward with blocking code for data retrieval, but making it non blocking (asynchronous) is more challenging. QAbstractItemModel is not easily compatible with asynchronous use.
I have it working now, but the view shows blank rows until the data arrives. If I hide rows without data then the view keeps asking for more rows until it has enough to fill the screen. So I have settled with showing blank rows. (Dummy data is essential blank column content).
-
No, QAbstractItemModel can not be used from different threads. It must be used in the main thread.
Featch your data in a separate thread, emit a signal to transfer the data from this thread to the gui/main thread. -
No, QAbstractItemModel can not be used from different threads. It must be used in the main thread.
Featch your data in a separate thread, emit a signal to transfer the data from this thread to the gui/main thread.@Christian-Ehrlicher That's actually what I'm doing. I have a DB thread which gets requests via signal, and sends responses via signal. However, the QAbstractItemModel must wait for the response - and the only way to do this is with an event loop (to allow handling of incoming signals).
However, when I do this my QAbstractItemModel allows another method (eg: rowCount) to run since these seem to be triggered by signals, so now I have 2 or more rowCounts in the same thread all waiting for answers via eventloops. A bit of a mess.
Since QAbstractItemModel is not re-entrant, is there an asynchronous version of this class available? (Or some other way to implement this)
(this is overlapping another post a bit - but still a bit different spin)
-
@Christian-Ehrlicher That's actually what I'm doing. I have a DB thread which gets requests via signal, and sends responses via signal. However, the QAbstractItemModel must wait for the response - and the only way to do this is with an event loop (to allow handling of incoming signals).
However, when I do this my QAbstractItemModel allows another method (eg: rowCount) to run since these seem to be triggered by signals, so now I have 2 or more rowCounts in the same thread all waiting for answers via eventloops. A bit of a mess.
Since QAbstractItemModel is not re-entrant, is there an asynchronous version of this class available? (Or some other way to implement this)
(this is overlapping another post a bit - but still a bit different spin)
@ocgltd said in Is QAbstractItemModel re-entrant:
However, the QAbstractItemModel must wait for the response - and the only way to do this is with an event loop (to allow handling of incoming signals).
No, it must not. You return the row count which you've actually have. Once the db thread sends new data you add this to your model and properly call begin/endInsertRows().
-
@ocgltd said in Is QAbstractItemModel re-entrant:
However, the QAbstractItemModel must wait for the response - and the only way to do this is with an event loop (to allow handling of incoming signals).
No, it must not. You return the row count which you've actually have. Once the db thread sends new data you add this to your model and properly call begin/endInsertRows().
@Christian-Ehrlicher But as soon as rowCount returns a value > 0, the tableView starts calling the 'data' function for each row&col. So I have to return something in the subclassed 'data' method. I thought I would return fake data, and once the real data arrives from the DB I will issue a dataChanged signal for that row.
Is there something I can return (not fake data) that tells the view that data is not available for this row/col? If I return an invalid QVariant for ALL columns, will the view hide the row? Because that's really what I want.
As for your suggestion to begin/endInsertRows(), I understand how that would work the first time the view is populated, but when a row goes out of view and back in again, won't that cause the rowcount to keep increasing? (per this doc )
-
@Christian-Ehrlicher But as soon as rowCount returns a value > 0, the tableView starts calling the 'data' function for each row&col. So I have to return something in the subclassed 'data' method. I thought I would return fake data, and once the real data arrives from the DB I will issue a dataChanged signal for that row.
Is there something I can return (not fake data) that tells the view that data is not available for this row/col? If I return an invalid QVariant for ALL columns, will the view hide the row? Because that's really what I want.
As for your suggestion to begin/endInsertRows(), I understand how that would work the first time the view is populated, but when a row goes out of view and back in again, won't that cause the rowcount to keep increasing? (per this doc )
@ocgltd said in Is QAbstractItemModel re-entrant:
rowCount
Why would it be bigger than the number of rows you actually have?
-
@Christian-Ehrlicher But as soon as rowCount returns a value > 0, the tableView starts calling the 'data' function for each row&col. So I have to return something in the subclassed 'data' method. I thought I would return fake data, and once the real data arrives from the DB I will issue a dataChanged signal for that row.
Is there something I can return (not fake data) that tells the view that data is not available for this row/col? If I return an invalid QVariant for ALL columns, will the view hide the row? Because that's really what I want.
As for your suggestion to begin/endInsertRows(), I understand how that would work the first time the view is populated, but when a row goes out of view and back in again, won't that cause the rowcount to keep increasing? (per this doc )
@ocgltd Sorry but I don't understand your problem. If there are no rows yet, return 0. If you received some rows from the database, return this number. What's so complicated about this?
-
@ocgltd Sorry but I don't understand your problem. If there are no rows yet, return 0. If you received some rows from the database, return this number. What's so complicated about this?
@Christian-Ehrlicher The MVC is very straight forward with blocking code for data retrieval, but making it non blocking (asynchronous) is more challenging. QAbstractItemModel is not easily compatible with asynchronous use.
I have it working now, but the view shows blank rows until the data arrives. If I hide rows without data then the view keeps asking for more rows until it has enough to fill the screen. So I have settled with showing blank rows. (Dummy data is essential blank column content).
-
@Christian-Ehrlicher The MVC is very straight forward with blocking code for data retrieval, but making it non blocking (asynchronous) is more challenging. QAbstractItemModel is not easily compatible with asynchronous use.
I have it working now, but the view shows blank rows until the data arrives. If I hide rows without data then the view keeps asking for more rows until it has enough to fill the screen. So I have settled with showing blank rows. (Dummy data is essential blank column content).
@ocgltd said in Is QAbstractItemModel re-entrant:
I have it working now, but the view shows blank rows until the data arrives.
Then you're doing something wrong. When no data is available, you should return '0' as row count... (already said at least three times).