In the last article I was considered an example of how to save objects in a graphical scene SVG file, and then we were able to open it in CorelDraw. Now try the same file open and restore the graphics in QGraphicsScene .
Note that we will not use QSvgRenderer class for this, for the reason that it is easily put the contents of SVG files in the graphic scene, but it will be one single graphic, but if you need to have it restored as a separate graphic objects, such as , QGraphicsItem , you will need to parse the SVG file to make of it all graphical objects.
Since SVG file is of XML-format structure, then disassemble it does not present any difficulty using classes QDomDocument family.
Структура проекта
As an example, the draft of the preceding article to be used, but will be diluted with additional class two static methods.
- SVGExample.pro - the profile of the project;
- svgreader.h - header parsing SVG file;
- svgreader.cpp - source SVG file parser;
- mainwindow.h - header file of the main application window;
- mainwindow.cpp - file source code of the main application window;
- mainwindow.ui - file forms the main application window;
- main.cpp - start file the application source code.
Structure of SVG file
Because we need to parse the file, look at his insides.
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg width="141.111mm" height="141.111mm" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny"> <title>SVG Example</title> <desc>File created by SVG Example</desc> <defs> </defs> <g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" > <g fill="#ff0000" fill-opacity="1" stroke="#000000" stroke-opacity="1" stroke-width="2" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,0,0)" font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal" > <rect x="10" y="50" width="100" height="50"/> </g> </g>
So, we are interested in svg tag, g, rect . The tag contains svg the size of the graphic scenes - it viewBox. The tag contains a rectangle rect size and the tag g, which wrapped rect tag contains the fill color and outline of a rectangle, and the thickness of the outline. They will need and Spars.
mainwindow.ui
This file will be added when the button load, on a signal from which the open file dialog and launch the opening of our SVG file.
SVGExample.pro
I call your attention to the fact that the profile of the project will connect the module xml need.
QT += xml
svgreader.h
#ifndef SVGREADER_H #define SVGREADER_H #include <QList> #include <QGraphicsRectItem> class SvgReader { public: SvgReader(); static QList<QGraphicsRectItem *> getElements(const QString filename); static QRectF getSizes(const QString filename); }; #endif // SVGREADER_H
svgreader.cpp
#include "svgreader.h" #include <QPen> #include <QFile> #include <QMessageBox> #include <QDomDocument> #include <QStringList> SvgReader::SvgReader() { } QList<QGraphicsRectItem *> SvgReader::getElements(const QString filename) { QList<QGraphicsRectItem *> rectList; // Declare the stack list boxes QDomDocument doc; // document object QFile file(filename); // Open your SVG-file // If it is not opened, or have failed to transmit the contents in QDocDocument if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) return rectList; // the refund list, but empty // We are looking for all objects in a document with tag g QDomNodeList gList = doc.elementsByTagName("g"); // Getting them to touch for (int i = 0; i < gList.size(); i++) { QDomNode gNode = gList.item(i); // Select from the node list QDomElement rectangle = gNode.firstChildElement("rect"); // And we seek in her element c rect tag // If the resulting elements are not zero, then if (rectangle.isNull()){ continue; } else { // We begin to create a rectangle QGraphicsRectItem *rect = new QGraphicsRectItem(); // This flag makes the object moves, the need to test rect->setFlag(QGraphicsItem::ItemIsMovable); // Taking the dimensions of rect tag QDomElement gElement = gNode.toElement(); rect->setRect(rectangle.attribute("x").toInt(), rectangle.attribute("y").toInt(), rectangle.attribute("width").toInt(), rectangle.attribute("height").toInt()); /* Take away from the element node gNode color options * Yes yes yes ... because of gNode, instead of the rectangle. These parameters are stored in the tag g * */ QColor fillColor(gElement.attribute("fill", "#ffffff")); fillColor.setAlphaF(gElement.attribute("fill-opacity","0").toFloat()); rect->setBrush(QBrush(fillColor)); QColor strokeColor(gElement.attribute("stroke", "#000000")); strokeColor.setAlphaF(gElement.attribute("stroke-opacity").toFloat()); rect->setPen(QPen(strokeColor,gElement.attribute("stroke-width", "0").toInt())); rectList.append(rect); } } file.close(); return rectList; } QRectF SvgReader::getSizes(const QString filename) { QDomDocument doc; // initialize the stack object QDomDocument QFile file(filename); // Open your SVG-file // If it is not opened, or have failed to transmit the contents in QDocDocument if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) return QRectF(0,0,200,200); // the return values for the default scene /* Then pick up a list of items with the tag svg. * If a list of elements is not empty, * take the size of the graphic scenes. * */ QDomNodeList list = doc.elementsByTagName("svg"); if(list.length() > 0) { QDomElement svgElement = list.item(0).toElement(); QStringList parameters = svgElement.attribute("viewBox").split(" "); return QRectF(parameters.at(0).toInt(), parameters.at(1).toInt(), parameters.at(2).toInt(), parameters.at(3).toInt()); } return QRectF(0,0,200,200); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> #include <QGraphicsRectItem> #include <QSvgGenerator> #include <QFileDialog> #include <QPainter> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: void on_saveButton_clicked(); void on_loadButton_clicked(); private: Ui::MainWindow *ui; QGraphicsScene *scene; QString path; // The path to save the file }; #endif // MAINWINDOW_H
mainwindow.cpp
Here in this file only the contents directly related to the analysis of the SVG file. The pressing processing slot button is selected using a file dialog box, and is broken down into graphical objects.
#include "mainwindow.h" #include "ui_mainwindow.h" #include "svgreader.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); scene = new QGraphicsScene(); ui->graphicsView->setScene(scene); scene->setSceneRect(0,0,400,400); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_saveButton_clicked() { // The code from the previous tutorial on working with SVG } void MainWindow::on_loadButton_clicked() { QString newPath = QFileDialog::getOpenFileName(this, trUtf8("Open SVG"), path, tr("SVG files (*.svg)")); if (newPath.isEmpty()) return; path = newPath; scene->clear(); scene->setSceneRect(SvgReader::getSizes(path)); // To set a graphic scene objects, received them with a method getElements foreach (QGraphicsRectItem *item, SvgReader::getElements(path)) { QGraphicsRectItem *rect = item; scene->addItem(rect); } }
Result
As a result, you will be able to parse the SVG file you saved to take away from him even rectangles. If you want to take all the other objects, you have pretty sweat, and write a parser for all these other objects similar to the rectangle. The only thing I want to note, do not try to use this code to open a file that was created originally in CorelDraw, the fact that the structure of the SVG file version is also very different. And this code for parsing a file that was created in the previous lesson, and the structure of the generated package CorelDraw files is slightly different and will not be read completely.
A project that brings together both lessons downloaded from the following link: SvgExample
Здравствуйте!
Там в коде у меня есть:
Для формирования задал объект QGraphiscPathItem
А кажется понял, я должен из атрибутов path сформировать заново элементы Ellipse, просто нужно правильно подобрать эти атрибуты.....
Ну да. Там должны быть координаты, их нужно пропарсить и по ним построить Path, либо преобразовать их в эллипс. Вообще, кое-что кривовато переносится в SVG местами.
How can I open another polygon type such as circle(ellipse) ?
The principle will be similar. You need to research content of svg file and make parsing of needed tag.
Thank You sir, So how can I change this method
For what You want to use another class instead of QRectF?
Sir,I tried your code for open ellipse item.but my program not open ellipse item.what should I need to do?
I think You have another version of SVG file. First, need to see content of SVG file. It is simple XML-format, therefore just need to research content.
Sir I post is as a topic,please help me to solve this problem
Скажите пожалуйста, как пользоваться QSvgRenderer и загружать целиком в QGraphicsScene ?
Если делаю так, то получаю белый экран:
А если делаю с помощью вашего класса, то тоже получаю белый экрак.
Рисую на сцене так: Qt/C++ - Урок 021. Рисование мышью в Qt
Вот так целиком добавлять можно