c
cordsac17 октября 2017 г. 5:26

How can I open SVG file through QT

I'm trying to develop flowchart diagram application using QT with C++. I'm planing to design basic shapes of flowchart, such as rectangle, ellipse,polygon and line item(arrow).In this code I designed rectangle and ellipse items and content of the QGraphicView saved properly.But problem is I can't open .SVG file properly. Program open rectangle shapes only. How can I open other shapes?  such as  ellipse,polygon and line item(arrow).


I'm new to this QT with C++ application  development.So please help me to solve this problem.here with I attach sample .SVG file.

ReadSvg.cpp

#include "readsvg.h"
#include <QPen>
#include <QFile>
#include <QMessageBox>
#include <QDomDocument>
#include <QStringList>

ReadSVG::ReadSVG()
{

}

QList<QGraphicsRectItem *> ReadSVG::getElements(const QString filename)
{
    QList<QGraphicsRectItem *> rectList;    // We declare in the stack a list of rectangles

    QDomDocument doc;       // document object
    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 rectList;    // then return the list, but empty

    // Look in the document for all objects with the tag g
    QDomNodeList gList = doc.elementsByTagName("g");
    // We start to sort them out
    for (int i = 0; i < gList.size(); i++) {
        QDomNode gNode = gList.item(i);     // Select the node from the list
        QDomElement rectangle = gNode.firstChildElement("rect");    // And we search in it for an element with the tag rect

        // If the resulting elements are not zero, then
        if (rectangle.isNull()){
            continue;
        } else {
            // begin to form a rectangle
            QGraphicsRectItem *rect = new QGraphicsRectItem();
            // This flag makes the object moveable, it will be required for verification
            rect->setFlag(QGraphicsItem::ItemIsMovable);
            // We take sizes from the rect tag
            QDomElement gElement = gNode.toElement();
            rect->setRect(rectangle.attribute("x").toInt(),
                          rectangle.attribute("y").toInt(),
                          rectangle.attribute("width").toInt(),
                          rectangle.attribute("height").toInt());

            /*
               We take the parameters of the colors gNode from the node element
               yes yes yes ... it's from gNode, not from rectangle. These parameters are stored in the tag g
             */
            QColor fillColor(gElement.attribute("fill", "#ffffff"));    // fill color
            fillColor.setAlphaF(gElement.attribute("fill-opacity","0").toFloat());
            rect->setBrush(QBrush(fillColor));

            // as well as the color and thickness of the outline
            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);  // add a rectangle to the list
        }
    }
    file.close();
    return rectList;
}

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

#include "widget.h"
#include "ui_widget.h"
#include "readsvg.h"

#include <QCursor>
#include <QFileDialog>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);

    QBrush redBrush(Qt::red);
    QBrush blueBrush(Qt::blue);
    QPen blackPen(Qt::black);
    blackPen.setWidth(6);

    elipse = scene->addEllipse(10,10,100,100,blackPen,redBrush);
    rect = scene->addRect(-10,-10,100,100,blackPen,blueBrush);
    rect->setFlag(QGraphicsItem::ItemIsMovable, true);


}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    QString fileName= QFileDialog::getSaveFileName(this, "Save image", QCoreApplication::applicationDirPath(), "BMP Files (*.bmp);;JPEG (*.JPEG);;PNG (*.png)" );
        if (!fileName.isNull())
        {
            QPixmap pixMap = this->ui->graphicsView->grab();
            pixMap.save(fileName);
        }
}

