I would like to render SVG files with PyQt5.
The simplest way to do that is to use QSvgGenerator applied on a QPainter object.
However, for some reason I have to render text in the output SVG file. To do that, having a QApplication running is compulsory because some components initialized during the execution of QApplication are needed. Otherwise, QPainter.drawText()
methods end in a SEGFAULT.
I'm now able to generate text in my SVG file by creating a QSvgWidget object with handles the painting through the paintEvent
method.
If I just run the application with the exec_
method, everything works fine. However I'm only interested in generating the SVG, so I don't want to be forced to close the main window with my mouse (I'd like to run my program on a headless server). Here is my base code:
app = QApplication(sys.argv)
drawer = MyDrawerClass()
drawer.show()
app.exec_()
and MyDrawerClass
inheritates from QSvgWidget
and implements printEvent
method which is successfully called when executing the app.
So my question is: Is there a way to run the app a headless way and quit it after everything is rendered? I read a few things on QTimer
but I can't find any example which suits my usage.
I assume you're referring to the approach used in your previous question.
Some painter capabilities require that a QGuiApplication is constructed before using them, and drawing text is amongst them, since it depends on the system's own GUI management (default fonts, DPI, etc). Usually one would use a standard QApplication, but, as reported in the documentation:
For "non-QWidget based Qt applications, use QGuiApplication instead, as it does not depend on the QtWidgets library".
This will make the creation of a QGuiApplication faster and lighter.
Unfortunately, a running display is mandatory for Q[Gui]Applications, so you will not be able to run it on a headless server, unless at least a minimal virtual X server is active. If you can manage to do that, the following example should work fine.
def createImage(width=400, height=400):
rect = QRect(0, 0, width, height)
generator = QSvgGenerator()
generator.setFileName("test.svg")
generator.setSize(rect.size())
generator.setViewBox(rect)
painter = QPainter(generator)
painter.fillRect(rect, Qt.black)
textRect = QRect(0, 0, 200, 200)
textRect.moveCenter(rect.center())
painter.setPen(Qt.white)
painter.setBrush(Qt.darkGray)
painter.drawRect(textRect)
painter.drawText(textRect, Qt.AlignCenter, 'test')
painter.end()
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
createImage()
Since there's no need for an event loop (because there's no GUI interaction), you don't have to actually exec_()
, and the program will automatically exit as soon as the paint function is returned.