JAN
3
2011

Rendering UI files to SVG

In response to a question on IRC yesterday, here's a quick example for the New
Year - rendering designer's UI files to SVG using QSvgGenerator. As usual, the
code is simple since Qt gives us everything we need.

The main program loads the UI file shows it, it also sets up our SVG
capture. Loading the UI file is done using QUiLoader allowing us to load any
file specified on the command line. We then figure out what to call the SVG
file we're going to generate. Next we setup our Renderer object by telling it
what to capture and the name of the file to write it to. In order to ensure
the UI is ready, we use a single shot timer to trigger the capture one second
after the application starts:

int main( int argc, char **argv )
{
    QApplication app( argc, argv );

    QString filename = QString::fromLocal8Bit( argv[1] );
    QUiLoader loader;
    QFile f( filename );
    if ( !f.open(QIODevice::ReadOnly) )
	return 1;

    QWidget *ui = loader.load( &f );
    if ( !ui )
	return 1;

    QString svgFile = filename.remove(".ui");
    svgFile = svgFile.append(".svg");
    
    Renderer render;
    render.setTarget(ui);
    render.setSvgFile(svgFile);
    QTimer::singleShot( 1000, &render, SLOT(start()));

    ui->show();
    app.exec();
}

The implementation of the actual capture is simple too, and is all handled by
a single method 'renderToSvg()'. This method creates the generator and tells
it the filename to use. Then it creates a QPainter and sets up drawing onto
the QSvgGenerator - this is possible because QSvgGenerator is a QPaintDevice
(like QWidget, QImage etc.). Finally we call the render() method of the widget
we're capturing in order to perform the actual drawing.

bool Renderer::renderToSvg()
{
    if (svgFile.isEmpty()) {
        qDebug() << "No svg file set";
        return false;
    }

    QSvgGenerator svg;
    svg.setFileName(svgFile);
    QPainter p;
    p.begin(&svg);
    target->render(&p);
    p.end();
    
    return true;
}

The result of running this on a simple UI file can be seen at http://xmelegance.org/devel/networkrequests.svg.
The code itself is available from my gitorious qt-examples repository as normal.

When I first wrote the above code, I tried to get the widget to render
directly to the svg file, but this turned out to hit QTBUG-2278. The code
that triggers the bug was:

    QSvgGenerator svg;
    svg.setFileName(svgFile);
    target->render(&svg);

So if I were you, I'd create the painter myself!