Python-Ref > GUI programming with PyGTK > Real world example > Cookbook GUI
 
 

^^->

Cookbook GUI

Real world example of a simple cookbook management program.
This example builds on the code that was shown in Real world example. The cookbook code (module) is an exact copy of the code in example Cookbook II., it was only renamed so that it may be imported as a module.
The following code adds a very simple GUI to the cookbook. It can handle reading and writing of files, but has no viewing or editing capabilities.
Expand/Shrink
<cookbook>
  <recipe>
    <title>Cheese cake</title>
    <text>Here comes the description for preparation of a cheese cake.</text>
    <ingredient amount="500g">soft cheese</ingredient>
    <ingredient amount="2">eggs</ingredient>
    <ingredient amount="100g">sugar</ingredient>
    <ingredient>raisins</ingredient>
  </recipe>
  <recipe>
    <title>Rosted duck</title>
    <text>Here we describe how to prepare a roasted duck.</text>
    <ingredient amount="1">duck</ingredient>
    <ingredient>cumin</ingredient>
    <ingredient amount="1">apple</ingredient>
  </recipe>
</cookbook>
  1   import xml.dom.minidom as dom
  2   
  3   class Recipe( object):
  4   
  5     dom_element_name = "recipe"
  6   
  7     def __init__( self, title="", text=""):
  8       self.title = title
  9       self.text = text
 10       self.ingredients = []
 11   
 12     def __str__( self):
 13       return "Recipe: %s (%d ingredients)" % (self.title, len( self.ingredients))
 14   
 15     def read_dom_element( self, e):
 16       titles = e.getElementsByTagName( "title")
 17       if not titles:
 18         raise ValueError( "Could not find title in the dom element")
 19       elif len( titles) > 1:
 20         print >> sys.stderr, "Warning: more than one title in dom element\n", titles
 21       self.title = get_all_text_from_element( titles[0])
 22       texts = e.getElementsByTagName( "text")
 23       if texts:
 24         self.text = get_all_text_from_element( texts[0])
 25       for ie in e.getElementsByTagName( Ingredient.dom_element_name):
 26         i = Ingredient()
 27         i.read_dom_element( ie)
 28         self.add_ingredient( i)
 29   
 30     def get_dom_element( self, doc):
 31       el = doc.createElement( self.dom_element_name)
 32       for attr_name in ['title','text']:
 33         attr_el = doc.createElement( attr_name)
 34         attr_el.appendChild( doc.createTextNode( getattr( self, attr_name)))
 35         el.appendChild( attr_el)
 36       for i in self.ingredients:
 37         ie = i.get_dom_element( doc)
 38         el.appendChild( ie)
 39       return el
 40   
 41     def add_ingredient( self, i):
 42       self.ingredients.append( i)
 43   
 44   
 45   class Ingredient( object):
 46   
 47     dom_element_name = "ingredient"
 48   
 49     def __init__( self, name="", amount=""):
 50       self.name = name
 51       self.amount = amount
 52   
 53     def __str__( self):
 54       if self.amount:
 55         return "%s %s" % (self.amount, self.title)
 56       else:
 57         return "%s" % self.title
 58   
 59     def read_dom_element( self, e):
 60       if e.hasAttribute( "amount"):
 61         self.amount = e.getAttribute( "amount")
 62       self.name = get_all_text_from_element( e)
 63   
 64     def get_dom_element( self, doc):
 65       el = doc.createElement( self.dom_element_name)
 66       if self.amount:
 67         el.setAttribute( "amount", str( self.amount))
 68       el.appendChild( doc.createTextNode( self.name))
 69       return el
 70   
 71   
 72   
 73   class CookBook( object):
 74   
 75     def __init__( self):
 76       self.recipes = []
 77   
 78     def __str__( self):
 79       return "Cookbook: %d recipes" % len( self.recipes)
 80   
 81     def read_xml_file( self, filename):
 82       doc = dom.parse( filename)
 83       for el in doc.getElementsByTagName( Recipe.dom_element_name):
 84         rec = Recipe()
 85         rec.read_dom_element( el)
 86         self.recipes.append( rec)
 87   
 88     def write_xml_file( self, filename):
 89       doc = dom.Document()
 90       root = doc.createElement( "cookbook")
 91       doc.appendChild( root)
 92       for rec in self.recipes:
 93         e = rec.get_dom_element( doc)
 94         root.appendChild( e)
 95       f = file( filename, "w")
 96       f.write( doc.toxml())
 97   
 98     def add_recipe( self, recipe):
 99       self.recipes.append( recipe)
