Communication between models - qt

My program loads records (one per line) from file in raw format.
I have some Views for displaying this data in different ways:
Byte View
Decimal View (by doing some calculations with byte ranges)
Both Views must provide the ability for editing values.
Here is some code:
class Record
{
public:
void setByte (int position, Byte byte);
void setValue (ValueType type, Value value);
Byte getByte (int position) const;
Value getValue (ValueType type) const;
private:
RawData data;
}
I'm loading records in
QVector<Record> records;
Byte View is a simple table with hex bytes (row - line number, column - byte position). Decimal View is a table too (row - line number, one column - value).
So,what's the best way to design Model(s) for my Views with the ability to communicate with each other (f.e. sending signals when a data was modified from one of the Views)?

As you're using Qt, it's usually best to subclass one of the Qt's own models. This way you'll get a lot of view widgets for free, and at the same time make your code more consistent by following the same standard as the rest of the toolkit you use. Qt's documentation have some guidelines stating which methods/signals/slots you must implement.
Some classes to take a look at: QAbstractItemModel, QAbstractTableModel and QAbstractListModel
For the view side, you should prefer to use widgets provided by Qt, and if necessary, implement a delegate to change it's appearance.
In your specific case, I'd subclass QAbstractTableModel, and wrap your records inside this class.

Related

How to set text alignment for all the data in the tableView without using FOR loop?

I have create a tableView from database. Then, how to make set text alignment for all the data in this tableView? I do not want to use for loop to set each item in the tableView since it is time consuming.
The main code is as follows:
QSqlRelationalTableModel *model= new QSqlRelationalTableModel(NULL, db);
model->setTable(dbName);
model->select();
QTableView *tableView = new QTableView(NULL);
tableView->setModel(model);
Some may suggest to make a subclass of QSqlRelationalTableModel, but this also need a for loop to set all the data. Is there any other option? Thank you.
Use QIdentityProxyModel (since 4.8 - however, the idea is the same using a QAbstractProxyModel, the former is simply a convenience class that saves you time by allowing to reimplement only the methods you need). This approach avoids using a for loop since the data is set and returned at the moment it is being requested request on a per-element basis. In other words, instead of iterating over all the data and setting the required value (i.e. an imperative approach), you modify a method in the class that provides data to the view (more of a declarative approach), and the view pulls the data when necessary on its own.
To quote the docs:
http://doc.qt.io/qt-5/qidentityproxymodel.html
The QIdentityProxyModel class proxies its source model unmodified. Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model. For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the need to implement all data handling in the same class that creates the structure of the model, and can also be used to create re-usable components.
For our case, a possible implementation follows:
class StylingProxyModel : public QIdentityProxyModel
{
QVariant data(const QModelIndex &index, int role) const
{
if (role != Qt::TextAlignmentRole)
return QIdentityProxyModel::data(index, role);
return Qt::AlignCenter;
}
};
As you can see, the model will pass through itself the part of the data that doesn't match Qt::TextAlignmentRole, and return the desired value otherwise.
Set the QSqlRelationalTableModel as the source of this custom identity model, and set the proxy model to be the source for the view.
The "heavy artillery" option would be to subclass QStyledItemDelegate but I feel it's overkill for the case in question, being better suited for tasks that modify the view / delegate appearance in more profound ways than just setting text alignment.
See Set color to a QTableView row for further reading.

QMap with multifields

I need to store some data of table type like a QTableWidget but without a GUI. Something along the line of the following code:
QMap<QString, QString, int, QString, int>
Is there a way of achieve this in Qt? My Qt version is 5.3.
You seem to be unclear on a few concepts.
A map (also known in some languages as a dictionary) is an associative array. It associates a key to a value, that's about it, there are no "fields" involved whatsoever, just a key and a value.
There is no data type in Qt to model a database table. For such tasks you usually directly use SQL, Qt supports SQL with various different database drivers.
If you don't want to use a database but instead want to have "native" C++ types, you can simply create an object with all the desired fields:
struct Entry {
QString s1, s2, s3;
int i1, i2;
};
And then put that into whatever container you want.
QList<Entry> entryList;
QVector<Entry> entryVec;
QSet<Entry> entrySet;
You can wrap the container in a QAbstractListModel, implement the key functions and roles and have that model be used for a table widget or a QML view.

Qt Get signal-slot connection information from a widget

I have a feeling this isn't possible with the current API, but I have to ask. Is it possible to query a particular QObject's signal or slot name (from the metaObject) and retrieve all the QObjects and their slot or signals names that are connected to it?
I'm doing this because, in effect, I have a large number of layouts that contain an identical arrangement of widgets, for each layout there an object and each of the layout's widgets control the various properties of it. I want to keep one layout, and connect it's widgets' signal/slots to all the other objects in the same pattern, but in order to do this I need to 'record' all the signal-slot data.
Is it possible?
There is an interesting file in Qt - %Qtdir%/src/corelib/kernel/qobject_p.h, it contains class QObjectPrivate, used by Qt internally.
Use
static QObjectPrivate *get(QObject *o) function to get QObjectPrivate member for your widgets, and try to call its interesting members like
QObjectList receiverList(const char *signal) const; or QObjectList senderList() const;. File is totally undocumented, but it seems to contain exactly what you need...

Qt: QAbstractItemModel and 'const'

I'm trying to use a QTreeView for the first time with QAbstractItemModel and instantly have a problem. QAbstractItemModel interface declares methods as const, assuming they will not change data. But I want the result of a SQL query displayed, and returning data for a record with specified index requires the use of QSqlQuery::seek() which is non-const. Are there any 'official' guidelines to using a QAbstractItemModel with data that must be changed in order to get the number of items, data per item etc? Or must I hack C++ with const casts?
You can get away without any const casts by holding a pointer to the QSqlQuery; your pointer won't change, only the value to which you point, hence the operation will still be considered "const".

Binding a Qt model to an existing data-structure

I've a tree-like polymorphic data-structure, where the nodes are instances of class Node (implemented by me) or any its subclass. My application heavily uses Boost and the nodes are actually represented by boost::shared_ptr type rather than Node*.
Now, I want to create a Qt model to wrap my tree data-structure. Therefore I need a way to associate any model index with a node in my internal data structure. And here comes the problem:
Qt supports two ways of doing it:
First:
QModelIndex QAbstractItemModel::createIndex ( int row, int column, void * ptr = 0 ) const
Creates a model index for the given
row and column with the internal
pointer ptr.
And second:
QModelIndex QAbstractItemModel::createIndex ( int row, int column, quint32 id ) const
Creates a model index for the given
row and column with the internal
identifier, id.
Ok, and how exactly should I associate the node in my case? There is no possibility to associate a shared_ptr with the model index... Yes, I know, I can receive a raw pointer from my shared_ptr and supply it to CreateIndex(), but it smells bad - seems too unsafe to me.
Any ideas?
By the way, I feel that in general Boost / Qt integration seems to be not trivial at least in the area of memory management.
10x a lot.
If you want to do an easy association without passing a raw pointer, put the shared memory in a container and pass the ID value for that container element into the model index. For example, you could created declare
QMap< quint32, boost::shared_ptr< Foo > > index_map;
and use that. You'd have to be careful to not duplicate IDs for existing pointers, perhaps. It seems somewhat overly complicated to me....
You could also just keep a list of the pointers (to ensure continued availability as you need them) and then use the actual address of the pointer in the QModelIndex as well. This is probably what I would do.

Resources