Scalable Vector Graphics (SVG) is an XML-based language for describing two-dimensional vector graphics. Qt provides classes for saving vector shapes into an SVG file. This feature can be used to create a simple vector graphics editor similar to Adobe Illustrator and Inkscape.
In the next example, we will continue using the same project file from the previous example.
Let's learn how to create a simple program that displays SVG graphics on screen:
actionSave_as_SVG
in the Action Editor window at the bottom of the Qt Creator window. Right-click on the item and choose Go to slot… from the pop-up menu. A window will now appear, which carries a list of slots available for the particular action. Choose the default signal called triggered()
and click the OK button:on_actionSave_as_SVG_triggered()
has been automatically added to your main window class. At the bottom of your mainwindow.h
, you will see something like this:void MainWindow::on_actionSave_as_SVG_triggered() { }
The preceding function will be called when you clicked on the Save as SVG option from the menu bar. We will write our code within this function to save all the vector graphics into an SVG file.
QSvgGenerator
at the top of our source file. This header is very important as it's required for generating SVG files. Then, we also need to include another class header called QFileDialog
, which will be used to open the save dialog:#include <QtSvg/QSvgGenerator> #include <QFileDialog>
QT += core gui svg
paintAll()
within mainwindow.h
, like so:public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); virtual void paintEvent(QPaintEvent *event); void paintAll(QSvgGenerator *generator = 0);
mainwindow.cpp
, move all the code from paintEvent()
to the paintAll()
function. Then, replace all the individual QPainter
objects with a single, unified QPainter
for drawing all the graphics. Also, call the begin()
function before drawing anything and call the end()
function after finishing drawing. The code should look like this:void MainWindow::paintAll(QSvgGenerator *generator) { QPainter painter; if (engine) painter.begin(engine); else painter.begin(this); painter.setFont(QFont("Times", 14, QFont::Bold)); painter.drawText(QPoint(20, 30), "Testing"); painter.drawLine(QPoint(50, 60), QPoint(100, 100)); painter.setBrush(Qt::BDiagPattern); painter.drawRect(QRect(40, 120, 80, 30)); QPen ellipsePen; ellipsePen.setColor(Qt::red); ellipsePen.setStyle(Qt::DashDotLine); painter.setPen(ellipsePen); painter.drawEllipse(QPoint(80, 200), 50, 20); QPainterPath rectPath; rectPath.addRect(QRect(150, 20, 100, 50)); painter.setPen(QPen(Qt::red, 1, Qt::DashDotLine, Qt::FlatCap, Qt::MiterJoin)); painter.setBrush(Qt::yellow); painter.drawPath(rectPath); QPainterPath ellipsePath; ellipsePath.addEllipse(QPoint(200, 120), 50, 20); painter.setPen(QPen(QColor(79, 106, 25), 5, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); painter.setBrush(QColor(122, 163, 39)); painter.drawPath(ellipsePath); QImage image; image.load("tux.png"); painter.drawImage(QPoint(100, 150), image); painter.end(); }
paintEvent()
to paintAll()
, we shall now call the paintAll()
function inside paintEvent()
, like so:void MainWindow::paintEvent(QPaintEvent *event)
{
paintAll();
}
on_actionSave_as_SVG_triggered()
, which was generated by Qt. We start by calling the save file dialog and obtain the directory path with the desired file name from the user:void MainWindow::on_actionSave_as_SVG_triggered() { QString filePath = QFileDialog::getSaveFileName(this, "Save SVG", "", "SVG files (*.svg)"); if (filePath == "") return; }
QSvgGenerator
object and save the graphics to an SVG file by passing the QSvgGenerator
object to the paintAll()
function:void MainWindow::on_actionSave_as_SVG_triggered() { QString filePath = QFileDialog::getSaveFileName(this, "Save SVG", "", "SVG files (*.svg)"); if (filePath == "") return; QSvgGenerator generator; generator.setFileName(filePath); generator.setSize(QSize(this->width(), this->height())); generator.setViewBox(QRect(0, 0, this->width(), this->height())); generator.setTitle("SVG Example"); generator.setDescription("This SVG file is generated by Qt."); paintAll(&generator); }
By default, QPainter
will use the paint engine from its parent object to draw the graphics assigned to it. If you don't assign any parent to QPainter
, you can manually assign a paint engine to it, which is what we have done in this example.
The reason why we placed the code into paintAll()
is because we want to reuse the same code for two different purposes: for displaying the graphics on the window and exporting the graphics to an SVG file. Notice the default value of the generator
variable in the paintAll()
function is set to 0
, which means no QSvgGenerator
object is required to run the function unless specified. Later on, in the paintAll()
function, we check whether the generator
object exists. If it does exist, use it as the paint engine for the painter, like so:
if (engine)
painter.begin(engine);
else
painter.begin(this);
Otherwise, pass the main window to the begin()
function (since we're writing the code in mainwindow.cpp
, we can directly use this
to refer to main window's pointer) so that it will use the paint engine of the main window itself, which means the graphics will be drawn onto the surface of the main window.
In this example, it's required to use a single QPainter
object to save the graphics into the SVG file. If you use multiple QPainter
objects, the resulting SVG file will contain multiple XML header definitions and thus the file will be deemed to be invalid by any graphics editor software out there.
QFileDialog::getSaveFileName()
will open up the native save file dialog for the user to choose the save directory and set a desired file name. Once the user is done with that, the full path will be returned as a string and we will be able to pass that information to the QSvgGenerator
object to export the graphics.
Notice that in the previous screenshot, the penguin in the SVG file has been cropped. This is because the canvas size of the SVG was set to follow the size of the main window. To help the poor penguin getting its body back, scale the window bigger before exporting the SVG file.
Scalable Vector Graphics (SVG) defines the graphics in XML format. Since it is vector graphics, SVG graphics do not lose any quality if they are zoomed or resized.
SVG allows three types of graphic object: vector graphics, raster graphics, and text. Graphical objects, including PNG and JPEG raster images, can be grouped, styled, transformed, and composited into previously rendered objects.
You can check out the full specification of SVG graphics at https://www.w3.org/TR/SVG.
3.145.17.18