Uložení do XML souboru

Jeste neumime obrazek editorat, misto toho zkusime cteni a zapisovani do souboru.

Priklad souboru abc.xml, ve kterem je ulozen popis dvou elips a jednoho obdelniku.

   <?xml version="1.0" encoding="UTF-8"?>
   <data>
       <ellipse name="elipsa 1" pen="orange" brush="lime" x="209" y="209" width="100" height="80"/>
       <ellipse name="elipsa 2" x="325" y="108" width="100" height="80"/>
       <rectangle name="rectange 1" x="100" y="100" width="100" height="80"/>
   </data>

Nejprve si popiseme ukladani do souboru - bude snad prehlednejsi nez cteni souboru.

( Muzete se podivat na tutorial: http://www.bogotobogo.com/Qt/Qt5_QtXML_QDomDocument_QDomElement.php )

Do menu “File” na polozku “Save” pripojime nasledujici funkci.
QFileDialog::getSaveFileName zobrazi dialog a necha uzivatele vybrat jmeno pro ukladany soubor.
Pokud by uzivatel ukoncil dialog a nevybral jmeno souboru bude v promenn fileName prazdny retezec.

void MainWindow::on_actionSave_triggered ()
{
    QString fileName = QFileDialog::getSaveFileName (this, "Save file");
    if (fileName != "")
        saveFile (fileName);
}

Funkce saveFile otevre soubor pro zapis.
Pokud se soubor povede otevrit, pripoji na soubor objekt typu QXmlStreamWriter.
QXmlStreamWriter nam vyrazne usnadni vytvareni XML souboru.

void MainWindow::saveFile (QString fileName)
{
    QFile f (fileName);
    if (f.open (QFile::WriteOnly))
    {
        QXmlStreamWriter w (&f);
        writeXml (w, scene);
    }
}

Fuknce writeXml je na konci souboru io.cc
Stream writer se neustale predava odkazem &, tj. pracujeme stale se stejnym stream writerem.
Funkce writeBegin vytvori povnny uvod a otevre element/znacku *<data>*
Potom writeXml v cyklu projde prvky graficke sceny.
Prvky sceny jsou odvozene z typu QGraphicsItem.
My si vybereme jen prvky, ktere nejsou vnorene do jinych grafickych prvku.

#include <QXmlStreamWriter>
 
void writeBegin (QXmlStreamWriter & w)
{
    w.setAutoFormatting (true);
    w.writeStartDocument ();
    w.writeStartElement ("data");
}
 
void writeEnd (QXmlStreamWriter & w)
{
    w.writeEndElement(); // end of data
    w.writeEndDocument();
}
 
void writeXml (QXmlStreamWriter & w, QGraphicsScene * scene)
{
    writeBegin (w);
 
    for (QGraphicsItem * item : scene->items (Qt::AscendingOrder))
    {
       if (item->parentItem() == nullptr)
          writeItem (w, item);
    }
 
    writeEnd (w);
}

Určení typu jednotlivých grafických prvků

Pomocna funkce itemType urci jmeno pouzivane v elementech <rectangle>, <ellipse> atd.
Parametr item je ukazatel na QGraphicsItem z ktereho jsou odvozeny jine typy, napr. QGraphicsEllipseItem.
Priblizne takto :

class QGraphicsItem
{
};
 
class QAbstractGraphicsShapeItem : public QGraphicsItem
{
};
 
class QGraphicsEllipseItem : public QAbstractGraphicsShapeItem
{
};
  • QGraphicsItem
    • QAbstractGraphicsShapeItem
      • QGraphicsEllipseItem

Přetypování z odvozene tridy na nadrazenou je v C++ automaticke.
Přetypování z nadrazene tridy na odvozenou se nemusi vzdy podarit.
Výraz dynamic_cast zkusi pretypovat ukazatel a pokud je pretypovani nepodari vrati nullptr.

   QGraphicsItem * item; // nejaky neznamy objekt, mozna i nullptr
 
   QGraphicsEllipseItem * e = dynamic_cast < QGraphicsEllipseItem * > (item);
   if (e != nullptr)
   {
       /* item je ellipsa, pretypovani se povedlo */
   }

A zde je slibovana funkce itemType.

QString itemType (QGraphicsItem * item)
{
    QString result = "node";
    if (dynamic_cast < QGraphicsRectItem * > (item) != nullptr)
       result = "rectangle";
    if (dynamic_cast < QGraphicsEllipseItem * > (item) != nullptr)
       result = "ellipse";
    if (dynamic_cast < QGraphicsLineItem * > (item) != nullptr)
       result = "line";
    return result;
}

Ukládání jednotlivých grafických prvků

Funkce writeItem vytvori novy XML element, napr. <ellipse>

   <ellipse name="jmeno" x="10" y="20">
      <rectangle>
        ...
      </rectangle>
   </ellipse>

Ulozi jednotlive atributy x = , y ==
Zjisti zda je prvek typu QAbstractGraphicsShapeItem, pokud ano muze ziskat a ulozit vlastnosti pen a brush.

    if (QAbstractGraphicsShapeItem * shape = dynamic_cast < QAbstractGraphicsShapeItem * > (item))
    {
      /* promenna shape je deklarovana uvnitr if ( ),
         je inicializovana pomoci dynamic_cast
         a existuje jen vramci slozenych zavarok, kde je tento komentar. */
    }

Pokud prvek obsahuje vnorene prvky, vypiseme vnorene prvky.
( <rectangle> v predesle ukazce XML souboru )

    for (QGraphicsItem * t : item->childItems ())
        writeItem (w, t);

Nakonec uzavreme element, napr </ellipse> pomoci writeEndElement.

void writeItem (QXmlStreamWriter & w, QGraphicsItem * item)
{
    w.writeStartElement (itemType (item));
    w.writeAttribute ("name", item->toolTip());
 
    w.writeAttribute ("x", QString::number ( item->x() ));
    w.writeAttribute ("y", QString::number ( item->y() ));
 
    if (QAbstractGraphicsShapeItem * shape = dynamic_cast < QAbstractGraphicsShapeItem * > (item))
    {
        w.writeAttribute ("pen", penToString (shape->pen()));
        w.writeAttribute ("brush", brushToString (shape->brush()));
 
        if (QGraphicsRectItem * r = dynamic_cast < QGraphicsRectItem * > (shape))
        {
           w.writeAttribute ("width", QString::number ( r->rect().width() ));
           w.writeAttribute ("height", QString::number ( r->rect().height() ));
        }
 
        if (QGraphicsEllipseItem * e = dynamic_cast < QGraphicsEllipseItem * > (shape))
        {
           w.writeAttribute ("width", QString::number ( e->rect().width() ));
           w.writeAttribute ("height", QString::number ( e->rect().height() ));
        }
    }
 
    for (QGraphicsItem * t : item->childItems ())
        writeItem (w, t);
 
    w.writeEndElement();
}
 
qt/graphics_write_xml.txt · Last modified: 2020/09/30 11:22 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki