QTreeView or QTreeWidget - qt

I want to implement in my program a tree with nested sub-levels, and I'm looking for which of those two kind(View/Widget) is best suited for my goal.
I have a list of days with task that are either done/missed/failed, each task has a count of how many times it was done/missed/failed and lastly a score for that day.
I want to display them like so:
I made this example in QtCreator using a QTreeWidget, but I'm worried that it would be hard to modify the elements since they are stored somewhere else.
Are my worries rational and should I go to the model/view structure, or can I easily get going with the QTreeWidget? The tree will be logging the task and thus will be constantly changing. Elements will only be added to it, not removed. And the days will be sorted from highest-lowest(day 2 is first, then day 1)

If your data is stored in a database model or if you want to have a single data model and show it in some views in different ways, then you are definitely better to go with QTreeView.
But QTreeWidget has it's internal model in some way along with the methods to deal with model in context of indexes. In general if you just want something that is simple to work, you can use the widget way.
But the Model/View approach is more general and flexible IMO. You can create your own subclasses of model and view which enables you to do whatever you like.

Related

What widget can be used to have a list?

I'm using Qt creator to write c++ GUI application. I want to have a list to show the some guides to user and prefer to have a list with Scroll Bar. what widget can I use to this?
For displaying lists, trees and tables, Qt has a set of Model/View classes.
In model/view, a subclass of QAbstractItemModel provides the data, which is then displayed by a QAbstractItemView. Models can be "stacked" for rather flexible filtering, sorting and mapping of data (see e.g. QSortFilterProxyModel).
There's basically now three ways to use them, of varying complexity, power and scalability:
So if you want full flexibility or have a large number of list entries (say, in the thousands), implement a QAbstractListModel with a QListView. While this is the most powerful solution, it's also the most complex one, and implementing a correct and efficient model has some pitfalls.
A simpler way would be to use QStandardItemModel (or for an even simpler list of just strings, QStringListModel) and set that as model of a QListView. That might be far less daunting for a beginner, compared with having to implement your own models. It's not the most scalable version, but if you display e.g. 50 items, that just doesn't matter.
You can still combine it with sorting and filtering via proxy models.
Then, the third and most simple way is to display a list is to use QListWidget. It's a subclass of QListView that allows you to pass in the list items via QListWidgetItem, similar to QStandardItemModel. It basically "merges" the model functionality into the view class so that you don't have to touch models at all. While this is the simplest way, it's also the most inflexible one: You cannot use sort/filter proxy models when using a QListWidget.
To get started with Model/View, especially to people who are used to manage item-based lists, I recommend (2) and then move up to (1). If you just want a simple and immutable list of a couple items, (3) might as well do. If you find out later that you need sort/filter functionality, converting (3) into (2) later is usually rather easy, while converting (3) to (1) is a far more intrusive change.

Completion for a QLineEdit with multiple models/categories

I'd like to build a completion for a QLineEdit which can take several completion models and organizes them as categories.
I have a working solution based on a QSortFilterProxyModel and a tree model for the items:
The root items in the model show up as category, and the children of each root-item show up as filtered items. Then there's a customized QTreeView so this is displayed properly, tabbing ignores categories, etc.
This works fine - however it makes it very hard to write new completions (e.g. for the possible values for a setting).
Each completion needs to be a tree model with all categories in it. I'd prefer to write simple list models for each category, and then being able to combine them to a QTreeModel, i.e. something like this (pseudo-ish Python code):
commands = CommandListModel()
settings = SettingListModel()
completion.setModels([('commands', commands), ('settings', settings)])
There are some different solutions I had in mind, but I'm not sure what route to go, as all of them feel non-trivial to implement:
Write a QAbstractProxyModel-like class (or a custom model) which combines several list models to one tree model, and leave the view part as-is.
Writing custom tree models in Python is hard however (and typically segfaults if you do anything wrong), and I've had performance issues with it in the past (compared to a QStandardItemModel, as there are some thousand items in the underlying models).
Write functions for each model which fill a tree model (given a category and a list of items).
This makes it harder to write dynamic models rather than just having a list of static items.
Use several list models, and adjust the view to be a QVBoxLayout of QListViews.
This sounds the most promising to me so far. However, implementing tabbing through the completion and filtering so it works right might be troublesome as well, and resizing the sub-views appropriately too.
Is there some easier way to do this I haven't considered? Which approach is likely to be the least painful down the road?

