ทำปลั๊กอิน QGIS หลามสำหรับทั้งรุ่น 2.x และ 3.x?


12

ฉันอยู่ระหว่างการโอนย้ายปลั๊กอิน QGIS python จากและQGIS 2ไปยังQGIS 3แหล่งข้อมูลต่างๆ

ยังไม่ชัดเจนว่าเป็นไปได้หรือไม่ที่จะมีปลั๊กอินที่เข้ากันได้กับทั้งสองเวอร์ชันหรือหากจำเป็นต้องมีสองจุดจับสำหรับปลั๊กอินเวอร์ชัน

ปัญหาที่ฉันได้รับจนถึงตอนนี้คือวิธีจัดการการนำเข้า PyQt (PyQt4 / PyQt5)?

คำตอบ:


18

เอกสาร

นี่คุณจะพบสิ่งใหม่และสิ่งที่อยู่ภายใต้การแบ่ง PyQGIS API
เพื่อรับรายละเอียดเกี่ยวกับวิธีพอร์ต Python2 ไปยัง Python3 ไปที่นั่น

คุณสามารถหารายละเอียดเกี่ยวกับการทดสอบจาก QGIS2 ถึง QGIS3 ในคำถามนี้: การเขียนการทดสอบอัตโนมัติสำหรับปลั๊กอิน QGIS?

และคุณจะพบกระดาษของ OpenGis.ch ที่น่าสนใจที่นี่เกี่ยวกับเครื่องมือการย้ายข้อมูล

อะไรจะเปลี่ยนเป็นรหัสของฉัน

ในความเป็นจริงคุณต้องเปลี่ยนรหัสของปลั๊กอินที่ไม่ได้เตรียมที่จะผ่านรุ่นใหม่

คุณได้รับฟังก์ชันqgis.utils.QGis.QGIS_VERSION_INTซึ่งทำขึ้นเพื่อตรวจสอบเวอร์ชั่น QGIS นี่คือประโยชน์เมื่อฟังก์ชันถูกคิดค่าเสื่อมราคา สำหรับตัวอย่างsetSelectedFeaturesตั้งแต่ 2.16

โดยสุดยอดกับการใช้ifคำสั่ง:

if qgis.utils.QGis.QGIS_VERSION_INT < 21600 :
            joinLayer.setSelectedFeatures( [ f.id() for f in request ] )
        else:
            joinLayer.selectByIds(  [ f.id() for f in request ] )

มันเหมือนกันกับPyQtวัตถุที่คุณนำเข้าภายใต้โมดูล หากคุณต้องการความเข้ากันได้ราคาคือการเขียนบรรทัดรหัสเพิ่มเติม (รหัสที่มีฟังก์ชั่น QGIS2 และรหัสที่มีฟังก์ชั่น QGIS3 และรหัสสำหรับการตรวจสอบรุ่นและความสามารถในการนำเข้าห้องสมุดใหม่)

เกี่ยวกับห้องสมุด PyQt

PyQt5 นั้นไม่สามารถใช้ร่วมกับ PyQt4 แบบย้อนหลังได้ มีการเปลี่ยนแปลงที่สำคัญหลายอย่างใน PyQt5 อย่างไรก็ตามมันไม่ยากที่จะปรับโค้ดเก่าให้เป็นไลบรารี่ใหม่ ความแตกต่างระหว่างคนอื่น ๆ มีดังนี้

  • โมดูล Python ถูกปรับโครงสร้างใหม่ บางโมดูลถูกดร็อป (QtScript), โมดูลอื่นถูกแบ่งเป็น submodules (QtGui, QtWebKit)

  • โมดูลใหม่ได้รับการแนะนำรวมถึง QtBluetooth, QtPositioning หรือ Enginio

  • PyQt5 รองรับเฉพาะสัญญาณสไตล์ใหม่และ handlig ของสล็อต ไม่รองรับการโทรไปยัง SIGNAL () หรือ SLOT () PyQt5 ไม่สนับสนุนส่วนใด ๆ ของ Qt API ที่ทำเครื่องหมายว่าเลิกใช้แล้วหรือล้าสมัยใน Qt v5.0

