Storing custom objects in QStandardItemModel - c++

I'd like to store custom objects (let's say instances of MyDataClass) in a tree structure, and linked with a view. So I used QStandardItemModel. I think that MyDataClass should inherit from QStandardItem :
class MyDataClass : public QStandardItem
{
public:
MyDataClass(QString name)
private:
vector<float> someData;
}
But I cannot figure out how to store instances of this class in a QStandardItemModel.
I tried QStandardItem.setChild and then appendRow but it does not work and I think I don't really get the QStandardItemModel thing.
I think that the solution deals woth QStandardItem.setData but I cannot figure out how it works for custom objects.

I have finally make it work using QVariant.
To fill the model with custom data :
MyDataClass *data;
... // adding some data
QVariant variant;
variant.setValue(data);
QStandardItemModel model; // here is your model
QStandardItem *parentItem = model.invisibleRootItem();
QStandardItem *item = new QStandardItem();
item->setData(variant);
parentItem->setChild(0, 0, item); // adding the item to the root
Later, when you want to retrieve your data :
MyDataClass *retrievedData = model.invisibleRootItem()->
child(0, 0)->data().value<MyDataClass*>();
Note that I had to add a line in the class declaration :
class MyDataClass : public QStandardItem
{
public:
MyDataClass(QString name)
private:
vector<float> someData;
}
Q_DECLARE_METATYPE(MyDataClass *) // add this line
Thank you for your help.

You can use QStandardItemModel::setItemPrototype.
http://qt-project.org/doc/qt-4.8/qstandarditemmodel.html#setItemPrototype
Inherit from QStandardItem and reimplement method clone.
Create a new instance of your item and pass it to setItemPrototype.

Related

how to override functions like QTreeWidget::currentItem() when using a subclass inherit from QTreeWidgetItem

I want to put some extrenal data in QTreeWidgetItem, so I made a subclass like this.
class DContentItem :public QTreeWidgetItem
{
public:
DContentItem();
const QString randomName = generateRandomName();
private:
QString generateRandomName();
};
then I add one to a QTreeWidget:
DContentItem *item = new DContentItem();
item->setText(0, "New One");
ui->widgetTree->addTopLevelItem(item);
when someone click the tree, I want to access it.
DContentItem *current_item = ui->widgetTree->currentItem();
But this gives an error, from currtItem()return QTreeWidgetItem, but here what I want is a DContentItem.
error: cannot initialize a variable of type 'DContentItem *' with an rvalue of type 'QTreeWidgetItem *'
I have tried writing a new function to return a DConteItem, but it seems a little complex. What is the better way to do this?
class a
class b subclass a
function foo return a
how to let it return b?
Wrong:
DContentItem *current_item = ui->widgetTree->currentItem();
Correct:
DContentItem *current_item = static_cast<DContentItem *>(ui->widgetTree->currentItem());
Thanks vahancho very much.

Why is QObject ::findChildren returning children with a common base class?

I am using QObject as a base class for a composite pattern.
Say I have a parent class File (in a contrived example) to which I am adding children of different types, HeaderSection and PageSection. File, HeaderSection and PageSection are all Sections. The constructor for Section takes a parent object which is passed through to QObject's constructor, setting the parent.
e.g:
class Section : public QObject {
Q_OBJECT
// parent:child relationship gets set by QObject
Section(QString name, Section *parent=NULL) : QObject(parent)
{ setObjectName(name);}
QString name(){return objectName();}
};
class File: public Section {
public:
// probably irrelevant to this example, but I am also populating these lists
QList<Section *> headers;
QList<Section *> pages;
};
class Header : public Section {
Header(QString name, File *file) : Section(name, file){}
};
class Page: public Section {
Body(QString name, File *file) : Section(name, file){}
};
Syntax for construction in the definition may be incorrect, apologies, I'm used to doing it outside. Anyway, when I do this:
File *file = new file();
Header *headerA = new Header("Title", file);
Header *headerB = new Header("Subtitle", file);
Page *page1 = new Page("PageOne", file);
Page *page2 = new Page("PageTwo", file);
QList<Page*> pages = file->findChildren<Page*>();
for(int i=0; i < pages.size(); i++)
qDebug() << pages.at(i)->name();
I get the following output:
Title
Subtitle
PageOne
PageTwo
What am I missing here? Surely if findChildren looked for common base classes then it would only ever return every single child of a Widget (for example), which I know it doesn't in normal use.
Also, if I iterate over the list of children returned and use dynamic_cast<Page*> on each returned child, I get the expected two Page items.
The answer is as #Mat and #ratchet freak tell me - I needed Q_OBJECT in every subclass, not just the base class.

