可插拔的Python程序 [英] Pluggable Python program

查看:209
本文介绍了可插拔的Python程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个支持插件的PyQt4程序.基本上,我希望用户能够在PyQt4中编写QWidget子类,并通过GUI从主应用程序窗口添加/删除它们.我该怎么做,尤其是插件机制?

解决方案

首先,使用 QFileDialog 或更方便地使用静态函数 QFileDialog.getOpenFileName ,让用户选择要插入" GUI的.py文件.

下一步,如果您想允许从磁盘上的任何地方导入插件(与之相反,例如从先前添加到sys.path的特定目录中,例如通过环境变量PYTHONPATH) ,您可以通过 im 模块),也可以按如下方式偷工减料"(假设filepathQString并带有文件路径,并且您正在使用具有本机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和& c的要旨没有太大关系). /p>

一旦有了模块对象(上面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中(在顶层)定义的所有窗口小部件(如果有).

当然,您接下来要做什么.如果列表为空(或者如果列表中有多个项目,则可能还想给出某种错误消息),或者如何确定要使用哪个窗口小部件类?)或者实例化窗口小部件类(多少次?).在什么坐标下?依此类推-只有您可以回答的问题),然后在窗口的适当位置显示生成的小部件.

I want to make a PyQt4 program that supports plugins. Basically I want the user to be able to write QWidget subclasses in PyQt4 and add/remove them from the main application window via a GUI. How would I do that, especially the plugin mechanism?

解决方案

First, use a QFileDialog or more conveniently the static function QFileDialog.getOpenFileName to let the user pick the .py file they want to "plug into" your GUI.

Next, if you want to allow importing the plugin from anywhere on the disk (as opposed to, from specific directories previously added to your sys.path, e.g. via the environment variable PYTHONPATH), you can "do it right" (a non-negligible amount of work), via the imp module in the standard Python library), or you can "cut corners" as follows (assuming filepath is the QString with the path to the file, and that you're using a filesystem/platform with natively Unicode filenames -- otherwise you'll have to add whatever .encode your platform and filesystem require)...:

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)

This isn't thread-safe because it may have a side effect on sys.path, which is why I said it's "cutting corners"... but then, making thread-safe imports (and "clean" imports from "anywhere") is really hard work (probably worth a separate question if you need to, since it really has nothing much to do with the gist of this one, or PyQt, &c).

Once you do have the module object (the result from importfrom above), I suggest:

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)]

This returns a list with all the widget classes (if any) defined (at the top level) in module amodule.

What you want to do next is up to you, of course. Perhaps you want to give some kind of error messages if the list is empty (or maybe also if it has more than one item? or else how do decide which widget class to use?) or else instantiate the widget class (how many times? At what coordinates? And so on -- questions only you can answer) and show the resulting widget(s) in the appropriate spot(s) on your window.

这篇关于可插拔的Python程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