Currently I am working on a program, to display SIP-Trace log files. It is written in Python 3.7 using the PyQt 5(.11.3) module to load and operate a GUI made in QDesigner. As a main feature it parses the SIP-Trace file and displays it as a sequence diagram to a QGraphicsScene with QGraphicsObjects.
My problem lies in the following: For later reference, the content of the QGraphicsScene should be saved as an image file, like .jpg or .png. In the Qt/PyQt documentation I found the useful sounding command QGraphicsScene.render() which renders the content of the GraphicsScene to a saveable file like QImage using QPainter. In the last days, I tried a couple of ways/sample codes found here and elsewhere, but cannot render the GraphicsScene to the QImage much less to an image file. Since I am rather new to Python and Qt, I think I am missing some basic setting somewhere. Following is a minimal version of my code.
# -*- coding: utf8 -*-
"""Class for getting a sequence diagram of a sip traffic"""
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class VoipGui(QMainWindow):
""" Class that handles the interaction with the UI """
def __init__(self, parent=None):
super().__init__(parent)
self.ui = uic.loadUi("main_window.ui", self)
self.showMaximized()
self.sequence_scene = QGraphicsScene()
self.ui.graphicsView.setScene(self.sequence_scene)
# self.sequence_scene.setSceneRect(0, 0, 990, 2048)
# sets the spacing between nodes
# For more than three nodes columns should be generated in a more automatic way
self.left_column = 51
self.middle_column = 381
self.right_column = 711
self.flow_height = 60 # Sets the spacing between the arrows in the flowchart
# --------------------------------- /class init and var set -------------------------------------------
self.actionOpenFile.triggered.connect(self.on_open_file)
self.actionCloseFile.triggered.connect(self.on_close_file)
self.actionCloseProgram.triggered.connect(self.close)
self.actionSaveFile.triggered.connect(self.save_seq_image)
# --------------------------------- /connecting slots and signals ----------------------------
def on_open_file(self):
"""Dummy version of the open file dialog"""
self.draw_node(self.left_column, 5, "192.168.2.1", 10)
self.draw_node(self.middle_column, 5, "192.168.2.22", 10)
def on_close_file(self):
self.ui.textBrowser.clear()
self.sequence_scene.clear()
def save_seq_image(self):
""" Here lies the problem: Save the rendered sequence scene to file for later use"""
rect_f = self.sequence_scene.sceneRect()
# rect = self.sequence_scene.sceneRect().toRect()
# img = QPixmap(rect.size())
img = QImage()
p = QPainter()
# p.setPen(QColor(255, 255, 255))
# p.setViewport(rect)
painting = p.begin(img)
self.sequence_scene.render(p, target=QRectF(img.rect()), source=rect_f)
p.end()
if painting:
print("Painter init pass")
elif not painting:
print("Painter init fail")
saving = img.save("save.jpg")
if saving:
print("Saving Pass")
elif not saving:
print("Saving Not Pass")
def draw_node(self, x_pos, y_pos, ip_address, y_stops):
"""Participating devices are displayed as these nodes"""
width = 100.0
height = 40.0
pc_box = QGraphicsRectItem(x_pos - 50, y_pos, width, height)
self.sequence_scene.addItem(pc_box)
pc_ip = QGraphicsTextItem("%s" % ip_address)
pc_ip.setPos(x_pos - 50, y_pos)
self.sequence_scene.addItem(pc_ip)
node_line = QGraphicsLineItem(x_pos, y_pos + 40, x_pos, y_pos + (y_stops * self.flow_height))
self.sequence_scene.addItem(node_line)
def show_window():
app = QApplication(sys.argv)
dialog = VoipGui()
dialog.show()
sys.exit(app.exec_())
if __name__ == "__main__":
show_window()
The problem is simple, in render()
you are indicating that the size of the target is equal to that of QImage
, and how size is QImage?, how are you using QImage()
the size is QSize(0, 0)
so it can not be generated the image, the solution is to create a QImage
with a size:
def save_seq_image(self):
""" Here lies the problem: Save the rendered sequence scene to file for later use"""
rect_f = self.sequence_scene.sceneRect()
img = QImage(QSize(640, 480), QImage.Format_RGB888)
img.fill(Qt.white)
p = QPainter(img)
self.sequence_scene.render(p, target=QRectF(img.rect()), source=rect_f)
p.end()
saving = img.save("save.jpg")
print("Saving Pass" if saving else "Saving Not Pass")
Output: