Evgenii Legotckoi
Evgenii Legotckoi01 квітня 2016 р. 12:51

Qt/C++ - Урок 045. SvgReader на Qt. Завантаження даних із SVG-файлу в QGraphicsScene

У минулій статті було розглянуто приклад того, як зберегти об'єкти графічної сцени у файл SVG, а потім ми змогли відкрити його в CorelDraw. А тепер спробуємо цей ж файл відкрити і відновити графічні об'єкти в QGraphicsScene .

Зазначу, що ми не будемо використовувати клас QSvgRenderer для цього з тієї причини, що він без проблем помістить вміст файлу SVG на графічну сцену, але це буде один єдиний графічний об'єкт, а якщо Вам потрібно, щоб він відновився в як окремі графічні об'єкти, наприклад, QGraphicsItem , то необхідно буде парсить файл SVG виготовляти з нього всі графічні об'єкти.

Оскільки файл SVG має структуру XML-формату, то розібрати його не уявить жодної праці за допомогою класів сімейства QDomDocument.


Структура проекта

Як приклад, використовуватиметься проект із попередньої статті, але буде розведений додатковим класом із двома статичними методами.

  • SVGExample.pro - профайл проекту;
  • svgreader.h - заголовний файл парсера SVG;
  • svgreader.cpp – файл вихідних кодів парсера SVG;
  • mainwindow.h - заголовний файл головного вікна програми;
  • mainwindow.cpp - файл вихідних кодів головного вікна програми;
  • mainwindow.ui - файл форми головного вікна програми;
  • main.cpp – стартовий файл вихідних кодів програми.

Структура SVG файла

Оскільки нам потрібно парсить цей файл, то заглянемо в його нутрощі.

<?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>

Отже, нас цікавлять теги svg, g, rect. У тезі svg містяться розміри графічної сцени - це *viewBox. * , у який обернутий тег rect містяться кольори заливки та абрису прямокутника, а також товщина абрису. Їх і треба буде спарити.

mainwindow.ui

У цьому файлі буде додана тільки кнопка load, по сигналу від якої відкриємо діалог вибору файлу та запустимо відкриття нашого файлу SVG.

SVGExample.pro