แหล่งที่มา: ( http://zetcode.com/gui/pyqt5/introduction/ )

นี่คือตัวอย่างบางส่วนของการเปลี่ยนแปลงในคำสั่ง from / import ของคุณ:

จดจำด้วย PyQt4 คุณต้องดูเอกสาร API ของ:
สำหรับ
โมดูล PyQT4 QtCoreตัวอย่างโมดูลPyQT4 โมดูล
PyQT4 QtGui

from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, Qt, QObject, SIGNAL

from PyQt4.QtGui import QAction, QIcon, QDialog, QFormLayout

และด้วย PyQt5 ตอนนี้คุณต้องมองหาเอกสารของ API เหล่านั้น:
PyQt5 โมดูลQtCore โมดูล
PyQt5 QtGui

ดังนั้นกลายเป็น:

from PyQt5.QtCore import QSettings, QTranslator, QVersionNumber, QCoreApplication, Qt, QObject, pyqtSignal 
from PyQt5.QtGui import QIcon 
from PyQt5.QtWidgets import QAction, QDialog, QFormLayout

โปรดทราบว่า:

โมดูล QtGui ได้ถูกแบ่งออกเป็น submodules โมดูล QtGui มีคลาสสำหรับการรวมระบบหน้าต่างการจัดการเหตุการณ์กราฟิก 2D การสร้างภาพขั้นพื้นฐานฟอนต์และข้อความ นอกจากนี้ยังมีชุดของการผูก OpenGL และ OpenGL ES ที่สมบูรณ์ (ดูการสนับสนุนสำหรับ OpenGL ) นักพัฒนาแอปพลิเคชันจะใช้สิ่งนี้กับ API ระดับสูงกว่าเช่นที่อยู่ในโมดูล QtWidgets

และ PyQt5 รองรับเฉพาะสัญญาณรูปแบบใหม่และ handlig สล็อต! มีลักษณะที่ดูหน้านี้ที่จะเข้าใจวิธีการใช้งานpyqtSignal, connectและวัตถุเหตุการณ์แทนการใช้eSIGNAL

ทำให้มันเข้ากันได้

ดังนั้นด้วยความเข้ากันได้ระหว่าง PyQt4 / PyQt5 (และ QGIS2 / QGIS3 เช่นกัน) คุณต้องลอง / ยกเว้นการนำเข้าก่อนที่จะใช้ pyQt5 librarie

try:
    from PyQt5.QtCore import QSettings, QTranslator, QVersionNumber, QCoreApplication, Qt, QObject, pyqtSignal 
    from PyQt5.QtGui import QIcon 
    from PyQt5.QtWidgets import QAction, QDialog, QFormLayout

except:
    from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication, Qt, QObject, SIGNAL
    from PyQt4.QtGui import QAction, QIcon, QDialog, QFormLayout

และอย่าลืมว่าคุณต้องเปลี่ยนฟังก์ชั่นบางอย่างภายใต้รหัสของคุณด้วยการเพิ่มลอง / ยกเว้นหรือถ้ามีคำสั่ง


2
คำตอบที่ดีสิ่งที่จะช่วยได้มากก็คือแทนที่ส่วนแรกfrom PyQt4.QtCore import *ด้วยfrom PyQt4.QtCore import QSomething, QWhatever, QElseสิ่งนี้จะทำให้สคริปต์การโอนย้ายทำขั้นตอนสุดท้ายได้อย่างถูกต้อง (รวมถึงการปรับเปลี่ยนที่จำเป็นเมื่อโมดูลเปลี่ยนแปลง) ดังนั้นจึงไม่จำเป็นต้องลอง
Matthias Kuhn

คุณถูกต้องฉันใช้ * เพื่อทำให้มันง่าย แต่ฉันจะเปลี่ยนขอบคุณสำหรับความคิดเห็นของคุณ
Hugo Roussaffa - GeoDatup

หัวข้อนี้เป็นสถานที่ที่สมบูรณ์แบบที่จะบอกให้คนไม่ได้ใช้ * -imports เพราะที่นี่จริงๆแล้วมันสร้างความแตกต่าง
Matthias Kuhn

@Hugo: คำตอบที่มีรายละเอียดมากแน่นอนมันช่วยได้มากในการเริ่มต้น ฉันจะเพิ่มปลั๊กอินqgis2compatไปยังทรัพยากรที่มีประโยชน์มากมายที่อ้างถึงแล้ว
sigeal

นั่นเป็นความคิดที่ดี คุณสามารถแก้ไขคำตอบได้ตามที่คุณต้องการ ขอบคุณสำหรับคำติชม
Hugo Roussaffa - GeoDatup

2

ลองอะไรเช่นนั้น:

try:
    # action for QGIS 3/PyQt5
except:
    # action for QGIS 2/PyQt4

สิ่งนี้อาจใช้ได้กับบางสิ่งบางอย่างที่แยกได้ แต่มักจะไม่ทำงานในรูปแบบทั่วไป
Matthias Kuhn

1

ฉันเพิ่งโอนย้ายปลั๊กอิน QGIS Python เสร็จสิ้นเพื่อให้รองรับเวอร์ชัน QGIS ทั้ง 2.x และ 3.x นี่คือประสบการณ์ของฉัน:

ส่วนใหญ่ฉันพยายามใช้เวอร์ชัน QGIS แต่แม้กระทั่งชั้นเรียนที่ถือเวอร์ชั่นก็เปลี่ยนชื่อเล็กน้อย ดังนั้นก่อนอื่นเลย

try:
    from qgis.utils import Qgis  # for QGIS 3
except ImportError:
    from qgis.utils import QGis as Qgis  #  for QGIS 2

จากนั้นทำการตรวจสอบ

if Qgis.QGIS_VERSION >= '3.0':
    # something for QGIS 3
else:
    # something for QGIS 2

หลังจากการปรับใช้รุ่นสุดท้ายฉันสังเกตเห็นว่าไฟล์resources.pyที่สร้างขึ้นโดยอัตโนมัติโดยpyrcc5ยังต้องพอร์ต มิฉะนั้นปลั๊กอินจะยังคงแยกย่อยใน 2.x ดังนั้นฉันจึงเปลี่ยนสาย

from PyQt5 import QtCore

ถึง

try:
    from PyQt5 import QtCore
except:
    from PyQt4 import QtCore

ดูเหมือนว่าจะทำงาน ฉันทำรุ่นอย่างเป็นทางการและคิดว่ามันเป็น จากนั้นฉันก็ค้นพบลำดับนี้:

ติดตั้งปลั๊กอินของฉันใน QGIS 2.18 ปิด QGIS เปิด QGIS agan แล้วเปิด Python Console ภายใน QGIS -> QGIS ทั้งหมดจะพังทันที!

หลังจากการทดสอบบางอย่างฉันพบว่าสาเหตุคือการเปลี่ยนแปลงเล็กน้อยในการresources.pyเขียนข้างต้น ฉันไม่มีความเชี่ยวชาญในห้องสมุด QGIS Python แต่คำอธิบายของฉันมีดังต่อไปนี้:

เมื่อฉันเปิด QGIS ปลั๊กอินของฉันจะเริ่มต้นได้ ความพยายามที่จะfrom PyQt5 import QtCoreทำให้เกิดการเปลี่ยนแปลงบางอย่างใน QGIS "เวิร์กโฟลว์" ก่อนรุ่น PyQt ที่ผิดจะเพิ่มข้อยกเว้น (ซึ่งเป็นRuntimeError) เมื่อฉันเริ่ม Python Console การเปลี่ยนแปลงเหล่านี้ทำให้ QGIS พัง

ในตอนท้ายฉันตัดสินใจหาทางออกที่แตกต่าง เนื่องจาก QGIS 2 ใช้ Python 2.7 และ QGIS 3 ใช้ Python 3 ฉันมักจะตรวจสอบเวอร์ชัน Pythonเสมอ

from sys import version_info

if version_info[0] >= 3:
    # something for QGIS 3
else:
    # something for QGIS 2

นี่เป็นการหลีกเลี่ยงการนำเข้าที่อาจเป็นอันตรายทั้งหมด ตอนนี้ปลั๊กอินของฉันใช้ได้กับทั้ง QGIS ทั้งสองรุ่นโดยไม่มีปัญหาใด ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.