programma Pluggable Python
Domanda
Voglio fare un programma PyQt4 che supporta i plugin. Fondamentalmente voglio che l'utente sia in grado di scrivere sottoclassi QWidget in PyQt4 e aggiungere / rimuovere dal finestra principale dell'applicazione tramite una GUI. Come avrei fatto che, in particolare il meccanismo di plug-in?
Soluzione
In primo luogo, utilizzare un QFileDialog o più comodamente la funzione statica QFileDialog.getOpenFileName per lasciare che il all'utente di scegliere il file .py
vogliono "plug in" GUI.
Poi, se si desidera consentire l'importazione del plugin dal ovunque sul disco (al contrario di, da specifiche directory precedentemente aggiunti alla tua sys.path
, ad esempio attraverso l'PYTHONPATH
variabile d'ambiente), è possibile " farlo bene"(una quantità non trascurabile di lavoro), tramite il imp modulo libreria standard di Python), oppure si può "angoli tagliati" come segue (supponendo filepath
è il QString
con il percorso del file, e che si sta utilizzando un file system / piattaforma con nativamente Unicode nomi di file - altrimenti dovrete aggiungere qualunque .encode
la propria piattaforma e filesystem richiedono) ...:
import sys, os
def importfrom(filepath):
ufp = unicode(filepath)
thedir, thefile = os.path.split(ufp)
if sys.path[0] != thedir:
sys.path.insert(0, thedir)
themodule, theext = os.path.splitext(thefile)
return __import__(themodule)
Questa non è thread-safe perché può avere un effetto collaterale sulla sys.path
, che è il motivo per cui ho detto che è "angoli di taglio" ... ma poi, che le importazioni siano thread-safe (e importazioni "pulite" da "ovunque ") è davvero il duro lavoro (probabilmente vale la pena una domanda separata se è necessario, dal momento che ha davvero nulla a che fare con l'essenza di questa, o PyQt, ecc).
Una volta che si ha l'oggetto modulo (il risultato da importfrom
sopra), vi consiglio:
from PyQt4 import QtGui
import inspect
def is_widget(w):
return inspect.isclass(w) and issubclass(w, QtGui.QWidget)
def all_widget_classes(amodule):
return [v for n, v in inspect.getmembers(amodule, is_widget)]
Questa funzione restituisce un elenco con tutti i widget di classi (se del caso) definita (al livello superiore) nel modulo amodule
.
Che cosa si vuole fare dopo è a voi, naturalmente. Forse si vuole dare un qualche tipo di messaggi di errore se l'elenco è vuoto (o forse anche se ha più di una voce? Altrimenti come si fa a decidere quale widget di classe da utilizzare?), Oppure creare un'istanza della classe widget di (quante volte? a che coordina e così via -?. domande solo tu puoi rispondere) e mostrare i conseguenti widget di (s) nel punto appropriato (s) sulla vostra finestra
Altri suggerimenti
Avere una directory per i plugin, definire un'interfaccia per i plugin, e camminare la directory di importarli.
Non ho mai fatto questo in Python, ma in C il modo in cui l'ho fatto è stato quello di definire un numero di funzioni che il plugin necessario per attuare. Gli elementi chiave di base che sono necessari è il nome delle cose nel plug-in (in modo da poterli visualizzare nel interfaccia utente in modo che l'utente li può istanziare) e una fabbrica per creare realmente le cose. Suppongo che in Python sarebbe abbastanza banale da fare solo quelli come uno dict che si può tornare dal modulo.
es. dichiarano che tutti i plugin devono all'autore una funzione chiamata GetPluginInfo (), che restituisce un dizionario di nome:. mappature di classe
In realtà, ora che ci penso si potrebbe probabilmente solo importare il file e il look per le classi che sono sottoclassi di qualsiasi che ti interessano e non richiede alcuna API esplicita essere implementato. Non ho fatto un sacco di che ma fondamentalmente si piacerebbe camminare dir del modulo () e test per vedere se ogni cosa è una sottoclasse di QWidget (per esempio).