100   
101   # help functions
102   
103   def get_all_text_from_element( el):
104       text = ""
105       for ch in el.childNodes:
106           if isinstance( ch, dom.Element):
107               text += get_all_text_from_element( ch)
108           if isinstance( ch, dom.Text):
109               text += ch.data
110       return text
111       
112   # end of help functions
113   
114   
115   if __name__ == "__main__":
116     c = CookBook()
117     c.read_xml_file( "infiles/cookbook2.xml")
118     print c
119     for rec in c.recipes:
120       print rec
121     new = Recipe( "Potato dumplings")
122     new.text = "Preparation instructions for czech potato dumplings"
123     c.add_recipe( new)
124     new.add_ingredient( Ingredient( name="potatoes", amount="500g"))
125     c.write_xml_file( "cookbook2-2.xml")
126     print c
  1   import pygtk
  2   pygtk.require('2.0')
  3   # import the GTK module
  4   import gtk
  5   
  6   from cookbook3_1 import CookBook
  7   
  8   class CookBookGUI:
  9   
 10     version = "3.1"
 11   
 12     def __init__( self):
 13       self.cookbook = CookBook() 
 14       self.window = gtk.Window()
 15       self.window.set_title( "CookBookGUI, version %s" % self.version)
 16       self.window.set_size_request( 400, 300)
 17       self.window.connect( "destroy", self.destroy)
 18       self.create_interior()
 19       self.window.show_all()
 20       self.update_status()
 21   
 22     def create_interior( self):
 23       self.mainbox = gtk.VBox()
 24       self.window.add( self.mainbox)
 25       # menu
 26       self.menu_bar = self.create_menu_bar()
 27       self.menu_bar.show()
 28       self.mainbox.pack_start( self.menu_bar, expand=False, fill=False)
 29       # label for status
 30       self.status = gtk.Label()
 31       self.status.set_alignment( 0.98, 0)
 32       self.mainbox.pack_end( self.status, expand=False, fill=False)
 33       self.status.show()
 34       # show the box
 35       self.mainbox.show()
 36   
 37     def create_menu_bar( self):
 38       # the file menu
 39       file_menu = gtk.Menu()
 40       open_item = gtk.ImageMenuItem( stock_id=gtk.STOCK_OPEN) 
 41       open_item.connect( "activate", self.open_file)
 42       self.save_item = gtk.ImageMenuItem( stock_id=gtk.STOCK_SAVE) 
 43       self.save_item.connect( "activate", self.save_file)
 44       quit_item = gtk.ImageMenuItem( stock_id=gtk.STOCK_QUIT) 
 45       quit_item.connect( "activate", self.quit)
 46       for i in [open_item, self.save_item, gtk.SeparatorMenuItem(), quit_item]:
 47         i.show()
 48         file_menu.append( i)
 49       # menu bar
 50       menu_bar = gtk.MenuBar()
 51       file_menu_item = gtk.MenuItem( "File")
 52       file_menu_item.set_submenu( file_menu)
 53       menu_bar.append( file_menu_item)
 54       return menu_bar
 55   
 56     def update_status( self):
 57       self.status.set_markup( "<b>%d</b> recipes" % len( self.cookbook.recipes))
 58       if len( self.cookbook.recipes) > 0:
 59         self.save_item.set_sensitive( True) 
 60       else:
 61         self.save_item.set_sensitive( False) 
 62   
 63     def main( self):
 64       gtk.main()
 65   
 66     def destroy( self, w):
 67       gtk.main_quit()
 68   
 69     def open_file( self, w, data=None):
 70       d = gtk.FileChooserDialog( title="Select a file",
 71                                  parent=self.window,
 72                                  action=gtk.FILE_CHOOSER_ACTION_OPEN,
 73                                  buttons=(gtk.STOCK_OK,gtk.RESPONSE_ACCEPT,
 74                                           gtk.STOCK_CANCEL,gtk.RESPONSE_REJECT)
 75                                  )
 76       # create filters
 77       f1 = gtk.FileFilter()
 78       f1.set_name( "All files")
 79       f1.add_pattern( "*")
 80       f2 = gtk.FileFilter()
 81       f2.set_name( "XML files")
 82       f2.add_pattern( "*.xml")
 83       d.add_filter( f2)
 84       d.add_filter( f1)
 85       # run the dialog
 86       ok = d.run()
 87       if ok != gtk.RESPONSE_ACCEPT:
 88         d.destroy()
 89         return
 90       filename = d.get_filename()
 91       d.destroy()
 92       self.cookbook.read_xml_file( filename)
 93       self.update_status()
 94   
 95     def save_file( self, w, data=None):
 96       d = gtk.FileChooserDialog( title="Select a file to save in..",
 97                                  parent=self.window,
 98                                  action=gtk.FILE_CHOOSER_ACTION_SAVE,
 99                                  buttons=(gtk.STOCK_OK,gtk.RESPONSE_ACCEPT,
100                                           gtk.STOCK_CANCEL,gtk.RESPONSE_REJECT)
101                                  )
102       # create filters
103       f1 = gtk.FileFilter()
104       f1.set_name( "All files")
105       f1.add_pattern( "*")
106       f2 = gtk.FileFilter()
107       f2.set_name( "XML files")
108       f2.add_pattern( "*.xml")
109       d.add_filter( f2)
110       d.add_filter( f1)
111       # run the dialog
112       ok = d.run()
113       if ok != gtk.RESPONSE_ACCEPT:
114         d.destroy()
115         return
116       filename = d.get_filename()
117       d.destroy()
118       self.cookbook.write_xml_file( filename)
119   
120     def quit( self, w, data=None):
121       self.destroy( w)
122   
123   if __name__ == "__main__":
124     m = CookBookGUI()
125     m.main()
Screenshot:
Program screenshot cookbook_gui3_1.pngProgram screenshot cookbook_gui3_1a.png
Doba běhu: 1670.4 ms