QQmlListProperty vs QAbstractListModel

I am trying to understand how one would choose whether to use a QAbstractListModel or a QObject with a QQmlListProperty.
Given that the QQmlListProperty handles the "roles" functionality that would have to be written using the QAbstractListModel, it seems like the less tedious route.
I can't tell if most people suggest using QAbstractListModel simply because it has been around longer or if it is the better choice for some reason.
Nor have I been able to find any discussion of the trade-offs between the two options. This question was brought up during a Qt Developer Days talk discussing QAbstractListModel, but the answer was along the lines of "that would also work".
A model implementation will generally be more efficient to work with a view. When you expose a "dumb list" to use a model, every time the model changes the whole view is reconstructed, whereas with a model only the changes are updated. If you have a lot of items there will be tangible performance overhead.
You could use a list for a model, and you could use a model for a list, but when you want optimal performance, you should use a list for a list, and a model for a model.

What is the right way to keep a QtTableWidget and a list in sync, in PySide?

I have a simple list:
mylist = ["foo", "bar", "baz"]
and a QtTableWidget with 1 column. I would like to keep the data in mylist in sync with that in the QtTableWidget, including allowing drag-and-drop reordering (i.e., the user can do that, and mylist gets updated) and programmatic changes (i.e., I update mylist and the table gets updated).
What is the right way to do this?
Note that in general there's no way in Qt/C++ proper to link a generic data structure with a view. Models are such instrumented data structures that allow trivial linking with views -- generic lists, like say QStringList can't be used like that.
In Python it should be possible to inject attributes into an existing instance of any list to turn it into a model that notifies its views of changes done to it. I don't know if any Qt-to-Python bridges do that sort of a thing, I can only give C++ perspective on this. Someone who knows PyQt or PySide is welcome to chime in and edit as appropriate.
Use a QStringListModel for the model. Enable drag-drop reordering on the view as follows:
view.setDragEnabled(true);
view.setDropIndicatorShown(true);
view.setDragDropMode(QAbstractItemView::InternalMove);
My other answer has a full example that uses the convenience widget QListWidget with its buit-in model. That may be better as a starting point, and for lists that can be reasonably manipulated with a mouse, it's a good choice. Generally if a model has 100s of items, it can't be readily manipulated with just a mouse without a way of doing real-time finds or pruning of some sort -- scrolling so many items is a usability nightmare. So don't do it.
Qt's documentation would be a good plate to start learning. Read about the model/view framework. Then look at QStringListModel and your chosen view, say QTableView or QListView.

QAbstractItemModel.parent(), why?

I'm a (Py)Qt newbie, porting C# GUI code to Qt for a couple of days now. One question that I keep asking myself is why are QAbstractItemModel subclasses required to supply a parent() method, and why are they required to supply, in the resulting QModelIndex, the row of a child in the parent?
This requirement forces me to add another layer over my tree data (because I don't want to call indexOf(item) in parent(), it wouldn't be very efficient) that remembers row indexes.
I ask this because it's the first time I see a model based view require this. For example, NSOutlineViewDataSource in Cocoa doesn't require this.
Trolltech devs are smart people, so I'm sure there's a good reason for this, I just want to know what reason.
The quick answer is, "they thought it best at the time." The Qt developers are people just like you and me -- they aren't perfect and they do make mistakes. They have learned from that experience and the result is in the works in the form of Itemviews-NG.
In their own words from the link above:
Let’s just say that there is room for improvement, lots of room!
By providing a parent that contains a row and column index, they provide one possible way to implement trees and support navigation. They could just as easily have used a more obvious graph implementation.
The requirement is primarily to support trees. I couldn't tell you the reason, since I'm not a Qt dev... I only use the stuff. However, if you aren't doing trees, you could probably use one of the more-tuned model classes and not have to deal with the overhead of supplying a parent. I believe that both QAbstractListModel and QAbstractTableModel handle the parent portion themselves, leaving you free to just worry about the data you want.
For trees, I suspect that one of the reasons they need the parent is that they try to keep to only asking for the information they need to draw. Without knowing all of the items in a tree (if it wasn't expanded, for example), it becomes much harder to provide an absolute position of a given item in a tree.
As for the quandry of using indexOf(item) in the parent function, have you considered using QModelIndex's internalId or internalPointer? I'm assuming they are available in PyQt... they can be used by your model to track things about the index. You might be able to use that to shortcut the effort of finding the parent's index.

Resources