Transcript GUI_design
GUI design with Python –
examples from crystallography
Bernhard Lohkamp
Karolinska Institute
Stockholm
Sweden
Coot - Who are we – why am I here?
Paul Emsley
(Oxford; everything)
Bernhard Lohkamp
(Stockholm; Python, GUI, Windows)
Kevin Cowtan (York;
crystallographic libraries & tools)
[email protected]
Eugene Krissinel, Stuart McNicholas, and others...
7/5/10
COOT
Graphical
(CrystallographicObject)-Oriented Toolkit
Used in macromolecular
(X-ray) crystallography
Main aims:
Model building
Model completion
Model validation
Graphical, interactive,
intuitive, …
[email protected]
7/5/10
G(raphical) U(ser) I(nterface)
GUI <-> UI
Allow end users to interact with application
Interface can be simple (e.g. command line) to
complex (graphical)
Good UI:
Intuitive
Easy to use/learn
Note: applications with good UI are preferred to ones
with inferior ones (independent of quality of
application!?)
[email protected]
7/5/10
What do you prefer?
>>> delete_residue(10)
[email protected]
7/5/10
GUIs
Good things about GUI
Intuitive (if designed properly)
More efficient (e.g., putting the cursor at a
particular location)
Multiple activities simultaneously
Bad things about GUI
Inefficient (if mis-designed)
Difficult to automate (e.g. difficult to write a
program to push a button in another application)
Speed
[email protected]
7/5/10
The challenge of GUI programming
programming model must address the following issues:
user allowed to perform different things (e.g. type a character,
type a hot-key, click on a button, resize the window, obscure
the window with another application, minimize it, etc.)
program needs to adapt to different window size (and with it all
its content)
Solution:
event-driven model
widget systems (controlled by a geometry manager)
Use Toolkits == TK
[email protected]
7/5/10
Windows manager/Desktop
Forms of interaction
events in context
Human Interface
Device (HID)
control
[email protected]
7/5/10
Windowing system/hierarchy
Lots of layers
Not very efficient
Slow (not necessary to be fast?!)
Our script (in Python): Real application
TK (in Python): glue to TK
TK Python plugin (usually in C): translate to TK calls
TK widgets (usually in C): Widget implementation
TK library (usually C): glue to
windowing system
Windows managing system (e.g. X)
[email protected]
7/5/10
Connect GUI with Python
Direct via script
GUI design tools and
IDEs (Integrated
Development
Environments)
GUI builder
GUI to build a GUI
application
Useful especially for larger
projects
Output usually xml
Use directly
Translate to Python script
[email protected]
7/5/10
GUI modules for Python (I)
(Toolkits, cross-platform)
PyGTK (Gnome): Coot
TK: GTK+ (GIMP Tool Kit)
Well supported
Builder (Glade)
xml direct
Not native on Mac (yet)
PyQt (KDE): CCP4mg –
molecular graphics
TK: Qt (“cu-te”)
Licence issue?
Native
Builder (Designer)
xml->python
[email protected]
7/5/10
GUI modules for Python (II)
Tk(Inter): PyMOL
TK: Tk
Tkinter Python Tk
interface
Distributed with python
Not OO
Builder (GUI builder)
wxPython: Phenix
TK: wxWidgets
Builder (wxGlade)
Native
?
[email protected]
7/5/10
Nomenclature/Widgets
Widget: “windowing gadget”, which means “a useful
building block (gadget) to make a windowing system”.
Hierarchy (exemplified):
[email protected]
7/5/10
Widget examples
Top level
(independent
widgets):
Main window
Various (predefined) dialogs
[email protected]
7/5/10
Dialogs (I)
Info (Message) dialog
Dialog box
[email protected]
7/5/10
Dialogs (II)
About dialog
Assistant
[email protected]
7/5/10
Dialogs (III)
Selection dialogs
Files
Colours
Fonts
….
[email protected]
7/5/10
Containers/Layout
Boxes
Vertical
Horizontal
Combined (grid, table)
Scrolled window
Tabbed
widgets/notebook
Frames
Panes
[email protected]
7/5/10
Boxed layout
[email protected]
7/5/10
Tabbed window/Notebook
[email protected]
tabs
7/5/10
Buttons
Button
Toggle button
Check button
Spin button
Radio button
Pre-defined buttons
Files
Colours
Fonts
…
[email protected]
7/5/10
Input & Entries (I)
Menu
Toolbar
[email protected]
7/5/10
Menus
Submenus
Icons
Accelerators
[email protected]
7/5/10
Context menu
Shown upon
event (usually
mouse click)
[email protected]
7/5/10
Toolbars
Like menus but contain icons/buttons
Short-cut for frequently used functions
[email protected]
7/5/10
Toolbar
[email protected]
7/5/10
Change
Style
[email protected]
7/5/10
Text
only
[email protected]
7/5/10
Text
and
Icons
[email protected]
7/5/10
Toolbar
Detouch/
Handle
[email protected]
7/5/10
detouched
[email protected]
7/5/10
Input & Entries (I)
Combobox –
spin button
Simple Entry:
[email protected]
7/5/10
Input & Entries (II)
Entry:
Auto-completion possible
Sliders
[email protected]
7/5/10
List/Tree structures
[email protected]
7/5/10
Can include: icons, buttons, …
[email protected]
7/5/10
Tree-> expansion
[email protected]
7/5/10
Miscellaneous widgets
Progress bar
Status bar
[email protected]
7/5/10
Canvas
Drawing area
Canvas/cairo drawing
(e.g. PyGoocanvas)
OpenGL drawing (e.g.
PyOpenGL, PyGtkGLExt)
Can be interactive
[email protected]
7/5/10
Tooltips
Pop ups with text
(upon mouse over)
Helps to explore the
GUI without reading
help files
Use whenever you
can (!?)
[email protected]
7/5/10
GUI design
What makes a good UI?
Simple
Intuitive
Respects the commonly accepted conventions
Visually organized
Native look
[email protected]
7/5/10
Designing UIs
Two levels:
Graphical: visual aspect
Events: Functionality
Basic blocks = widgets
Making an application react to events = binding
[email protected]
7/5/10
General concepts
Main loop and events
Packing
Showing
How to do.
[email protected]
7/5/10
Main loop and events
TK mainloop:
Event loop
Idle until an event happens (e.g. a button is pushed, a menu
is pulled, etc.)
Quit when program (GUI) finishes
Can have multiple loops (count!!)
PyGTK:
TKinter:
PyQT:
[email protected]
gtk.main()
tk.mainloop()
application.exec_()
7/5/10
Main loop and events
Events (examples):
Keyboard (key-pressed, key-released)
Mouse (button-pressed, button-released, motion, wheel, …)
Window/widget (resize, destroy, visibility, activate, deactivate, …)
Etc.
Event modifiers (Shift, Alt, …)
Events emit signals
Can be connected with callbacks (functions, methods)
[email protected]
7/5/10
Callbacks and signals
Callback functions/bindings:
functions, methods
do something when event happens (e.g. button pressed)
PyGTK:
object.connect(signal_name, callback_func, func_data)
def callback_func(widget, callback_data):
def callback_meth(self, widget, callback_data):
Tkinter:
Button(master, text="OK", command=callback)
def callback_func():
PyQT:
connect(widget, signal, callback_func)
[email protected]
7/5/10
Synergy between objects and widgets
Variables are passed automatically within class
refer to them as self.whatever
No need to pass variables
Callback functions
Easy to handle
No need to define callbacks on the fly (lambda functions)
[email protected]
7/5/10
Packing
Add widget to container
Pack widget in boxes
PyGTK:
container_widget.add(widget)
box_object.pack_start(child, expand, fill,
padding)
Tkinter:
object.pack(various_options)
PyQT:
Layout.addWidget(widget)
[email protected]
7/5/10
Packing
Homogeneous
(equal space for
everyone)
HBox(True/False, 0)
Expand, fill
box.pack(expand=,
fill=)
[email protected]
7/5/10
Showing
Widgets itself do not show (neither do they do anything else ->
connect signals!)
Need to show every (!) widget
Can hide widgets
Usually collective show for all
PyGTK:
widget.show()
widget.hide()
widget.show_all()
Tkinter:
Done via mainloop
PyQT:
widget.show()
widget.hide()
[email protected]
7/5/10
Simple example
GUI command input
Schematic in terms
of widgets
window
VBox
HBox
Label
ScrolledWindow
Entry
TextBuffer
Button
[email protected]
7/5/10
Simple example
- make window
# import gtk module
import gtk
# create a main window
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
# set the title
window.set_title("Coot Python Scripting")
# set some more properties (if we wish)
window.set_default_size(400,250)
[email protected]
7/5/10
Simple example
- create widgets
# create other needed widgets: boxes, label, entry, …
vbox = gtk.VBox(homogeneous=False, spacing=0)
hbox = gtk.HBox(False, 0)
label = gtk.Label("Command: ")
entry = gtk.Entry()
scrolled_win = gtk.ScrolledWindow()
text = gtk.TextView()
textbuffer = text.get_buffer()
close_button = gtk.Button("
[email protected]
Close
")
7/5/10
Simple example
- pack it in
window
VBox
HBox
Label
ScrolledWindow
# add vbox in window
Entry
TextBuffer
Button
window.add(vbox)
# pack the hbox and pack into the vbox
hbox.pack_start(child=label,
expand=False, fill=False,
padding=0)
hbox.pack_start(entry, True, True, 0)
vbox.pack_start(hbox, False, False, 5)
[email protected]
7/5/10
Simple example
- pack it in
window
VBox
HBox
Label
ScrolledWindow
Entry
TextBuffer
Button
# pack the scrolled text area
scrolled_win.add(text)
vbox.add(scrolled_win)
# and finally the button
vbox.pack_end(close_button, False,
False, 5)
[email protected]
7/5/10
Simple example
- show it
# show everything connected to the window
window.show_all()
# run the main loop
gtk.main()
[email protected]
7/5/10
Simple example
- making it functional (close button)
Does not perform any function (yet)
Main loop never stops
connect callbacks and signals
# connect close_button (no further args)
close_button.connect(“clicked”, close_callback)
# define callback: destroy window, quit gtk loop
def close_callback(widget):
window.destroy()
gtk.main_quit()
[email protected]
7/5/10
Simple example
- making it functional (destroy window)
Closing window does not finish gtk loop
Deal with delete event
# connect delete_event (two args, but no extra)
window.connect(“delete_event”, delete_event_cb)
# define callback: quit gtk main loop
def delete_event_cb(widget, event):
gtk.main_quit()
[email protected]
7/5/10
Simple example
- making it functional (entry)
# do something with entry when enter is pressed
entry.connect(“activate”, do_callback)
# what to do
def do_callback(widget):
entry_text = widget.get_text()
print “input is”, entry_text
# erase the entry
widget.set_text(“”)
# do something with the text,
# e.g. put in text
# scrolled window
end = textbuffer.get_end_iter()
textbuffer.insert(end,
str(entry_text + "\n"))
[email protected]
7/5/10
Glade (GUI builders)
Inspector
Palette
Editor
Properties
[email protected]
7/5/10
Glade
Output xml file
Two different ‘formats’ (libglade, builder)
==> my_test3.libglade <==
<?xml version="1.0"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy project-wide -->
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property
name="orientation">vertical</property>
[email protected]
==> my_test3.glade <==
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide -->
<object class="GtkWindow" id="window1">
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property
name="orientation">vertical</property>
7/5/10
Connect to python script
Keep GUI/widgets and events separate
Useful for larger projects (easy to add, remove, clean)
import pygtk, gtk
builder = gtk.Builder()
builder.add_from_file(“my_file.glade”)
# get the main window and connect event
window = builder.get_object(“window1”)
window.connect("destroy", gtk.main_quit)
# show and run
window.show_all()
gtk.main()
[email protected]
7/5/10
Glade – connect more signals
Use automatic connection
# dictionary of callbacks (name of signal,
# callback function)
dic = { "on_button1_clicked" : button1_cb,
"on_button2_toggled" : button2_cb,
"on_window1_destroy" : gtk.main_quit }
# define some callbacks
def button1_cb(widget): print “button 1 pressed”
def button2_cb(widget): print “button 2 toggled”
# connect the signals
builder.connect_signals(dic)
[email protected]
7/5/10
(lib)glade
same principle (as for gtk.Builder)
slightly different syntax
[email protected]
7/5/10
The higher end implementations
Combining C/C++/Python/GTK
Python
[email protected]
7/5/10
Coot and Python
SWIG
Python
functions
C(++)-functions
Python
interface
Python
scripting functions
call
return value
Python functions
(objects)
Gtk+ objects
(graphics)
[email protected]
7/5/10
Main Menubar
Main Menubar
[email protected]
7/5/10
Accessing existing menus
Addition of individual
menu items
[email protected]
7/5/10
Main Toolbar
Main Toolbar
[email protected]
7/5/10
Main Toolbar
Pop-up menu
to manage
toolbuttons
Extra toolbuttons
[email protected]
7/5/10
Some hints for your own design:
Organize
[email protected]
7/5/10
Some hints for your own design:
group related items
[email protected]
7/5/10
Some hints for your own design:
keep it simple
[email protected]
7/5/10
Some hints for your own design:
don’t reinvent the wheel – keep
conventions
Use standard menu items
Use standard icons
Carefully choose colours:
colour blindness!!
[email protected]
7/5/10
Further information on GUI/Python/TKs
GUI
PyGTK, Glade
http://www.guidebookgallery.org/index
http://www.asktog.com/basics/firstPrinciples.html
http://web.cs.wpi.edu/~matt/courses/cs563/talks/smartin/int_design.html
http://www-01.ibm.com/software/ucd/designconcepts.html
http://library.gnome.org/devel/hig-book/stable/intro.html.en
http://www.pygtk.org/
http://glade.gnome.org/
http://live.gnome.org/Glade/Tutorials
http://www.micahcarrick.com/12-24-2007/gtk-glade-tutorial-part-1.html
PyQT
http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html
http://www.commandprompt.com/community/pyqt/
http://www.cs.usfca.edu/~afedosov/qttut/
[email protected]
7/5/10
Acknowledgements
http://www.biop.ox.ac.uk/coot/
or
Paul Emsley
Kevin Cowtan
Eleanor Dodson
Keith Wilson
BBSRC & CCP4 funding
Libraries, dictionaries
Alexei Vagin, Eugene Krissinel, Stuart McNicholas
Dunbrack, Richardsons
Coot Builders and Testers
William Scott, Ezra Peisach
York YSBL, Dundee, Glasgow (early adopters)
Coot Mailing List subscribers
[email protected]
Google: Coot
or
http://www.ysbl.ac.uk/~lohkamp/coot
7/5/10
DEMO?
[email protected]
7/5/10
Hierarchy
[email protected]
7/5/10
[email protected]
7/5/10