need ideas for list/table implementation
-
@mzimmers said in need ideas for list/table implementation:
I did a little reading on Qt's model/view programming, and it seems rather elaborate for my needs, though maybe I have to go that route.
That would be my go-to solution. You would need to implement only a couple of methods from
QAbstractTableModel
and use the standard view that goes with it. -
@mzimmers said in need ideas for list/table implementation:
OK, if I'm going to attempt this, I'll need a good example to follow. Is the frozencolumn example (found in Creator->Welcome->Examples) a good one to use as a model (so to speak)?
Yes it should do, although it seems a bit elaborate for what you describe. If you need to have simply a list also consider
QAbstractListModel
(e.g. puzzle example) which provides even more methods already overriden, so there's less to write. The model subclassing page should also be of use to check. -
I'll need a table (2 dimensions of data). I'm working through an example I found in an old 4.8 tutorial...it's starting to make sense. I'm curious, though, about how this works with the traditional Qt worker/widget paradigm. Currently, my worker sends table data to the widget (via the signal mechanism). Obviously, my widget needs to update the table, but it can't do this directly because the data structure is contained in my table class. Do I manually create methods for the widget object to call, or is there something automatic that does this for me?
-
@mzimmers said in need ideas for list/table implementation:
I'm curious, though, about how this works with the traditional Qt worker/widget paradigm.
You lost me here. Could you rephrase? I don't get what you're asking.
-
So, an application might typically have a worker object and a widget object. Now, we're introducing the table object (based on QAbstractTableModel). I'm accustomed to the worker receiving data from a remote device, and passing that along to the widget. Now, however, the widget doesn't directly process that data, but somehow needs to get it into the table. How is this best accomplished?
-
Hi,
In this case, your worker should work with your table model. When implemented properly, the model signals that it has new/modified data through
begin/endInsertRows
,dataChanged
and their signal friends. All views that you set this model on will then update themselves. -
The fact that it's read-only is a detail. You can disable all edit triggers and even make the setData method of your model a "no-op" method.
So, yes, your worker can still work with your model directly.
-
So, the examples I'm looking at are somewhat lightweight on the data. It isn't clear to me if/how the worker is supposed to store a copy of this data. I don't see where the call to insertRows() provides any actual data.
Each row in my table will consist of 3 columns, all strings. When I want to update a row, what do I call to do this? The first column will be like my primary key.
-
Are you using your model as wrapper on top of a custom data structure or as holder of said data ?
Your worker can feed the model, it doesn't need to store anything.
-
I don't know how to answer that; I'm new to this model/view stuff. But the intention is simply to pass information along from the worker to the UI. If i can bypass the need to store the information locally, so much the better. But I don't see how to do that.
I gather that I'm supposed to re-implement the insert rows function, but I don't see how to use that to actually inject data into the model.
Also, now that I've bypassed the widget, my table is showing up in a separate window. Do I correct this by passing a different parent object (like the Ui) to its constructor?
EDIT:
Oh, I think I get it a little better now. So, the class derived from the table model holds the data. The table object receives the data updates from the worker and stores them, then emits the dataChanged() signal. And the data() function then conveys the current data to the UI. That about right?
So, am I responsible for maintaining a row index for my records? (Since data uses an int to identify a row.) I could store my table data in a hash, with an int as the key, and a structure containing the strings as the value.
-
@mzimmers said in need ideas for list/table implementation:
Oh, I think I get it a little better now. So, the class derived from the table model holds the data. The table object receives the data updates from the worker and stores them, then emits the dataChanged() signal. And the data() function then conveys the current data to the UI. That about right?
Yep, quite correct.
So, am I responsible for maintaining a row index for my records? (Since data uses an int to identify a row.)
Yep.
I could store my table data in a hash, with an int as the key, and a structure containing the strings as the value.
You could, but if your keys are sequential and uninterrupted a hash isn't exactly efficient, maybe a vector.
-
@mzimmers said in need ideas for list/table implementation:
Now..what do I have to do to get my table to not appear as a separate window?
Give it a parent widget and/or add it to an active layout (which will give it a parent widget).
-
My program isn't working quite correctly, and I'm wondering if it has to do with my non-use of insertRows().
Do I correctly understand that in order to insert a new row into my table, I need to do something like this:
// part of the subclass update function devices.insert({row, device}); // my local copy of the data beginInsertRow(parent, rowCount(), rowCount()); insertRow(rowCount(), 1, parent); endInsertRow();
-
@mzimmers said in need ideas for list/table implementation:
The table belongs to the worker class
If you mean the table view belongs the the worker object (which is presumably living in another thread), then this is wrong. You must keep the GUI classes in the GUI thread. If you mean the table model is in the worker thread then I think it is okay. What I meant is that you should parent the table view to a widget (and add it to a layout), so it's not a native widget and doesn't get its own window.
My program isn't working quite correctly, and I'm wondering if it has to do with my non-use of insertRows().
Perhaps, can you share the actual code?
Do I correctly understand that in order to insert a new row into my table, I need to do something like this:
insertRow
calls the virtualinsertRows
, so it's a convenience method. You should implementinsertRows
for your model in which you'd callbeginInsertRows
before saving the data, andendInsertRows
after that. -
OK, I'm doing it wrong.
My table view is in my worker. If I move it to my widget, how do I give it the model information in the setModel() call -- do I do something like pass the model as an argument to the widget constructor?
I'll post some code in a bit, when it's more "post-worthy." In the meantime, I'm still a little unclear on the insertRows() function I need to write. Does this operate on my local copy of the data? So, the pseudocode would be something like:
void Devices::MyInsertRow() { devices.insert(etc) } ... beginInsertRow(parent, rowCount(), rowCount()); myInsertRow(); endInsertRow();
-
@kshegunov said in need ideas for list/table implementation:
If you mean the table model is in the worker thread then I think it is okay.
It's not. The view calls methods of the model (
data()
being the most obvious one) directly and that's a race condition (and no, you can't just serialise access to your internal data asQPersistentModelIndex
still causes a race condition as soon as you try to sort)@mzimmers I think a lot of our confusion comes from you using the ambiguous term "table object" that doesn't tell us if you are talking about a model or a view