Звертаю вашу увагу на те, що у профайлі проекту потрібно буде підключити модуль xml.

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;    // Объявим в стеке список прямоугольников

    QDomDocument doc;       // объект документа
    QFile file(filename);   // Открываем наш SVG-файл
    // Если он не открылся или не удалось передать содержимое в QDocDocument
    if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
        return rectList;    // то возвратим список, но пустой

    // Ищем в документе все объекты с тегом g
    QDomNodeList gList = doc.elementsByTagName("g");
    // Начинаем их перебирать
    for (int i = 0; i < gList.size(); i++) {
        QDomNode gNode = gList.item(i);     // Выделяем из списка ноду
        QDomElement rectangle = gNode.firstChildElement("rect");    // И ищем в ней элемент c тегом rect
        // Если полученный элементы не нулевой, то
        if (rectangle.isNull()){
            continue;
        } else {
            // начинаем формировать прямоугольник
            QGraphicsRectItem *rect = new QGraphicsRectItem();
            // Этот флаг делает объект перемещаемым, потребуется для проверки
            rect->setFlag(QGraphicsItem::ItemIsMovable);
            // Забираем размеры из тега rect
            QDomElement gElement = gNode.toElement();
            rect->setRect(rectangle.attribute("x").toInt(),
                          rectangle.attribute("y").toInt(),
                          rectangle.attribute("width").toInt(),
                          rectangle.attribute("height").toInt());

            /* Забираем из элемента ноды gNode параметры цветов
             * да да да... именно из gNode, а не из rectangle. Эти параметры храняться в теге 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;       // инициализируем в стеке объект QDomDocument
    QFile file(filename);   // Открываем наш SVG-файл
    // Если он не открылся или не удалось передать содержимое в QDocDocument
    if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
        return QRectF(0,0,200,200); // то возвратим значения для сцены по умолчанию

    /* Далее забираем список элементов с тегом svg.
     * В случае, если список элементов будет не пустой,
     * то заберём размеры графической сцены.
     * */
    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;           // Путь сохранения файла
};

#endif // MAINWINDOW_H

mainwindow.cpp

Наведу в цьому файлі тільки вміст, що стосується безпосередньо SVG-файлу. У слоті обробки натискання кнопки вибирається за допомогою діалогового вікна файл та розбирається на графічні об'єкти.

#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()
{
    // Код из предыдущего урока по работе с 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)); // Зададим размеры графической сцены

    // Установим на графическую сцену объекты, получив их с помощью метода getElements
    foreach (QGraphicsRectItem *item, SvgReader::getElements(path)) {
        QGraphicsRectItem *rect = item;
        scene->addItem(rect);
    }
}

Підсумок

В результаті ви зможете розібрати збережений SVG файл, щоб забрати з нього хоча б прямокутники. Якщо ви хочете забирати і всі інші об'єкти, то доведеться добряче попотіти і написати парсер для всіх інших об'єктів за аналогією з прямокутником. Єдине, що хочу відзначити, не намагайтеся за допомогою цього коду відкрити файл, створений спочатку в CorelDraw, справа в тому, що версії структури файлу SVG теж сильно відрізняються. І цей код призначений для парсингу файлу, який був створений у минулому уроці, а структура файлів, що генеруються пакетом CorelDraw дещо відрізняється і не буде прочитана повністю.

Докладніше ви можете з цим ознайомитись у відеоуроці. А проект, який об'єднав обидва уроки завантажити за посиланням: SvgExample

  1. Збереження об'єктів QGraphicsScene у файл векторної графіки SVG

Відеоурок

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

F
  • 12 серпня 2017 р. 08:24

Здравствуйте!

Назрел вопрос насчет данной темы.
Реализовал отрисовку и перемещение объектов на сцене по структуре урока https://evileg.com/post/86/
Но там я в MoveItem.cpp отрисовывал не с drawRect, а с drawEllipse
void MoveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setPen(Qt::black);
    painter->setBrush(Qt::cyan);
    //painter->drawRect(-30,-30,60,60);
    painter->drawEllipse(-30,-30,30,30);
    painter->drawEllipse(-25,-25,20,20);
    painter->drawEllipse(-20,-20,10,10);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}
Далее возвращал область также прямоугольную
QRectF MoveItem::boundingRect() const
{
    return QRectF (-30,-30,30,30);
}
После добавления нескольких объектов на сцену
также проделал процесс сохранения в *.svg. При этом создался файл, где тег rect отсутствует
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="176.389mm" height="176.389mm"
viewBox="0 0 500 500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"  version="1.2" baseProfile="tiny">
<title>SVG VKR</title>
<desc>File created by Fidan Gallyamov</desc>
<defs>
</defs>
<g fill="none" stroke="black" stroke-width="1" fill-rule="evenodd" stroke-linecap="square" stroke-linejoin="bevel" >

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" 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"
>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,416,71)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>

<g fill="#00ffff" fill-opacity="1" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,416,71)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M0,-15 C0,-6.71573 -6.71573,0 -15,0 C-23.2843,0 -30,-6.71573 -30,-15 C-30,-23.2843 -23.2843,-30 -15,-30 C-6.71573,-30 0,-23.2843 0,-15 "/>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M-5,-15 C-5,-9.47715 -9.47715,-5 -15,-5 C-20.5228,-5 -25,-9.47715 -25,-15 C-25,-20.5228 -20.5228,-25 -15,-25 C-9.47715,-25 -5,-20.5228 -5,-15 "/>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M-10,-15 C-10,-12.2386 -12.2386,-10 -15,-10 C-17.7614,-10 -20,-12.2386 -20,-15 C-20,-17.7614 -17.7614,-20 -15,-20 C-12.2386,-20 -10,-17.7614 -10,-15 "/>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,416,71)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,70,190)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>

