need ideas for list/table implementation
-
I need to add a list or table (I'm not sure which) to the UI of a program I'm developing. This is to display a (fairly short) list of connected devices. The information on each entry would be a few columns, such as name, type, most recent activity. The table would be updated a few times per second. Some color coding (based on most recent activity) and sorting would be nice additions.
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. Before I jump in, I'd be interested in hearing any other ideas on how best to implement this.
Thanks...
-
@mzimmers
So http://doc.qt.io/qt-5/qtablewidget.html#details or a http://doc.qt.io/qt-5/qtableview.html would indeed be my first suggestion. -
@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.