Сменная программа Python
Я хочу сделать программу PyQt4, которая поддерживает плагины. По сути, я хочу, чтобы пользователь мог писать подклассы QWidget в PyQt4 и добавлять / удалять их из главного окна приложения через графический интерфейс. Как бы я это сделал, особенно механизм плагинов?
2 ответа
Во-первых, используйте QFileDialog или, более удобно, статическую функцию QFileDialog.getOpenFileName, чтобы позволить пользователю выбрать .py
файл, который они хотят "подключить" к вашему GUI.
Далее, если вы хотите разрешить импорт плагина из любого места на диске (в отличие от определенных каталогов, ранее добавленных в ваш sys.path
например, через переменную окружения PYTHONPATH
), вы можете "сделать это правильно" (немалый объем работы) через модуль imp в стандартной библиотеке Python) или "обрезать углы" следующим образом (при условии, что filepath
это QString
с путем к файлу и тем, что вы используете файловую систему / платформу с собственно именами Unicode - в противном случае вам придется добавить что угодно .encode
ваша платформа и файловая система требуют)...:
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)
Это не потокобезопасно, потому что может иметь побочный эффект sys.path
Вот почему я сказал, что это "обрезка углов"... но тогда сделать потокобезопасный импорт (и "чистый" импорт из "где угодно") - это действительно тяжелая работа (вероятно, стоит отдельного вопроса, если вам нужно, так как на самом деле не имеет ничего общего с сущностью этого, или PyQt, и с).
Как только у вас есть объект модуля (результат из importfrom
выше), предлагаю:
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)]
Это возвращает список со всеми классами виджетов (если таковые имеются), определенных (на верхнем уровне) в модуле amodule
,
То, что вы хотите сделать дальше, зависит от вас, конечно. Возможно, вы хотите выдавать какие-то сообщения об ошибках, если список пуст (или, может быть, если в нем более одного элемента? Или как решить, какой класс виджетов использовать?) Или создать экземпляр класса виджетов (сколько раз? По каким координатам? И так далее - вопросы, на которые только вы можете ответить) и покажите получившиеся виджеты в соответствующих точках вашего окна.
Иметь каталог для плагинов, определить интерфейс для этих плагинов и пройти каталог, импортирующий их.
Я никогда не делал этого в Python, но в C я сделал так, чтобы определить ряд функций, которые плагин должен был реализовать. Основными ключевыми элементами, которые необходимы, являются имена вещей в плагине (чтобы вы могли отображать их в своем пользовательском интерфейсе, чтобы пользователь мог их создавать) и фабрика для фактического создания вещей. Я предполагаю, что в Python было бы довольно тривиально просто сделать это как один из указаний, которые вы можете вернуть из модуля.
Например, объявите, что все плагины должны создавать функцию GetPluginInfo(), которая возвращает словарь отображений name:class.
На самом деле, теперь, когда я думаю об этом, вы можете просто импортировать файл и искать классы, которые являются подклассами того, что вас волнует и не требуют реализации какого-либо явного API. Я не сделал этого много, но в основном вы должны пройти модуль dir() и проверить, является ли каждая вещь подклассом QWidget (например).