Plugins Tutorial: Difference between revisions
m (add see also Plugins) |
(pymol2-demo-plugin) |
||
Line 1: | Line 1: | ||
This tutorial is about writing your own plugin for PyMOL 2.x. | |||
See the [[plugins]] page for how to install and use exisiting plugins. | |||
==Writing Plugins: Learn By Example== | ==Writing Plugins: Learn By Example== | ||
This tutorial | |||
This tutorial shows how to write a PyMOL plugin with PyQt. '''The full source of the demo plugin is [https://github.com/Pymol-Scripts/pymol2-demo-plugin available on github]'''. | |||
The demo plugin adds a dialog to render images at a custom resolution. | |||
=== Plugin Files === | |||
We will create a plugin which consists of [[PluginArchitecture#More than one file per plugin|multiple files inside a directory]]: | |||
<source lang="Python"> | |||
pymol2-demo-plugin/ | |||
├── demowidget.ui | |||
└── __init__.py (defines "__init_plugin__(app=None)" function) | |||
</source> | |||
===Registering your Plugin=== | ===Registering your Plugin=== | ||
First you must add your plugin to the ''Plugins'' menu. | |||
First you must add your plugin to the ''Plugins'' menu. | |||
This is done in the <code>__init_plugin__</code> function of your plugin. | |||
A callback (here: <code>run_plugin_gui</code>) is added. | |||
<source lang="python"> | <source lang="python"> | ||
# file pymol2-demo-plugin/__init__.py | |||
def __init_plugin__(app=None): | |||
from pymol.plugins import addmenuitemqt | |||
addmenuitemqt('Demo "Render" Plugin', run_plugin_gui) | |||
</source> | </source> | ||
=== | ''Legacy note'': The <code>__init_plugin__</code> function takes one argument, a reference to the main Tk app to [[PluginArchitecture#init_plugin|support legacy plugins witten with Tkinter]] (unused with PyQt plugins). | ||
=== Creating a GUI === | |||
The callback may do arbitrary stuff. Here we're going to create a dialog and show it to the user. | |||
<source lang="python"> | <source lang="python"> | ||
def run_plugin_gui(): | |||
# pymol.Qt provides the PyQt5 interface, but may support PyQt4 and/or PySide as well | |||
from pymol.Qt import QtWidgets | |||
# create a new (empty) Window | |||
dialog = QtWidgets.QDialog() | |||
# TODO: FILL DIALOG WITH WIDGETS HERE | |||
dialog.show() | |||
</source> | </source> | ||
=== Filling the GUI with Widgets === | |||
[[Image:designer-demo-plugin.png|thumb|right|400px|Screenshot of Qt Designer]] | |||
The most convenient and maintainable way to create user interfaces with Qt is by using the [http://doc.qt.io/qt-5/qtdesigner-manual.html Qt Designer]. | |||
Follow these steps to get started: | |||
</ | |||
# Create a new "Widget" form (New Form > templates/forms > Widget > Create) | |||
# Drag widgets like "Push Button" or "Line Edit" into your form | |||
# Name your widgets ("objectName" in the "Property Editor"), this name will become a Python variable in your code | |||
# Save as a UI file (<code>*.ui</code>) inside the <code>pymol2-demo-plugin</code> directory | |||
PyMOL provides a utility function to load a UI file into a parent widget: <code>pymol.Qt.utils.loadUi(filename, widget)</code> | |||
< | <syntaxhighlight lang="python"> | ||
# filename of our UI file | |||
uifile = os.path.join(os.path.dirname(__file__), 'demowidget.ui') | |||
# load the UI file into our dialog | |||
from pymol.Qt.utils import loadUi | |||
form = loadUi(uifile, dialog) | |||
</syntaxhighlight> | |||
== | === Make Buttons do something === | ||
We need to connect the [http://doc.qt.io/qt-5/signalsandslots.html signals] of those widgets we created with the Qt Designer, like our buttons' <code>clicked</code> signal. | |||
Our example has a "Ray" button (''objectName=button_ray'') that we'll connect to the <code>run()</code> function. | |||
<syntaxhighlight lang="python"> | |||
def run(): | |||
# get form data | |||
height = form.input_height.value() | |||
# some debugging feedback | |||
print('User entered height', height) | |||
# TODO: DO SOMETHING WITH FORM DATA | |||
form.button_ray.clicked.connect(run) | |||
</syntaxhighlight> | |||
=== Deploy the final plugin === | |||
The <code>pymol2-demo-plugin</code> directory can be zipped for deployment (see [[PluginArchitecture#More than one file per plugin]]). | |||
== | === Full Source === | ||
The full source of the demo plugin is [https://github.com/Pymol-Scripts/pymol2-demo-plugin available on github]'''. | |||
== Extending Plugins to the Command Line == | |||
While not really applicable to our simple "Render" plugin (it only wraps existing <code>ray</code> and <code>png</code> commands), most plugins should also provide their functionality as new PyMOL commands using [[extend|cmd.extend()]]. | |||
</ | |||
and | |||
== See Also == | |||
* [[PluginArchitecture]] | |||
[[Plugins]] | * [[Plugin Manager]] | ||
* [[Plugins]] | |||
* [[extend|cmd.extend()]] | |||
[[Category:Developers|Plugins_Tutorial]] | [[Category:Developers|Plugins_Tutorial]] | ||
[[Category:Plugins|Plugins_Tutorial]] | [[Category:Plugins|Plugins_Tutorial]] | ||
[[Category:Tutorials]] | [[Category:Tutorials]] |
Revision as of 13:17, 13 November 2018
This tutorial is about writing your own plugin for PyMOL 2.x.
See the plugins page for how to install and use exisiting plugins.
Writing Plugins: Learn By Example
This tutorial shows how to write a PyMOL plugin with PyQt. The full source of the demo plugin is available on github.
The demo plugin adds a dialog to render images at a custom resolution.
Plugin Files
We will create a plugin which consists of multiple files inside a directory:
pymol2-demo-plugin/
├── demowidget.ui
└── __init__.py (defines "__init_plugin__(app=None)" function)
Registering your Plugin
First you must add your plugin to the Plugins menu.
This is done in the __init_plugin__
function of your plugin.
A callback (here: run_plugin_gui
) is added.
# file pymol2-demo-plugin/__init__.py
def __init_plugin__(app=None):
from pymol.plugins import addmenuitemqt
addmenuitemqt('Demo "Render" Plugin', run_plugin_gui)
Legacy note: The __init_plugin__
function takes one argument, a reference to the main Tk app to support legacy plugins witten with Tkinter (unused with PyQt plugins).
Creating a GUI
The callback may do arbitrary stuff. Here we're going to create a dialog and show it to the user.
def run_plugin_gui():
# pymol.Qt provides the PyQt5 interface, but may support PyQt4 and/or PySide as well
from pymol.Qt import QtWidgets
# create a new (empty) Window
dialog = QtWidgets.QDialog()
# TODO: FILL DIALOG WITH WIDGETS HERE
dialog.show()
Filling the GUI with Widgets
The most convenient and maintainable way to create user interfaces with Qt is by using the Qt Designer. Follow these steps to get started:
- Create a new "Widget" form (New Form > templates/forms > Widget > Create)
- Drag widgets like "Push Button" or "Line Edit" into your form
- Name your widgets ("objectName" in the "Property Editor"), this name will become a Python variable in your code
- Save as a UI file (
*.ui
) inside thepymol2-demo-plugin
directory
PyMOL provides a utility function to load a UI file into a parent widget: pymol.Qt.utils.loadUi(filename, widget)
# filename of our UI file
uifile = os.path.join(os.path.dirname(__file__), 'demowidget.ui')
# load the UI file into our dialog
from pymol.Qt.utils import loadUi
form = loadUi(uifile, dialog)
Make Buttons do something
We need to connect the signals of those widgets we created with the Qt Designer, like our buttons' clicked
signal.
Our example has a "Ray" button (objectName=button_ray) that we'll connect to the run()
function.
def run():
# get form data
height = form.input_height.value()
# some debugging feedback
print('User entered height', height)
# TODO: DO SOMETHING WITH FORM DATA
form.button_ray.clicked.connect(run)
Deploy the final plugin
The pymol2-demo-plugin
directory can be zipped for deployment (see PluginArchitecture#More than one file per plugin).
Full Source
The full source of the demo plugin is available on github.
Extending Plugins to the Command Line
While not really applicable to our simple "Render" plugin (it only wraps existing ray
and png
commands), most plugins should also provide their functionality as new PyMOL commands using cmd.extend().