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