如何在Python中显示SVG图像。

11
我正在按照 这个教程 编写一个Python象棋程序。
它使用了python-chess引擎。该引擎的函数显然返回SVG数据,可用于显示棋盘。
  • 教程中的代码:
import chess
import chess.svg

from IPython.display import SVG

board = chess.Board()
SVG(chess.svg.board(board=board,size=400))  

但是当我运行那段代码时,我只在终端上看到一行文字,没有图片。

<IPython.core.display.SVG object>

该教程提到了Jupyter Notebooks以及如何使用它们来显示SVG图像。我对Jupyter Notebooks没有经验,尽管我已经从pip安装了该软件包,并尝试了一些如何使用它的方法,但在解决我的原始棋盘问题方面并没有取得太大进展。但是我有使用C++进行Qt开发的经验,因为Qt有Python绑定,所以我决定使用这些绑定。
以下是我写的内容:
import sys
import chess
import chess.svg
from PyQt5 import QtGui, QtSvg
from PyQt5.QtWidgets import QApplication
from IPython.display import SVG, display

app = QApplication(sys.argv);

board = chess.Board(); 
svgWidget = QtSvg.QSvgWidget(chess.svg.board(board=board, size=400));
#svgWidget.setGeometry(50,50,759,668)
svgWidget.show()

sys.exit(app.exec_())


一个Qt窗口打开但是什么也没有显示,终端上却有很多文本——(显然SVG数据出现在控制台,而不是正在打开的Qt窗口中?)我想我需要安装一些python下的SVG库,所以我从pip安装了drawSvg。但是这个库似乎只生成SVG图片,对我没有用处。更奇怪的是,在看到this SO question后,我尝试了以下操作:
import sys
import chess
import chess.svg
from PyQt5 import QtGui, QtSvg
from PyQt5.QtWidgets import QApplication
from IPython.display import SVG, display

app = QApplication(sys.argv);

board = chess.Board(); 
svgWidget = QtSvg.QSvgWidget('d:\projects\python_chess\Zeichen_123.svg');
#svgWidget.setGeometry(50,50,759,668)
svgWidget.show()

sys.exit(app.exec_())

我看到了一张图片 - 一张SVG图片!那么我的情况和这种情况有什么区别呢?

问题:所以我的问题是,在国际象棋棋盘SVG数据的情况下,我做错了什么? Python-chess库生成的SVG数据与QtSvg不兼容吗?

2个回答

8

我认为你对Python脚本语言的特性感到困惑。你说自己有使用C++下的Qt开发经验,那么在那里你是否会先创建一个主窗口小部件,然后在其中添加SVG小部件,并在其中调用或加载SVG数据呢?

我会将你的代码重写成以下形式。

import chess
import chess.svg

from PyQt5.QtSvg import QSvgWidget
from PyQt5.QtWidgets import QApplication, QWidget


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 1100, 1100)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 1080, 1080)

        self.chessboard = chess.Board()

        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

编辑

如果您将一个绘图函数添加到MainWindow类中,那么将更好。因为在未来,每当移动棋子时,您肯定会多次重绘棋盘图片。所以我会做这样的事情。

     def paintEvent(self, event):
         self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
         self.widgetSvg.load(self.chessboardSvg) 

谢谢您的快速回复。好的,我明白了关于创建主父部件的事情。但是由于某些原因,这似乎仍然无法正常工作。 - Duck Dodgers
好的,我现在编辑了我的回答。再试一次,并且现在指定编码。 - SmartKittie
是的,这解决了我的问题。现在我可以看到棋盘了。但我现在只有一个疑问。我如何显示SVG图像“Zeichen_123.svg”,而不是棋盘? - Duck Dodgers
1
有点晚了,但问题在于QSvgWidget构造函数需要一个文件名,因此当您给它Zeichen_123.svg的路径时,它将显示该文件。相反,chess.svg.board的返回值是实际的SVG代码(即文件内容),因此QSvgWidget不知道该怎么处理它。另一方面,load方法期望接收SVG数据,而不是文件名,因此可以使用它。(实际上,这与使用或不使用“主窗口”的问题有些无关;您不需要MainWindow类来显示国际象棋SVG。) - Ed Bennett
感谢 @EdBennett 的澄清! - undefined

2

这是我用Python显示SVG图像的方法,无需使用第三方工具。

首先将SVG图像保存在硬盘上, 然后只需要像这样调用:os.Startfile("exemple.svg")

例如:

boardsvg = svg.board(board(fen), size=600, coordinates=True)
   with open('temp.svg', 'w') as outputfile:
     outputfile.write(boardsvg)
   time.sleep(0.1)
   os.startfile('temp.svg')

这就是它!

但是,这并不会使用Python显示SVG - 这将使用与每个特定系统上的.svg文件扩展名相关联的任何应用程序来显示SVG,这使得程序的行为高度不确定,并且更加依赖第三方软件:在一台计算机上它可能在浏览器中打开,在另一台计算机上可能在矢量编辑器中打开,在第三台计算机上可能根本无法工作。 - Ronald McFüglethorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接