<g fill="#00ffff" fill-opacity="1" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,70,190)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M0,-15 C0,-6.71573 -6.71573,0 -15,0 C-23.2843,0 -30,-6.71573 -30,-15 C-30,-23.2843 -23.2843,-30 -15,-30 C-6.71573,-30 0,-23.2843 0,-15 "/>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M-5,-15 C-5,-9.47715 -9.47715,-5 -15,-5 C-20.5228,-5 -25,-9.47715 -25,-15 C-25,-20.5228 -20.5228,-25 -15,-25 C-9.47715,-25 -5,-20.5228 -5,-15 "/>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M-10,-15 C-10,-12.2386 -12.2386,-10 -15,-10 C-17.7614,-10 -20,-12.2386 -20,-15 C-20,-17.7614 -17.7614,-20 -15,-20 C-12.2386,-20 -10,-17.7614 -10,-15 "/>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,70,190)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,319,236)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>

<g fill="#00ffff" fill-opacity="1" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,319,236)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M0,-15 C0,-6.71573 -6.71573,0 -15,0 C-23.2843,0 -30,-6.71573 -30,-15 C-30,-23.2843 -23.2843,-30 -15,-30 C-6.71573,-30 0,-23.2843 0,-15 "/>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M-5,-15 C-5,-9.47715 -9.47715,-5 -15,-5 C-20.5228,-5 -25,-9.47715 -25,-15 C-25,-20.5228 -20.5228,-25 -15,-25 C-9.47715,-25 -5,-20.5228 -5,-15 "/>
<path vector-effect="non-scaling-stroke" fill-rule="evenodd" d="M-10,-15 C-10,-12.2386 -12.2386,-10 -15,-10 C-17.7614,-10 -20,-12.2386 -20,-15 C-20,-17.7614 -17.7614,-20 -15,-20 C-12.2386,-20 -10,-17.7614 -10,-15 "/>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,319,236)"
font-family="MS Shell Dlg 2" font-size="8.25" font-weight="400" font-style="normal"
>
</g>

<g fill="none" stroke="#000000" stroke-opacity="1" stroke-width="1" 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"
>
</g>
</g>
</svg>
Сразу бросается в глаза отличие
<path vector-effect="non-scaling-stroke">
У вас там просто none
 
Не подскажите как пропарсить данный файл???
Заранее спасибо)).
 
 
 
Evgenii Legotckoi
  • 13 серпня 2017 р. 03:56

Там в коде  у меня есть:

gNode.firstChildElement("rect"); 
Вам же стоит использовать просто path в данном случае.
gNode.firstChildElement("path"); 
Аттрибуты забирать аналогично, как они забираются из rect в моём коде. Делайте по аналогии, при возникновении некоторых проблем используйте qDebug() что понять, что идёт не так.
F
  • 13 серпня 2017 р. 16:11

Для формирования задал объект QGraphiscPathItem

QGraphicsPathItem *rect = new QGraphicsPathItem();
rect->setFlag(QGraphicsRectItem::ItemIsMovable);
QDomElement gElement = gNode.toElement();
rect->setPath();
у тега path есть атрибут "d". Пытаюсь считать этот атрибут с помощью setPath, который требует параметры типа QPainterPath
Как передать методу данные параметры в требуемом типе и правильно ли я сделал воспользовавшись QGraphicsPathItem?
F
  • 13 серпня 2017 р. 16:22

А кажется понял, я должен из атрибутов path сформировать заново элементы Ellipse, просто нужно правильно подобрать эти атрибуты.....


Evgenii Legotckoi
  • 15 серпня 2017 р. 05:04

Ну да. Там должны быть координаты, их нужно пропарсить и по ним построить Path, либо преобразовать их в эллипс. Вообще, кое-что кривовато переносится в SVG местами.

c
  • 15 жовтня 2017 р. 10:27

How can I open another polygon type such as circle(ellipse) ?

Evgenii Legotckoi
  • 15 жовтня 2017 р. 14:52

The principle will be similar. You need to research content of svg file and make parsing of needed tag.

