Calling QStandardItem mimeData() method - qt

In my app I have a QTableView and a QTreeView. I need to drag from the table view and drop in the tree view. I had this working, but I reworked the app so that the GUI elements were created in C++ and this this has stopped working.
I can pick up an item from the table and drop it on the tree - all looks fine. However, the table model's mimeData() method is not called, so the dropped data is incomplete.
How do I get the drag drop operation to call the mimeData() method?
The tables' model is based on a QStandardItemModel.

Had a similar issue with my code. Make sure you override the mimeData properly. For example, some examples show the prototype as:
QMimeData *mimeData(const QList<QTreeWidgetItem *> &items) const;
while the correct prototype is:
QMimeData * mimeData(const QList<QTreeWidgetItem *> items) const;
(note the missing reference in front of items). And if you implement it incorrectly, you're not overriding the mimeData() but implementing another mimeData() function.
An easy check to make sure you're doing it right is to declare a function you want to override, but change its return type from QMimeData* to bool, such as:
bool mimeData(const QList<QTreeWidgetItem *> items) const;
If you are overriding a correct function, your code will not compile due to conflicting return type (you're not allowed to override only the return type). If your code compiles fine, you are not overriding anything but instead declaring a new function. Check the function signature.

Related

How to pass a QTextEdit to signal/slot mechanism

I have read some topics here about signals and slots and its parameters but found nothing about following problem:
I am working with Qt 5.7
I simply have 2 classes, inside 1st, I want to emit signal with string message and location(or specific object) where to display it.
Now it is like this: I have 1st class where I emit signal :
emit signalWriteToTextEdit("hallo","textEdit_3");
What I want to do is somehow pass as the second argument an object like textEdit. No QString as its now.
Inside 2nd class is the slot:
void writeToTextEdit(QString info, QString where){
where.append(info); //I would like to do something like this
}
Just dont know how to consider that second parameter "where" as accessible object for example textEdit, so I could change its content.
I am thinking also if this is possible:
Is there some method for Ui object like finding elements by name?
Is it possible to go with foreach over all elements in ui and check their names...? I tried but dont know how to go through that.
If its not clear, I will explain more
After a little digging, I came across the QObject::findChild function. This will allow a string lookup recursively through the UI, those I am unsure of performance.
Edit for more detail:
Returns the child of this object that can be cast into type T and that is called name, or 0 if there is no such object. Omitting the name argument causes all object names to be matched. The search is performed recursively.
If there is more than one child matching the search, the most direct
ancestor is returned. If there are several direct ancestors, it is
undefined which one will be returned. In that case, findChildren()
should be used.
Just use QWidget* or QObject* (if it is not always a widget) as the argument type
signals:
void writeToTextEdit(const QString &what, QWidget *where)
or if it is always a QTextEdit even more specifically
signals:
void writeToTextEdit(const QString &what, QTextEdit *where)
Though it is not clear why the code needs to emit a signal if it has access to the target object, it could simply call setText directly

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.

Qt QAbstractItemModel function data() called with undefined role

I want to create a custom list using QListView and so I had to extend QListView, QItemDelegate and QAbstractListModel and then implement the specific methods, along with QAbstractItemModel::data(const QModelIndex & index, int role = Qt::DisplayRole) const.
It displays correctly on the screen at first glance, but the problem occurs after populating the list model.,The function data(index,role) is called 4-5 times per item model with different roles (some of them undefined roles/out of range/probably random). And it occurs not only after the initialization of the list model! When I hover a list element, the view calls data(index,role) with the correct index and role but right afterwards it is called again with an unexpected role value.
It seems an awkward behavior. I couldn't find the source of the strange calls. I put logs in every method of my custom classes to be sure that I'm not calling by mistake the data(index,role) method with wrong values.
Does anyone have some ideas where to look at or why this strange calls occur?
EDIT
The source of the "strange" calls is in:
QSize CDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
return QSize(QItemDelegate::sizeHint(option, index));
}
somehow when calling QItemDelegate::sizeHint() it triggers data() with different role values.
In my case I have defined role values starting from 0(0,1,2,3). According to #Jens those values are reserved. Changing the starting value of my custom roles solved my problem.
Custom roles start at 0x100, 0..3 are roles defined by Qt. See the list of roles in qnamespace.h. 13 for example ist SizeHintRole.
The different role calls stem from the interns of QListView, which is trying to figure out, how the cells should be displayed. Example: If you want to change the font of a row, you simply add the switch for FontRole to your data() implementation and pass back a bold font whenever something is important and should be displayed in bold.

