PyQt is a set of Python bindings to Qt — Nokia’s cross-platform GUI toolkit. Qt is mature, versatile and is released under an Open Source license. It is used in software like Google Earth, KDE, Opera, Skype, VLC media player and VirtualBox (Source: Wikipedia).
One of the advantages of using PyQt for graphical user interface (GUI)
development is the bundled
makes GUI design very easy and efficient. Widgets can be dragged and
dropped onto dialogs, main windows and widgets. The resulting XML user
.ui) files can be converted to Python code using the scripts
included with PyQt.
Using PyQt from within Bionumerics scripts opens up a number of possibilities — use simple message boxes with error or informative texts, create dialogs and display windows for working with databases and so on. Bionumerics includes some modules including BioPython but PyQt will need to be included manually. It is fairly simple to use an existing PyQt installation.
The latest stable version as of this writing is 2.6.5. It can be downloaded from http://python.org/download/releases/
Latest version can be downloaded and installed from http://www.riverbankcomputing.co.uk/software/pyqt/download [under Binary packages]. PyQt version as of this writing is
To be able to import PyQt modules from within Bionumerics, the module directory:
should be added to
PYTHONPATHor appended to
sys.pathbefore other import statements.
The Qt DLL’s must be available or added to the system
PATH. This will be done automatically by the PyQt installer. If the DLL’s are not added to the system path, it will lead to error messages like “DLL load failed” and the script will fail.
To demonstrate, I am going to use a simple dialog application as an example. This application is used to set the value of a given field of entries selected in the BioNumerics main window. When run, this is how it will appear:
Step 1 — Creating the dialog using Qt Designer§
The dialog displayed above was created in Qt Designer and the
file was saved as
setfielddlg.ui. The text at the top,
labels are all of
QLabel. The combo box used to display existing field names from the
database is of type
QComboBox. The input field
Deselect All buttons are all of type
Step 2 — Generating Python code for the Dialog§
setfielddlg.ui file generated from Qt Designer in the previous step is
an XML file describing all the elements of the dialog. This can
be converted to Python code using the
included with PyQt4:
pyuic4 -o ui_setfielddlg.py setfielddlg.ui
-o option specifies the name of the output file.
The dialog can now be called from other scripts.
should be in the system
PATH for the
pyuic4 command to work.
Step 3 — The main script§
"""A simple dialog application to set the field of selected entries in Bionumerics 6 """ import sys import bns #append paths to PyQt4 and the current directory to sys.path moduledir = [r'C:\Python26\Lib\site-packages', r'G:\Python\Bionumerics_scripts\src'] for moddir in moduledir: if moddir not in sys.path: sys.path.append(moddir) import dbf from PyQt4.QtCore import SIGNAL from PyQt4.QtGui import QApplication, QDialog, QMessageBox import ui_setfielddlg class Dlg(QDialog, ui_setfielddlg.Ui_Dialog): def __init__(self, fieldnames, parent=None): super(Dlg, self).__init__(parent) self.setupUi(self) self.connect(self.close_button, SIGNAL('clicked()'), self.accept) self.connect(self.apply_button, SIGNAL('clicked()'), self.setfield) self.connect(self.deselect_button, SIGNAL('clicked()'), self.deselect) if fieldnames: self.field_combo_box.addItems(fieldnames) else: QMessageBox.critical(None, 'Error', 'Could not get fieldnames') return def deselect(self): '''Deselect all entries if selected''' if len(bns.Database.Db.Selection): bns.Database.Db.Selection.Clear() else: return def setfield(self): '''Sets the field value of selected entries''' field = unicode(self.field_combo_box.currentText()) value = unicode(self.value_line_edit.text()) selected = dbf.getSelected() if selected: for item in selected: key = item.Key try: bns.Database.EntryField(key, field).Content = value except Exception, e: QMessageBox.critical(None, 'Error', str(sys.exc_info())) bns.Database.Db.Fields.Save() else: QMessageBox.information(None,'No entries selected', 'Please select entries before running script') if __name__ == '__main__': sys.__dict__['argv'] = ['argv'] app = QApplication(sys.argv) fields = dbf.getFieldNames() dialog = Dlg(fields) dialog.show() __bnscontext__.Stop(app.exec_())
Step 4 — Running the script§
Source code of all the scripts used here can be downloaded from my GitHub repository.
ui_setfielddlg.py and the module
dbf.py should be in the same directory. In my case, this was
G:\Python\Bionumerics_scripts\src and also specified in the
moduledir list in the
The dialog can be called by using the
Scripts -> Run script from file
option in Bionumerics and selecting
For this to work, database entries must be selected in the
main window of BioNumerics or else the dialog displays a
message and does nothing. Select the field from the
combo box, type in the value that needs to be set for the field and hit
Apply. The value field has a maximum length of 80 characters, which is the
maxiumum length of a field in BioNumerics.
The script in detail§
Some additional notes
bnsis the BioNumerics Python module
- PyQt4 module directories are appended to
sys.path, as is the path to the directory of the running script. This is done as to import any additional modules used by the script.
dbfis a module I wrote for general database functions. In this script, it is used for getting a list of selected entries (
get_selected) and for getting the list of field names in the database -
ui_setfielddlg contains code for the dialog:
import sys import bns #append paths to PyQt4 and the current directory to sys.path moduledir = [r'C:\Python26\Lib\site-packages', r'G:\Python\Bionumerics_scripts\src'] for moddir in moduledir: if moddir not in sys.path: sys.path.append(moddir) import dbf from PyQt4.QtCore import SIGNAL from PyQt4.QtGui import QApplication, QDialog, QMessageBox import ui_setfielddlg
The dialog class — Dlg§
Takes the fieldnames as an argument and populates the
combo box if it is not empty. The
clicked() signal of the
close button is connected to the
accept slot, which closes
the dialog. This is the same signal that is emitted by when
the window is closed from the menubar. The other buttons are connected to their respective slots which are
defined within the class.
sys.__dict__['argv'] = ['argv'] does nothing.
For some reason,
sys.argv is empty or not defined when running
the script from BioNumerics, and the line of the code
QApplication(sys.argv) refuses to work without it.
As no commandline arguments are used in the code above, it should cause no harm:
__bnscontext__.Stop(app.exec_()) stops the program once the event
app.exec_() returns. This is similar to
sys.exit(app.exec_()) used in standard PyQt4 programs.
Some issues I am aware of:
- Only one instance of the script should run. Calling it twice causes a crash.
- The dialog must be closed before exiting Bionumerics or else the program crashes.
If you have any questions or comments on this post, please send them by email to vimal (at) disroot (dot) org.
If you would like your comment to remain anonymous, please state that in your email. In any case, your email address will not be published.