Seite 1 von 1

QList mit QVariant

Verfasst: 5. Oktober 2010 22:22
von TheBert
Hi,

ich hab die doku zu QVariant rauf und runter gelesen, aber nirgendst etwas gelesen, ob man in QVariant auch einen zeiger speichern kann? Wenn dem doch so ist, habe ich es vermutlich überlesen.

Ich habe eine QList<QVariant> und möchte darin die zeiger verschiedener objekte speichern (QTextEdit, QPushButton, etc.), geht das?

Und dann wäre da noch der destructor, ich habe jetzt die liste mit den objekten, wie lösche ich die zeiger in der liste?

Eigentlich wollte ich mit qDeleteAll(anfang, ende) alles löschen, doch das geht ja mit QVariant nicht.

Ich iteriere also durch die liste, muss ich da jetzt jedes objekt casten und dann löschen?

Oder reicht es gar, wenn ich nur die liste leere mit .clear()? Vermutlich aber nicht.

Danke!

TestKlasse.h

Code: Alles auswählen

class TestKlasse
{
...

private:
QList<QVariant> myItems;
QPushButton *myButton;
QTestEdit *myTextEdit;
}
TestKlasse.cpp

Code: Alles auswählen


TestKlasse::TestKlasse()
{
myButton = new QPushButton();

myItem.append(myButton);
}

TestKlasse::~TestKlasse()
{
    QList<QVariant>::iterator it;

    for(it=myItems.begin();it!=myItems.end();++it)
    {
        //hier hängts
    }

myItems.clear();
}

[/code]

Verfasst: 5. Oktober 2010 22:27
von padreigh
Warum nimmst du nicht einfach eine QList<QObject*> aka QObjectList oder QList<QWidget*> ... und wozu das eingentlich?

Wenn du brav immer deine Objecte in irgendein parent addest löscht dieses Parent seine childs wenns selbst zerstört werden soll ... daher macht man doch

Code: Alles auswählen

#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])         
{
 QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
  
} // hier wird w dann zerstört und räumt alles auf was sein child ist ...
siehe http://doc.qt.nokia.com/4.6/qobject.html#details
Detailed Description

The QObject class is the base class of all Qt objects.

QObject is the heart of the Qt object model. The central feature in this model is a very powerful mechanism for seamless object communication called signals and slots. You can connect a signal to a slot with connect() and destroy the connection with disconnect(). To avoid never ending notification loops you can temporarily block signals with blockSignals(). The protected functions connectNotify() and disconnectNotify() make it possible to track connections.

QObjects organize themselves in object trees. When you create a QObject with another object as parent, the object will automatically add itself to the parent's children() list. The parent takes ownership of the object; i.e., it will automatically delete its children in its destructor.
In Qt werden laufen Objecte re-parent()ed ... zB wenn sie in nem Layout stekcen und du das Layout per QWidget::setLayout() einem Widget zuweist dann bekommen alle ge-layouteten Sachen dieses Widget als Parent ... es fehlt also nicht an QList<QVariant> sondern Basis API ;)

Verfasst: 5. Oktober 2010 22:31
von TheBert
Danke für die antwort!

Wenn alle objekte die in die liste kommen von QWidget oder QObject abgeleitet sind wäre das ok, aber mir gehts eher um die theorie, wenn z.b. ein objekt nicht von den o.g. abgeleitet ist, verwende ich QVariant.

Wie gehe ich da vor beim hinzufügen der zeiger und beim löschen im destructor?

Verfasst: 6. Oktober 2010 06:27
von Christian81
Dann musst du eben casten wie Du schon geschrieben hast. Aber was nützt es Dir? delete auf void* ist nicht möglich also musst du wieder auf einen korrekten Datentyp casten - nur welchen?
Und warum dann nicht gleich QList<void*> benutzen? Löschen geht dann natürlich genausowenig.
Was sollte man auch in einer Liste speichern was nicht einmal eine gemeinsame Basisklasse hat? Die Idee ist also grundsätzlich falsch.

Verfasst: 6. Oktober 2010 11:41
von TheBert
Christian81 hat geschrieben:Was sollte man auch in einer Liste speichern was nicht einmal eine gemeinsame Basisklasse hat? Die Idee ist also grundsätzlich falsch.
Danke für den hinweis, dann werde ich alle objekte in der liste von QObject ableiten und die liste als QList<QObject*> deklarieren. Das wäre dann der bessere ansatz?

