PyQt 5:将 QGraphicsScene 渲染到 QImage 时 QPainter returns false

PyQt 5: QPainter returns false while rendering QGraphicsScene to a QImage

目前我正在开发一个程序,用于显示 SIP-Trace 日志文件。它是在 Python 3.7 中编写的,使用 PyQt 5(.11.3) 模块来加载和操作 QDesigner 中制作的 GUI。作为主要功能,它解析 SIP-Trace 文件并将其显示为带有 QGraphicsObjects 的 QGraphicsScene 的序列图。

我的问题在于:为了以后参考,QGraphicsScene的内容应该保存为图像文件,如.jpg或.png。在 Qt/PyQt 文档中,我找到了有用的声音命令 QGraphicsScene.render(),它使用 QPainter 将 GraphicsScene 的内容呈现为可保存的文件,如 QImage。在过去的几天里,我尝试了在这里和其他地方找到的几个 ways/sample 代码,但无法将 GraphicsScene 渲染到 QImage,更不用说渲染到图像文件了。由于我是 Python 和 Qt 的新手,我想我在某处缺少一些基本设置。以下是我的代码的最小版本。

# -*- 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()

问题很简单,在render()中你表示target的大小等于QImage,QImage的大小是多少?,你是怎么用的QImage() 大小是 QSize(0, 0) 所以不能生成图像,解决方法是创建一个 QImage 大小:

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")

输出: