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變得更好用.

 

 

 

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