Inkscape 1.0 插件(4) 使用QT界面输入参数修改路径,让插件更强大

上一节里说过把解释器调整到默认的python3.8.3后可以做很多事, 本文就演示一下在Inkscape插件里如何使用Qt做输入界面, 并用全局变量方式传递参数, 实现修改svg的目的. 关于如何在python里使用QT做界面, 网上有很多教程, 这里不详细说, 我安装Qt Designer遇到的一点小问题可以参阅另一篇文章. https://blog.csdn.net/majian/article/details/106792573 , 总之这个方法使用的前提是安好Qt Designer,  python能运行pytqt5 , 我用vscode编辑.

首先在Qt Designer里设计一个如图的界面保存, 在vscode里打开这个ui文件, 转换为py文件(在vscode里安装  PYQT Integration 插件),  我直接贴出转换后的py文件, 没装PYQT或者Qt Designer启动不成功的同学直接用这个py文件也可以 .

PYQT

文件名: Ui_InkQtDemo.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'd:\Inkscape\share\inkscape\extensions\MyExtension\InkQtDemo.ui'


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(258, 178)
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setGeometry(QtCore.QRect(80, 70, 41, 31))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(Form)
        self.lineEdit_2.setGeometry(QtCore.QRect(150, 70, 51, 31))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(10, 80, 72, 15))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(130, 70, 31, 21))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(Form)
        self.label_3.setGeometry(QtCore.QRect(20, 10, 331, 31))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(Form)
        self.label_4.setGeometry(QtCore.QRect(20, 40, 191, 16))
        self.label_4.setObjectName("label_4")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(80, 120, 101, 41))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.lineEdit.setText(_translate("Form", "0"))
        self.lineEdit_2.setText(_translate("Form", "0"))
        self.label.setText(_translate("Form", "请输入 X"))
        self.label_2.setText(_translate("Form", "Y"))
        self.label_3.setText(_translate("Form", "这是QT界面输入参数演示"))
        self.label_4.setText(_translate("Form", "XY值决定path显示位置"))
        self.pushButton.setText(_translate("Form", "PushButton"))

第二步, 在Python里把这个界面运行起来, 我的主程序 MyQtDemo.py

#!/usr/bin/env python
# coding=utf-8

import sys

# Qt所需
from PyQt5.QtWidgets import *
# #这个是ui文件对应的py文件的文件名
from  Ui_InkQtDemo  import Ui_Form

#我的Form是用的QWidget作为基类
class MyWindow(QWidget,Ui_Form):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.OnClick_pushButton)    #设置按钮和事件的连接
    def OnClick_pushButton(self):
        self.close()   #点击后关闭窗口

if __name__ == '__main__':
    app=QApplication(sys.argv)
    w=MyWindow()
    w.show()
    sys.exit(app.exec_())

先试运行这个py程序, 正常情况下会弹出 QtDesigner里设计的那个窗口. 成功后再添加几行代码把输入值保存到一个全局变量InputXY里.

    def OnClick_pushButton(self):
        x =  self.lineEdit.text() 
        y =  self.lineEdit_2.text() 
        global inputXY
        inputXY={"x":x, "y":y }     # 用字典的方式把输入值保存到全局变量

以上的步骤均可以在python里直接调试, 不用打开Inkspace. 这是我想提高效率的地方, 不涉及到图层元素操作的算法,设置类代码就不用self.msg, 那个效率太低.   好了, 现在可以加入 Inkex代码了. 加入一个Inkex类,

class MyExtension(inkex.EffectExtension):
    def effect(self):
        global inputXY
        x = inputXY["x"]
        y = inputXY["y"]

直接运行编译不成功, 提示:     class MyExtension(inkex.EffectExtension):  NameError: name 'inkex' is not defined

没有 import 当然不行, 添加两行 import:  

import inkex

from inkex.elements import Group, PathElement

这回错误提示变成 :   ModuleNotFoundError: No module named 'inkex'  , 找不到模块, 这是因为默认python环境里没有inkex的查找路径,  所以在 import inkex前面 添加一行把搜索路径加入进去 (注意修改为你自己的Inkscape安装路径 ) : 

sys.path.append("D:\Inkscape\share\inkscape\extensions")

再次运行, 成功弹出窗口, 说明我们已经成功地在python运行起inkex/ Qt混合程序了.  这时在effect()里添加图层相关代码直接在python跑会没反应,最后程序挂掉, (如果inkex无关则一切正常) , 所以后面的步骤还是要进入Inkscape执行, 用self.msg调试

编辑一个MyQtDemo.inx, 把py和inx一起放入到extensions目录里. MyQtDemo.inx 内容如下

<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
    <name>Qt Input Example</name>
    <id>org.inkscape.filter.qt_input_example</id>

    <effect>
        <object-type>path</object-type>
            <effects-menu>
                <submenu name="AAA Tools"/>
            </effects-menu>
    </effect>
    <script>
        <command location="inx" interpreter="python">MyQtDemo.py</command>
    </script>
</inkscape-extension>

完整的 MyQtDemo.py

#!/usr/bin/env python
# coding=utf-8

import sys

sys.path.append("D:\Inkscape\share\inkscape\extensions")
# # #inkscape 插件所需
import inkex
from inkex.elements import Group, PathElement

# Qt所需
from PyQt5.QtWidgets import *
# #这个是ui文件对应的py文件的文件名
from  Ui_InkQtDemo  import Ui_Form
# 全局变量
inputXY={}

class MyExtension(inkex.EffectExtension):
    def effect(self):
        global inputXY
        x = inputXY["x"]
        y = inputXY["y"]
        # self.msg(x)
        # self.msg(y)

        cur_layer = self.svg.get_current_layer()
        my_shape = PathElement()
        my_shape.style =  {'stroke': 'red', 'stroke-width': '2', 'fill': 'none'}
        my_shape.path =  " M " + str(x) +" " + str(y) +"L 150 190 L 120 15 z"
        my_shape.set_id ("QtDemoPath")      # path id
        cur_layer.append( my_shape )        # 添加一个路径

class MyWindow(QWidget,Ui_Form):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.OnClick_pushButton)
    def OnClick_pushButton(self):
        x =  self.lineEdit.text() 
        y =  self.lineEdit_2.text() 
        global inputXY
        inputXY={"x":x, "y":y }     # 用字典的方式把输入值保存到全局变量
        self.close()
        MyExtension().run()

if __name__ == '__main__':
    app=QApplication(sys.argv)
    w=MyWindow()
    w.show()
    sys.exit(app.exec_())

打开Inkscape, 主菜单 -> 扩展 -> AAA Tools -> Qt Input Example, 在弹出界面里输入x,y值, 会显示一个三角形, 形状因输入值不同而变化, 而在图层上也会看到path的id是 "QtDemoPath"

当然这个方法也有个缺陷, 就是参数没保存到 preferences.xml 里面, 如果按快捷键 alt+Q, 还是会弹出界面要求输入参数, 这点比使用inx文件的用户体验要差一点, 但是Qt界面很全面, 这种方法让开发者几乎可以使用python全部的功能, 让Inkscape变得更好用.

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章