void Widget::on_btnSave_clicked()
{
    // Заберём путь к файлу и его имененем, который будем создавать
    QString newPath = QFileDialog::getSaveFileName(this, trUtf8("Save SVG"),
        path, tr("SVG files (*.svg)"));

    if (newPath.isEmpty())
        return;

    path = newPath;

    QSvgGenerator generator;        // Создаём объект генератора файла
    generator.setFileName(path);    // Устанавливаем путь к файлу, куда будет сохраняться векторная графика
    generator.setSize(QSize(scene->width(), scene->height()));  // Устанавливаем размеры рабочей области документа в миллиметрах
    generator.setViewBox(QRect(0, 0, scene->width(), scene->height())); // Устанавливаем рабочую область в координатах
    generator.setTitle(trUtf8("SVG Example"));                          // Титульное название документа
    generator.setDescription(trUtf8("File created by SVG Example"));    // Описание документа

    // С помощью класса QPainter
    QPainter painter;
    painter.begin(&generator);  // Устанавливаем устройство/объект в котором будем производить отрисовку
    scene->render(&painter);    // Отрисовываем содержимое сцены с помощью painter в целевое устройство/объект
    painter.end();              // Заканчиваем отрисовку

    // По окончанию отрисовки получим векторный файл с содержимым графической сцены
}


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)); // Set the size of the graphic scene

    // Install the objects on the graphical scene, get them using the getElements
    /*foreach (QGraphicsRectItem *item, ReadSVG::getElements(path)) {
        QGraphicsRectItem *rect = item;
        scene->addItem(rect);
    }*/

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


}
sample.svg
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

6
Evgenii Legotckoi
  • 17 октября 2017 г. 6:01
  • Ответ был помечен как решение.

Hello.

Yes... This SVG file have another structure of tags.
Just see the following part of SVG via any text editor.
<g fill="#ff0000" fill-opacity="1" stroke="#000000" stroke-opacity="1" stroke-width="6" stroke-linecap="square" stroke-linejoin="bevel" transform="matrix(1,0,0,1,379,152)"
font-family="MS Shell Dlg 2" font-size="7.8" font-weight="400" font-style="normal" 
>
<circle cx="60" cy="60" r="50"/>
</g>
I wrote example for You for ellipse tag, because I had SVG file of another version (from Inkscape progam). But You have circle tag.

Therefore need to write some another code like this.
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("circle");

        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("r").toFloat(),
                                 ellipseElement.attribute("cy").toFloat() - ellipseElement.attribute("r").toFloat(),
                                 ellipseElement.attribute("r").toFloat() * 2,
                                 ellipseElement.attribute("r").toFloat() * 2);

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

            ellipseItem->setPen(QPen(strokeColor,gElement.attribute("stroke-width", "0").toInt()));
            ellipsesList.append(ellipseItem);
        }
    }
    file.close();
    return ellipsesList;
}
Check it, please.
I think it should work, but I haven`t opportunity to check this code now. If it will not work, just write about it, then I will check it after my job.
    c
    • 17 октября 2017 г. 6:57

    Thank you very much sir,my problem solved :) Is this the way to do for other ? I mean polygon,line shape(arrow line)

      Evgenii Legotckoi
      • 17 октября 2017 г. 7:20

      Yes. Just You need see xml structure of your svg file, tags for figures (polygon, paths, lines and so on) and realize same functions for all figures.

        c
        • 17 октября 2017 г. 7:42

        Okay sir :) I'll do so

          Evgenii Legotckoi
          • 17 октября 2017 г. 7:50
          • (ред.)

          Good luck.
          If You will need some another advice, do not hesitate to ask a new question on this forum.

            c
            • 17 октября 2017 г. 9:28

            Okay,Thank you sir :)

              Комментарии

              Только авторизованные пользователи могут публиковать комментарии.
              Пожалуйста, авторизуйтесь или зарегистрируйтесь
              г
              • ги
              • 23 апреля 2024 г. 22:51

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

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

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

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

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

              • Результат:50баллов,
              • Очки рейтинга-4
              Последние комментарии
              k
              kmssr9 февраля 2024 г. 2:43
              Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
              АК
              Анатолий Кононенко5 февраля 2024 г. 9:50
              Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
              EVA
              EVA25 декабря 2023 г. 18:30
              Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
              J
              JonnyJo25 декабря 2023 г. 16:38
              Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
              G
              Gvozdik19 декабря 2023 г. 5:01
              Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
              Сейчас обсуждают на форуме
              G
              Gar22 апреля 2024 г. 12:46
              Clipboard Как скопировать окно целиком в clipb?
              DA
              Dr Gangil Academics20 апреля 2024 г. 14: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 г. 13:41
              Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
              Павел Дорофеев
              Павел Дорофеев14 апреля 2024 г. 9:35
              QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
              f
              fastrex4 апреля 2024 г. 11:47
              Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

              Следите за нами в социальных сетях