For Example:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="210mm"
   height="297mm"
   viewBox="0 0 744.09448819 1052.3622047"
   id="svg2"
   version="1.1"
   inkscape:version="0.91 r13725"
   sodipodi:docname="circle.svg">
  <defs
     id="defs4" />
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="0.49497475"
     inkscape:cx="405.75379"
     inkscape:cy="583.59967"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1366"
     inkscape:window-height="703"
     inkscape:window-x="0"
     inkscape:window-y="0"
     inkscape:window-maximized="1" />
  <metadata
     id="metadata7">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <rect
       style="fill:#0000ff;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="rect3336"
       width="222.23357"
       height="131.31982"
       x="125.25892"
       y="219.99651" />
    <ellipse
       style="fill:#ff0000;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
       id="path3338"
       cx="287.89346"
       cy="466.47372"
       rx="89.90358"
       ry="74.751289" />
  </g>
</svg>
In this code You can try to get ellipse.
Method for parsing will be same.
QList<QGraphicsEllipseItem*> SvgReader::getEllipses(const QString filename)
{
    QList<QGraphicsEllipseItem *> ellipsesList;

    QDomDocument doc;
    QFile file(filename);

    if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
        return ellipsesList;

    QDomNodeList gList = doc.elementsByTagName("g");
    for (int i = 0; i < gList.size(); i++) {
        QDomNode gNode = gList.item(i);
        QDomElement ellipseElement = gNode.firstChildElement("ellipse");

        if (ellipseElement.isNull()){
            continue;
        } else {
            QGraphicsEllipseItem *ellipseItem = new QGraphicsEllipseItem();
            ellipseItem->setFlag(QGraphicsItem::ItemIsMovable);

            QDomElement gElement = gNode.toElement();
            ellipseItem->setRect(ellipseElement.attribute("cx").toFloat() - ellipseElement.attribute("rx").toFloat(),
                                 ellipseElement.attribute("cy").toFloat() - ellipseElement.attribute("ry").toFloat(),
                                 ellipseElement.attribute("rx").toFloat() * 2,
                                 ellipseElement.attribute("ry").toFloat() * 2);

            QColor fillColor(ellipseElement.attribute("style").split(";").at(0).split(":").at(1));
            ellipseItem->setBrush(QBrush(fillColor));

            QColor strokeColor(gElement.attribute("stroke", "#000000"));
            strokeColor.setAlphaF(gElement.attribute("stroke-opacity").toFloat());

            ellipseItem->setPen(QPen(strokeColor,gElement.attribute("stroke-width", "0").toInt()));
            ellipsesList.append(ellipseItem);
        }
    }
    file.close();
    return ellipsesList;
}
c
  • 16 жовтня 2017 р. 09:53

Thank You sir, So how can I change this method


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);
}

which class I need to use instead of QRectF
Evgenii Legotckoi
  • 16 жовтня 2017 р. 11:25

For what You want to use another class instead of QRectF?

This static method return just size of QGraphicsScene from svg file. QRectF should be enough.
c
  • 16 жовтня 2017 р. 16:09

Sir,I tried your code for open ellipse item.but my program not open ellipse item.what should I need to do?


here is my code :

readsvg.cpp

QList<QGraphicsEllipseItem*> ReadSVG::getEllipses(const QString filename)
{
    QList<QGraphicsEllipseItem *> ellipsesList;

    QDomDocument doc;
    QFile file(filename);

    if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
        return ellipsesList;

    QDomNodeList gList = doc.elementsByTagName("g");
    for (int i = 0; i < gList.size(); i++) {
        QDomNode gNode = gList.item(i);
        QDomElement ellipseElement = gNode.firstChildElement("ellipse");

        if (ellipseElement.isNull()){
            continue;
        } else {
            QGraphicsEllipseItem *ellipseItem = new QGraphicsEllipseItem();
            ellipseItem->setFlag(QGraphicsItem::ItemIsMovable);

            QDomElement gElement = gNode.toElement();
            ellipseItem->setRect(ellipseElement.attribute("cx").toFloat() - ellipseElement.attribute("rx").toFloat(),
                                 ellipseElement.attribute("cy").toFloat() - ellipseElement.attribute("ry").toFloat(),
                                 ellipseElement.attribute("rx").toFloat() * 2,
                                 ellipseElement.attribute("ry").toFloat() * 2);

            QColor fillColor(ellipseElement.attribute("style").split(";").at(0).split(":").at(1));
            ellipseItem->setBrush(QBrush(fillColor));

            QColor strokeColor(gElement.attribute("stroke", "#000000"));
            strokeColor.setAlphaF(gElement.attribute("stroke-opacity").toFloat());

            ellipseItem->setPen(QPen(strokeColor,gElement.attribute("stroke-width", "0").toInt()));
            ellipsesList.append(ellipseItem);
        }
    }
    file.close();
    return ellipsesList;
}