How to reset a user-defined tree model in Qt

I have finally implemented my own tree model (inherited from QAbstractItemModel) for a QTreeView.
A blueprint of what I did can be found here:
http://www.trinitydesktop.org/docs/qt4/itemviews-simpletreemodel.html
So, I have:
the user-defined tree items, which are pure C++ (no Qt) and these are wrapped by
the TreeModel class which is inherited from QAbstractItemModel (like in the example link above).
I now have a generated tree hierarchy of tree items from (1.). This hierarchy has thousands of items, and I want to insert this hierarchy into my existing model at runtime.
How do I do that?
(All I have is the root-node to the c++ tree hierarchy as TreeItem pointer and a QModelIndex of the existing model where the "new sub-tree" has to be inserted)
I found modelAboutToBeReset(), modelReset(), and endResetModel() from here: http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#beginResetModel
But I don't know if these are the right functions, and, if they are, how to use them.
Any ideas?
You should call modelAboutToBeReset() before removing real items from your model. This call will "freeze" all views from requesting any data. After removing all real items you should call endResetModel() - it will unfreeze data requesting and force all connected views to update it content.
This is what i did:
void
TreeModel::addNewSubTreeToModel( TreeNode* t_rootOfNewTree, TreeNode* t_addNewSubTreeAsChildOfThisItem )
{
beginResetModel();
t_rootOfNewTree->setParent(t_addNewSubTreeAsChildOfThisItem);
t_addNewSubTreeAsChildOfThisItem->addChild(t_rootOfNewTree);
endResetModel();
}

QTreeView & QAbstractItemModel & insertRow

I'm trying to implement QAbstractItemModel for QTreeView. I have problem with inserting rows.
I noticed that if I insert at the beginning of my application all works fine. But If I insert rows later - after some other operations (like selections etc.) new items stay invisible. Moreover QTreeView seems to doesn't work at all! Do I have to emit some signals to notify QTreeView about rows insertion?
This is my insertion method:
bool LayersModel::insertRows(int position, int count, const QModelIndex & parent)
{
LayersModelItem * parentItem = getItem(parent);
if (position > parentItem->childCount())
return false;
beginInsertRows(parent,position,position+count-1);
bool result = true;
for (;count;--count)
result &= parentItem->insertChildren(position, new LayersModelItem());
endInsertRows();
return result;
}
LayersModelItem is class with QList with its children and data.
Full code of my project (KDE libs needed) is here:
https://github.com/coder89/PhotoFramesEditor/tree/v0.0.8
To see the problem select one of blue item on main window and then right-click on it and select "Delete item". (this method is in Canvas::removeItems()) and it is completly commented - I'm desperate and I've tried to find reason of this problem... (in fact it wasn't delete anything - it adds new item).
Thanks for any help & advice!
Just a quick guess, the QT Doc for QAbstractItemModel says...
The model emits signals to indicate
changes. For example, dataChanged() is
emitted whenever items of data made
available by the model are changed.
Changes to the headers supplied by the
model cause headerDataChanged() to be
emitted. If the structure of the
underlying data changes, the model can
emit *layoutChanged() to indicate to
any attached views that they should
redisplay any items shown, taking the
new structure into account*.
So i guess, you need to emit layoutChanged() signal from your model (whenever you change the data in model) in order to update connected views.
Also read the QT docs for model view architecture, how it is implemented in QT
see if that helps, if it doesn't i will try to download your code and debug it and see, what's wrong.
Good Luck

Resources