Verfasst: 6. Oktober 2010 12:08
von franzf
TheBert hat geschrieben:Das wäre dann der bessere ansatz?
Keine Ahnung... Besser als QVariantList allemal.
Brauchst du denn jetzt wirklich alles mögliche an Objekten in einer Liste? Wie willst du dann darauf zugreifen? Nur dass alle Objekte in einer Liste stehen diesen Ansatz wählen ist nicht gut... Auf was für ein Interface willst du dich stützen? Für alles was über das Interface der Basisklasse (von mir aus QObject) hinaus geht, musst du den konkreten Type wissen und casten, dann stehen dir die Methoden zur Verfügung. Das bedeutet, du musst wie wild rumcasten, oder irgendwo zusätzlich Typinformationen speichern, mit denen du dann casten kannst. Über lange switch-Konstrukte musst du dann trotzdem gehen.

Kurz: Überlg dir ein besseres Programmdesign. Zum mal damit spielen ist das OK, für produktiven Einsatz ist es zu fehleranfällig und inperformant.

Verfasst: 6. Oktober 2010 22:27
von TheBert
Ich hab mich jetzt weiter eingelesen und und bin zu testzwecken gleich von QObject zu QGraphicsItem gegangen, und habe folgendes erstellt, jedoch wird in der methode deserialize() das auslesen beim kompilieren mit einem fehler abgebrochen.

Ich habe das listing aus einem qt buch, darin wird das auch so gemacht, bis auf das, das ich ein QGraphicsItem auslesen möchte.

Bitte um hilfe, wo der fehler ist, danke!

Code: Alles auswählen

class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    QList<QGraphicsItem*> items;

    QGraphicsTextItem *tItem;
    QGraphicsLineItem *lItem;
    QGraphicsRectItem *rItem;
    QGraphicsItem *gItem;

    void serialize();
    void deserialize();
};

Code: Alles auswählen

[...]
void MainWindow::init()
{
    tItem = new QGraphicsTextItem("Test");
    tItem->setData(0, "TextItem");
    lItem = new QGraphicsLineItem(10,5,10,20);
    lItem->setData(0, "LineItem");
    rItem = new QGraphicsRectItem(0,0,100,100);
    rItem->setData(0, "RectItem");

    items.append(tItem);
    items.append(lItem);
    items.append(rItem);
}

void MainWindow::serialize()
{
    QFile File("/home/bert/file.dat");
    File.open(QIODevice::WriteOnly);
    QDataStream ds(&File);
    ds << items;
    File.close();

    qDeleteAll(items.begin(), items.end());
    items.clear();
}

void MainWindow::deserialize()
{
    QFile File("/home/bert/file.dat");
    File.open(QIODevice::ReadOnly);
    QDataStream ds(&File);
    
    while(!ds.atEnd())
    {
        ds >> gItem;
        items.append(gItem);
    }

    File.close();

    if(items.count() > 0)
    {
        QList<QGraphicsItem*>::iterator it;

        for(it=items.begin();it!=items.end();++it)
        {
            QGraphicsItem *itm = qgraphicsitem_cast<QGraphicsItem*>(*it);
            qDebug(qPrintable(itm->data(0).toString()));
        }
    }
}
Fehlermeldung:
error: no match for ‘operator>>’ in ‘ds >> ((MainWindow*)this)->MainWindow::gItem’
Was im eigentlich erreichen will ist folgendes, ich möchte gerne meine QList<QGraphicsItem*> in eine datei serialisieren, wieder auslesen und wieder eine QList<QGraphicsItem*> erhalten.

Verfasst: 6. Oktober 2010 22:54
von kater
Und wo ist die Fehlermeldung?

Verfasst: 7. Oktober 2010 06:32
von Christian81
Du schreibst eine QList<QGraphicsItem*> in den Datastream aber beim rauslesen versuchst Du ein QGraphicsItem* zu lesen. Wie soll das gehen?
Des weiteren speicherst Du Pointer und leist sie später wieder aus- was soll das? Woher willst Du wissen das die Pointer noch gültig sind? Nach einem Neustart können sie gar nicht mehr gültig sein!
Und nun zur Fehlermeldung - QDataStream hat nunmal keinen operator >>(void*) bzw. operator>>(QGraphicsItem*) und zwar aus den oben genannten Grund.