QRectF ReadSVG::getSizes(const QString filename)
{
    QDomDocument doc;       // initialize the QDomDocument object on the stack
    QFile file(filename);   // Open our SVG file
    // If it did not open or could not transfer content to QDocDocument
    if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
        return QRectF(0,0,200,200); // then return the values ​​for the default scene
    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);
}
widget.cpp

void Widget::on_btnOpen_clicked()
{
    QString newPath = QFileDialog::getOpenFileName(this, trUtf8("Open SVG"),
                                                   path, tr("SVG files (*.svg)"));
    if (newPath.isEmpty())
        return;

    path = newPath;
    scene->clear();

    scene->setSceneRect(ReadSVG::getSizes(path));
    foreach (QGraphicsEllipseItem *itemE, ReadSVG::getEllipses(path)) {
        QGraphicsEllipseItem *elips = itemE;
        scene->addItem(elips);
    }


}
Evgenii Legotckoi
  • 17 жовтня 2017 р. 01:44

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.

Do You want just open SVG file or make special graphics object (from QGraphicsItem etc.), which you will change it on QGraphicsScene?
If You want just open SVG file without changes, You can use QSvgWidget for it.
Otherwise, I suggest You create topic on forum of this site , where You can attach svg file, and we continue discuss about this issue.
c
  • 17 жовтня 2017 р. 05:29

Sir I post is as a topic,please help me to solve this problem

Михаиллл
  • 10 червня 2019 р. 11:43
  • (відредаговано)

Скажите пожалуйста, как пользоваться QSvgRenderer и загружать целиком в QGraphicsScene ?
Если делаю так, то получаю белый экран:

    QString newPath = QFileDialog::getOpenFileName(this, trUtf8("Open SVG"),
                                                   path, tr("SVG files (*.svg)"));

    if (newPath.isEmpty())
            return;

        path = newPath;
        scene->clear();

        QSvgRenderer w;
        w.load(path);
        scene->setSceneRect(w.viewBoxF());

А если делаю с помощью вашего класса, то тоже получаю белый экрак.
Рисую на сцене так: Qt/C++ - Урок 021. Рисование мышью в Qt

Михаиллл
  • 11 червня 2019 р. 02:41

Вот так целиком добавлять можно

    QString newPath = QFileDialog::getOpenFileName(this, trUtf8("Open SVG"),
                                                   path, tr("SVG files (*.svg)"));

    if (newPath.isEmpty())
            return;

        path = newPath;
        scene->clear();

        //QSvgRenderer myRenderer;
        QSvgRenderer* myRenderer = new QSvgRenderer();
        myRenderer->load(path);
        //scene->setSceneRect(myRenderer->viewBoxF());
        QGraphicsSvgItem *myItem = new QGraphicsSvgItem();
        myItem->setSharedRenderer(myRenderer);
        scene->addItem(myItem);

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
г
  • ги
  • 24 квітня 2024 р. 03:51

C++ - Тест 005. Структуры и Классы

  • Результат:41бали,
  • Рейтинг балів-8
l
  • laei
  • 23 квітня 2024 р. 21:19

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:10бали,
  • Рейтинг балів-10
l
  • laei
  • 23 квітня 2024 р. 21:17

C++ - Тест 003. Условия и циклы

  • Результат:50бали,
  • Рейтинг балів-4
Останні коментарі
k
kmssr09 лютого 2024 р. 07:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 14:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 23:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 21:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 грудня 2023 р. 10:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
G
Gar22 квітня 2024 р. 17:46
Clipboard Как скопировать окно целиком в clipb?
DA
Dr Gangil Academics20 квітня 2024 р. 19:45
Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
a
a_vlasov14 квітня 2024 р. 18:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 квітня 2024 р. 14:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex04 квітня 2024 р. 16:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Слідкуйте за нами в соціальних мережах