AbstactTableModels that work on the same data source - qt

Let's say i want to implement a library tool to manage different types of media. Therefore i have a base class Medium and derived classes e.g. Book and DVD which have additional properties.
My Problem is i can't figure out how to design the models correctly. I want to be able to show the media in one TableView with the basic properties from the Medium class as well as only the DVD's in another TableView with it's special properties from the derived class. And if i delete a DVD, i want it to be deleted in the Media table as well. Therefore i thought that they need to have the same data source.
What is the best way to achive this? Haven't found any example that illustrates that problem.

It can be simple one model which includes all columns from all three sources - medium, dvd, book.
In one view you make only columns of "medium" to be shown, other hidden, in another view you allows to show only "dvd" columns. But model object is just one applied as source to all views.
If one row is removed from the model, all views will be updated appropriate. Same about "add".

implement own Tree Item (take a look, for example: http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html#treeitem-class-definition)
add something like enum with types, add methods for your TreeItem to manipulate with types, then use proxy model(detailed example: http://doc.qt.io/qt-5/qsortfilterproxymodel.html#details) to sort data.
like:
enum Property {Book, DVD, Other };
class TreeItem
{
...
public:
Property GetProperty() const;
void setProperty(Property iProp);
...
};

Related

Get item of the source model from the index of a QSortFilterProxyModel

I have an application that contains a QTreeView whose underlying model, say MyModel is derived from a QStandardItemModel. In order to filter out from the view some of the items of MyModel, I plug it into a QSortFilterProxyModel which is in turn plugged into the QTreeView. When I need to get one item of my source model from a given index of my proxy model I always have to code this:
auto my_model = dynamic_cast<MyModel*>(proxy_model->sourceModel());
auto source_index = proxy_model->mapToSource(proxy_index);
auto item = my_model->itemFromIndex(source_index);
I did not find any direct method to do this. Would you be aware of more direct way to do this or is that the sign that I imserunderstand something in the way I use Qt proxy model concept ?
You are using it correctly - there is no built in shortcut for the steps you are doing.
You could use qobject_cast to speed things up if MyModel has the Q_OBJECT macro, but otherwise thats exactly how to use the models.
For situation like these, I typically create a wrapper method on the class that is using the models or extend the QSortFilterProxyModel to have such a method. YOu could, for example create a StandardSortFilterProxyModel that extends the former and only accepts QStandardItemModel based classes and provides a bunch of methods to access the items the way you need to.
Note that if you only want to get specific data out of the model instead of the item itself (like the text of the selected column), you can always use proxy_model->data(proxy_index) directly and get your value from the QVariant.

Simple 2-level hierarchy subclassing QAbstractItemModel

Having a data stored in QVector<QVector<QString>> data; (or alternatively a list of lists of strings if you are a Pythonist) how should I subclass QAbstractItemModel to be able to display (read-only) such a simple structure in QTreeView? I would like to see something like this:
"group 1"
data[0][0]
data[0][1]
"group 2"
data[1][0]
data[1][1]
etc.
From the docs, I read that I should override index(), parent(), rowCount(), columnCount() and data(). What is the simplest possible implementation of these methods to achieve my goal?
To make the possible answer more enlightening, how can one subclass QAbstractItemModel without using the internal pointers (stored in QModelIndexes). All the examples I have seen use the underlying model in a form of a tree with nodes (having pointers to their children and parent nodes) which make is easy to wrap inside QAbstractItemModel using the internal pointers. But can we use QAbstractItemModel even without a tree/node-like underlying structure and without QModelIndex's internal pointers? My question is based on the docs saying that you can use internal pointers, but I have not yet seen any example without it.
It doesnt really matter which level of hierarchy you use, Create custom class node
with QVector(commonly QList<QString> QList is similar to std::deque) to store data, and pointer to its child nodes QList<Node*> children. Top level of hierarchy is invisible root node. Then process data in model.
Really great guide, with node and model examples:
http://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html
You can basically copy-paste code and implement own setupModelData method.

Populate QComboBox with QEnums

I've looked in multiple places and cannot seem to find anything to work for my purpose.
I have this QComboBox that constantly changes (And could change after the program is completely finished).
To make it easier I made an Enum list for switch statements
public:
enum Race{
Race1,
Race2,
ect
}
The combo is filled with the same elements.
However, I want to make it even easier. So instead of changing the Combobox and changing the enum list, is there a way where all i have to do is add a new "race" to the enum list, that it will populate the combobox, so all i would have to do is a switch statement to handle new race?
Additional info:
I'm willing to put the enum list into a qstringlist.
I have Q_ENUMS (Race) set
Using Q_ENUMS will give you a way to iterate over your enum and add their enumerands to the combobox in a loop. However it will not give you the possibility to add a related GUI text for each enumerand. The enumerand name like it is written in your source code will be available only. Maybe your code side name is not what you want to see in your GUI as a text.
Remember that you can add any kind of QVariant supported user values to a combobox while you populate it with text strings... so you do not need to maintain an enumeration if there is some other kind key you can use instead.

Formatted text in QTreeWidgetItem

I need to create QTreeWidgetItems which have support for formatted texts, such as:
MyCreatedType - INTEGER(1)
(ie: the line above should have a "normal" part : MyCreatedType and a "formatted" part (INTEGER(1) in our case).
Any idea how to accomplish this?
Thanks.
What you need is a delegate. Delegates are explained here:
Star Delegate Example http://qt-project.org/doc/qt-4.8/itemviews-stardelegate.html
QItemDelegate Reference http://qt-project.org/doc/qt-4.8/qitemdelegate.html
The general procedure I follow when creating and using custom delegates:
Create a custom type with the information you want to encapsulate.
For your case, perhaps fields for the variable type name and type value.
Store these custom types in your model, wrapping them in QVariants to satisfy the return types required by QAbstractItemModel
Create a control that matches the UI you want.
In this case it might mean a QText label for "MyCreatedType" followed by a second label in bold for "Integer(1)".
Perhaps the control has methods like "setTypeName" and "setTypeValue"
Create a delegate that paints your specific control when your custom type is found.
You will have to map fields in the custom type to fields in the custom UI control as needed.
Associate your model and delegate with the Tree View you are using.
I hope this general procedure makes sense. I would recommend completing the Star Delegate Example and then reading my procedure, as it will make more sense with some background.

Qt equivalent of .NET data binding?

Is there an equivalent of .NET's data binding in Qt?
I want to populate some combo boxes and other widgets with QStrings that refer to specific entities in my database. However, it would be cleaner if I could bind the data to these strings rather than either querying the database again based off of a new combobox selection or some other scheme based off of building my own index of entities that would be searched with the QStrings.
The best I've come up with is to derive these entities from QString and pushing them into the widgets this way, but I've yet to actually try it. I'm not sure if it will work the way I want it to, and it seems like a nasty hack.
If there is no data binding, what do you suggest?
Thank you.
As the user nonchalant mentioned in a comment you can use the QDataWidgetMapper class.
This is quite an easy way of binding arbitrary widgets to data that is stored in a QAbstractItemModel.
The example on the linked page shows in a few lines of code, how you can link your data model to common used input widgets:
QDataWidgetMapper *mapper = new QDataWidgetMapper;
mapper->setModel(model);
mapper->addMapping(mySpinBox, 0);
mapper->addMapping(myLineEdit, 1);
mapper->addMapping(myCountryChooser, 2);
mapper->toFirst();
One way is using Qt Model/View Classes (with base at QAbstractItemModel), but they need that you widget inherits QAbstractItemView (this is widgets like QTableView etc.).
If you want map Qt model to set of widgets, which haven't nothing common with QAbstractItemView you can use QDataWidgetMapper, which maps separate widget to Qt Model/View indexes. But anyway, as said Aaron Digulla, you must write some boiler plate code...
Well, for combobox specifically, you can set a model. For QObjects in general you can use the notify signal for properties to connect or other non-property related signals. I think there is another way to do it but I can't recall.

Resources