0

Im trying to make the code which reads xml files and deserialize various qt controls from this xml, and im doing this using QDomDocument, and i want to get the QLlist from my deserealization method. And im having a bit of troubles, here is some code of the template class (.h) file:

 QList<T*> deserialize(QIODevice *input)
 {

        QList<T*> objects = QList<T*>();


        if(_deserializeObject(input, objects)) 
            return objects;

    }
    bool _deserializeObjects(QIODevice* input, QList<QObject*>& list);

and my .cpp file with deserialize method, here im reading the control tags from file:

bool Serializer::_deserializeObjects(QIODevice* input,  QList<QObject *> &objects)
{
    QDomDocument doc;
    if (!doc.setContent(input))
        return false;
    QDomElement root= doc.documentElement();

    for(int j = 0; j < root.childNodes().length();j++)
    {


         QObject* object;
         qDebug() << root.tagName();
        if(root.tagName().contains("QGroupBox"))   //  <------- Here i need to determine which control i need to process.
        {
           ????  
        }

       qDebug () << object->metaObject()->className();
       qDebug() << object->metaObject()->propertyCount();

    for(int i = 0; i < object->metaObject()->propertyCount(); i++)
    {

        object->metaObject()->cast()

        QMetaProperty prop = object->metaObject()->property(i);


            QString propName = prop.name();
             if(propName == "objectName")
                 continue;
             QDomNodeList nodeList = root.elementsByTagName(propName);
             if(nodeList.length() < 1)
                continue;
              QDomNode node = nodeList.at(0);
              QVariant value = object->property(propName.toLatin1().data());
              QString v = node.toElement().text();

              if(propName == "x")
              {
                  x = v.toInt();
              }
              else if(propName == "y")
              {
                  y = v.toInt();
              }
              else if(propName == "width")
              {
                  width = v.toInt();
              }
              else if(propName == "height")
              {
                  height = v.toInt();
              }
              if(propName == "geometry")
              {
                   continue;

              }
              object->setProperty(propName.toLatin1().data(), QVariant(v));


    }
    object->setProperty("geometry",QVariant(QRect(x,y,width,height)));
    objects.push_back(object);

    }
    return true;
}

In this part

  if(root.tagName().contains("QGroupBox"))   //  <------- Here i need to determine which control i need to process.
            {
               ????  
            }

           qDebug () << object->metaObject()->className();
           qDebug() << object->metaObject()->propertyCount();

        for(int i = 0; i < object->metaObject()->propertyCount(); i++)
        {
          ...
        }

I want to actually somehow get the type of the control by name, so the question is, can i cast QGroupBox to QObject saving the QGroupBox properties so QObject metaObject class name would be QGroupBox, so i can pass all this properties? Because i don't want to make the loops for each control type. Also i when i got the result like so:

     QList<QObject *> ds = s.deserialize<Object>((QIODevice*)&f);

Can i then just pass all QObjects in a loop and using QMetaObject class name and using qobject_cast cast each object to QPushButton,QLabel etc.?

SirLanceloaaat
  • 213
  • 9
  • 18

2 Answers2

1

QGroupBox is a subclass of QObject; therefore every QGroupBox is also a QObject, so you can treat it as one whenever you like. An explicit cast isn't necessary.

Iterating over all the diffent objects-derived-from-QObject in a loop will do what you want, provided that the methods you call on them are virtual methods (which they presumably will be -- in particular, QObject::metaObject() is a virtual method, so your loop will get the appropriate QMetaObject returned even if it is calling them method through a QObject pointer).

(As an aside, the annoying part of the process will probably be the part where you have read the name of the object's type from the XML and now need to instantiate an object of that type. AFAIK there is no good automatic way to do that in C++, so the best you can do is a factory function containing a giant switch statement with a separate case for every type you might want to instantiate)

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Soo it should be someting like this? `if(nodeName.contains("QPushButton")) { QPushButton *btn = new QPushButton(); object = btn; }` – SirLanceloaaat Aug 21 '13 at 16:27
  • Maybe more like: QObject * obj = NULL; if (nodeName == "QPushButton") obj = new QPushButton; else if (nodeName == "QGroupBox") obj = new QGroupBox; else [...] – Jeremy Friesner Aug 21 '13 at 16:43
  • I have one more question, can i somehow create my deserialized objects in a different thread? Deserialisation in ui thread freezes my UI, because of the loops etc. Is it possible that i can somehow create QPushButton/QLabel in a different thread, and then assign them to my gui? – SirLanceloaaat Aug 27 '13 at 17:25
  • I don't think so ( see http://stackoverflow.com/questions/13184555/creating-a-qwidget-in-a-non-gui-thread ). A better approach would be to figure out why your deserialization routine is taking so long to execute, and make it faster. Profiling is your friend here. – Jeremy Friesner Aug 27 '13 at 17:55
0

Alternatively, use a right tool for a right job. Chances are that what you are really building here is some XML thing for defining widget layouts etc. Qt already has a tool for that, the Qt Designer which uses an XML format for the UI definitions and a C++ code generator for actually producing a C++ code during compile time.

Jan Kundrát
  • 3,700
  • 1
  • 18
  • 29