What is the correct method to get all QLabels form UI in QList?

QList<QLabel> labelList;
foreach (QLabel lbl, ui)
{
labelList.append(lbl);
}
I wanted to add all QLabels in the QList, above code generates an error, please help
You can get the list of pointers to the child widgets using QList<T> QObject::findChildren ( const QString & name = QString() ). If ui belongs to a QMainWindow, it could be done by:
QList<QLabel *> list = ui->centralWidget->findChildren<QLabel *>();
To find children of non-QMainWindow containers, such as QDialog or QWidget, use:
QList<QLabel *> list = this->findChildren<QLabel *>();
Now you can iterate through the list like:
foreach(QLabel *l, list)
{
...
}
Or, in C++11:
for(auto l : list)
{
...
}
findChildren should do exactly that: try
QList<QLabel*> labelList; // note the pointer!
labelList = findChildren<QLabel*>();
to be executed in a QWidget derived object

Class name from QMetaProperty

I am working on making my own designer widget that looks and functions like qt. But now I needed to know how the property is created. I knew we can get the properties of an widget using QMetaObject and QMetaProperty but my question is will I be able to get the class name of each property. Like object name property comes from QObject and geomentry property comes from QWidget. Is it so that i should hard code myself to model or is there a way to get the classInfo from property. I have attached the image which im trying to achieve any response or related post is appreciated.
thanks,
In order to create mapping between classes and their properties you need to traverse through your object's class hierarchy. Here is the sample code that crates such mapping:
// Create properties per class mapping for the initialObject.
const QMetaObject *mo = initialObject->metaObject();
QMap<QString, QStringList> propertyMap;
do {
QStringList properties;
for(int i = mo->propertyOffset(); i < mo->propertyCount(); ++i) {
properties << QString::fromLatin1(mo->property(i).name());
}
propertyMap[mo->className()] = properties;
} while (mo = mo->superClass());
Now the propertyMap contains all properties sorted by the class names they belong to.

wxTreeItemId how to get data

I'm tried to create my own version of the wxTreeItemId which stores extra data. Sew below:
TreeItemId.h
#ifndef TREE_CTRL
#define TREE_CTRL
#include "wx/treectrl.h"
#include "Particle System.h"
class TreeItemId : public wxTreeItemId
{
public:
TreeItemId(ParticleSystem* system);
private:
ParticleSystem* particleSystem;
};
TreeItemId.cpp
TreeItemId::TreeItemId(ParticleSystem* system)
: wxTreeItemId()
{
particleSystem = system;
}
I want to use an event to get the selected TreeItem but I can't work out a way of using my treeItem class rather than the standard.
I want to do something in the line of:
void TopRightPanel::OnSelChanged(wxTreeEvent& event)
{
TreeItemId *item = (TreeItemId)event.GetItem();
}
This doesn't work though... Any advice would be appreciated. Do I need to use my own version of wxTreeItemData?
You should subclass your data object from wxTreeItemData instead of wxTreeItemId.
Let's say you have MyItemData : public wxTreeItemData {}; then
wxTreeItemId itemId = event.GetItem();
MyItemData * data = (MyItemData *)m_MyTreeCtrl->GetItemData(itemId);
if(data) { /* Doo what you need here */ }
In order to set the item data you need to use InsertItem() method and specify the data object there. Or use SetItemData() for existing item and pass item ID and data object to this method.