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)
Bernhard.Lohkamp@ki.se
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, …
Bernhard.Lohkamp@ki.se
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!?)
Bernhard.Lohkamp@ki.se
7/5/10
What do you prefer?
>>> delete_residue(10)
Bernhard.Lohkamp@ki.se
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
Bernhard.Lohkamp@ki.se
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
Bernhard.Lohkamp@ki.se
7/5/10
Windows manager/Desktop
Forms of interaction
events in context
Human Interface
Device (HID)
control
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
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
Bernhard.Lohkamp@ki.se
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
Bernhard.Lohkamp@ki.se
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
?
Bernhard.Lohkamp@ki.se
7/5/10
Nomenclature/Widgets
Widget: “windowing gadget”, which means “a useful
building block (gadget) to make a windowing system”.
Hierarchy (exemplified):
Bernhard.Lohkamp@ki.se
7/5/10
Widget examples
Top level
(independent
widgets):
Main window
Various (predefined) dialogs
Bernhard.Lohkamp@ki.se
7/5/10
Dialogs (I)
Info (Message) dialog
Dialog box
Bernhard.Lohkamp@ki.se
7/5/10
Dialogs (II)
About dialog
Assistant
Bernhard.Lohkamp@ki.se
7/5/10
Dialogs (III)
Selection dialogs
Files
Colours
Fonts
….
Bernhard.Lohkamp@ki.se
7/5/10
Containers/Layout
Boxes
Vertical
Horizontal
Combined (grid, table)
Scrolled window
Tabbed
widgets/notebook
Frames
Panes
Bernhard.Lohkamp@ki.se
7/5/10
Boxed layout
Bernhard.Lohkamp@ki.se
7/5/10
Tabbed window/Notebook
Bernhard.Lohkamp@ki.se
tabs
7/5/10
Buttons
Button
Toggle button
Check button
Spin button
Radio button
Pre-defined buttons
Files
Colours
Fonts
…
Bernhard.Lohkamp@ki.se
7/5/10
Input & Entries (I)
Menu
Toolbar
Bernhard.Lohkamp@ki.se
7/5/10
Menus
Submenus
Icons
Accelerators
Bernhard.Lohkamp@ki.se
7/5/10
Context menu
Shown upon
event (usually
mouse click)
Bernhard.Lohkamp@ki.se
7/5/10
Toolbars
Like menus but contain icons/buttons
Short-cut for frequently used functions
Bernhard.Lohkamp@ki.se
7/5/10
Toolbar
Bernhard.Lohkamp@ki.se
7/5/10
Change
Style
Bernhard.Lohkamp@ki.se
7/5/10
Text
only
Bernhard.Lohkamp@ki.se
7/5/10
Text
and
Icons
Bernhard.Lohkamp@ki.se
7/5/10
Toolbar
Detouch/
Handle
Bernhard.Lohkamp@ki.se
7/5/10
detouched
Bernhard.Lohkamp@ki.se
7/5/10
Input & Entries (I)
Combobox –
spin button
Simple Entry:
Bernhard.Lohkamp@ki.se
7/5/10
Input & Entries (II)
Entry:
Auto-completion possible
Sliders
Bernhard.Lohkamp@ki.se
7/5/10
List/Tree structures
Bernhard.Lohkamp@ki.se
7/5/10
Can include: icons, buttons, …
Bernhard.Lohkamp@ki.se
7/5/10
Tree-> expansion
Bernhard.Lohkamp@ki.se
7/5/10
Miscellaneous widgets
Progress bar
Status bar
Bernhard.Lohkamp@ki.se
7/5/10
Canvas
Drawing area
Canvas/cairo drawing
(e.g. PyGoocanvas)
OpenGL drawing (e.g.
PyOpenGL, PyGtkGLExt)
Can be interactive
Bernhard.Lohkamp@ki.se
7/5/10
Tooltips
Pop ups with text
(upon mouse over)
Helps to explore the
GUI without reading
help files
Use whenever you
can (!?)
Bernhard.Lohkamp@ki.se
7/5/10
GUI design
What makes a good UI?
Simple
Intuitive
Respects the commonly accepted conventions
Visually organized
Native look
Bernhard.Lohkamp@ki.se
7/5/10
Designing UIs
Two levels:
Graphical: visual aspect
Events: Functionality
Basic blocks = widgets
Making an application react to events = binding
Bernhard.Lohkamp@ki.se
7/5/10
General concepts
Main loop and events
Packing
Showing
How to do.
Bernhard.Lohkamp@ki.se
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:
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
7/5/10
Packing
Homogeneous
(equal space for
everyone)
HBox(True/False, 0)
Expand, fill
box.pack(expand=,
fill=)
Bernhard.Lohkamp@ki.se
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()
Bernhard.Lohkamp@ki.se
7/5/10
Simple example
GUI command input
Schematic in terms
of widgets
window
VBox
HBox
Label
ScrolledWindow
Entry
TextBuffer
Button
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
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("
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
7/5/10
Simple example
- show it
# show everything connected to the window
window.show_all()
# run the main loop
gtk.main()
Bernhard.Lohkamp@ki.se
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()
Bernhard.Lohkamp@ki.se
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()
Bernhard.Lohkamp@ki.se
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"))
Bernhard.Lohkamp@ki.se
7/5/10
Glade (GUI builders)
Inspector
Palette
Editor
Properties
Bernhard.Lohkamp@ki.se
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>
Bernhard.Lohkamp@ki.se
==> 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()
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
7/5/10
(lib)glade
same principle (as for gtk.Builder)
slightly different syntax
Bernhard.Lohkamp@ki.se
7/5/10
The higher end implementations
Combining C/C++/Python/GTK
Python
Bernhard.Lohkamp@ki.se
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)
Bernhard.Lohkamp@ki.se
7/5/10
Main Menubar
Main Menubar
Bernhard.Lohkamp@ki.se
7/5/10
Accessing existing menus
Addition of individual
menu items
Bernhard.Lohkamp@ki.se
7/5/10
Main Toolbar
Main Toolbar
Bernhard.Lohkamp@ki.se
7/5/10
Main Toolbar
Pop-up menu
to manage
toolbuttons
Extra toolbuttons
Bernhard.Lohkamp@ki.se
7/5/10
Some hints for your own design:
Organize
Bernhard.Lohkamp@ki.se
7/5/10
Some hints for your own design:
group related items
Bernhard.Lohkamp@ki.se
7/5/10
Some hints for your own design:
keep it simple
Bernhard.Lohkamp@ki.se
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!!
Bernhard.Lohkamp@ki.se
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/
Bernhard.Lohkamp@ki.se
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
Bernhard.Lohkamp@ki.se
Google: Coot
or
http://www.ysbl.ac.uk/~lohkamp/coot
7/5/10
DEMO?
Bernhard.Lohkamp@ki.se
7/5/10
Hierarchy
Bernhard.Lohkamp@ki.se
7/5/10
Bernhard.Lohkamp@ki.se
7/5/10