📜 ⬆️ ⬇️

Introduction to pygtk / gtkbuilder: write a calculator

Let us analyze the creation of the interface in pygtk using the example of the most primitive calculator. Lots of pictures, some code.
gtkbuilder is the most progressive format for describing gtk interface in xml,
if you previously used libglade, you can convert the .glade file to the new format with libglade-convert

All this can work under windows, you need to install pygtk and all the necessary libraries; in the future, you can pack everything with py2exe.
We start glade-3

Create a window, put a table in it

Insert the Entry into the top left cell, put the right in the packing
attachment-4 to stretch it into 4 columns
In general we set Editable: No


For window1 in signals, enter in the key-press-event "key_press";
in destroy - “quit” (so that when you close the window, we exit the program)
key_press and quit is the name of the methods in our code that will be
called when performing certain actions, in this case, pressing the button and closing the window.

Add buttons

The rest we will generate in the code.
For all buttons except "=" and reset, set signals / clicked "put_text"
For "=" - “calculate”, for reset - “reset”

We set common / accelerators for buttons so that we clicked on
when you click corresponding. keys, for "=" it will be "=" and Return, for reset not
expose nothing (we want to escape and do it in code)

Save to demo.ui file
Write the code

If you have questions, run “devhelp” and read the documentation.


Notice the EntryDescriptor is a Python descriptor that
allows us to work with values ​​in gtk much more conveniently. Entry
')
The rest should be clear from the comments.

Note: the calculator works with integers and integer division,
those. 5/2 = 2 :) This is an article about creating an interface, I did the rest
as simple as possible so as not to distract.

 #! / usr / bin / env python
 # coding: utf-8
 # vim: ai ts = 4 sts = 4 et sw = 4

 import gtk
 import os

 class EntryDescriptor (object):
     def __init __ (self, object_name):
         self.object_name = object_name
     def __get __ (self, obj, cls):
         return obj.get_object (self.object_name) .get_text ()
     def __set __ (self, obj, value):
         obj.get_object (self.object_name) .set_text (value)


 class Calculator (gtk.Builder):
     def __init __ (self):
         super (Calculator, self) .__ init __ ()
         # load demo.ui
         self.add_from_file (os.path.join (os.path.dirname (__ file __), 'demo.ui'))
         # connect the signal handlers described in demo.ui to the self object
         self.connect_signals (self)
         # create a group of hot keys, for keys with numbers and connect it to the window
         agroup = gtk.AccelGroup ()
         self.window1.add_accel_group (agroup)
         # create buttons, hang hotkeys on them and place them in table1
         for i in xrange (10):
             btn = gtk.Button (str (i))
             btn.connect ('clicked', self.put_text)
             btn.add_accelerator ('clicked', agroup, ord (str (i)), 0, 0)
             y, x = i / 3, i% 3
             self.table1.attach (btn, x, x + 1, y + 1, y + 2)
         # show the window and all the widgets on it
         self.window1.show_all ()

     def __getattr __ (self, attr):
         # it is more convenient to write self.window1 than self.get_object ('window1')
         obj = self.get_object (attr)
         if not obj:
             raise AttributeError ('object% r has no attribute% r'% (self, attr))
         setattr (self, attr, obj)
         return obj

     # Python descriptor that allows us to work with values ​​in gtk much more conveniently. Entry
     expr = EntryDescriptor ('entry1')
    
     def calculate (self, widget = None):
         if not self.expr: return
         try:
             self.expr = str (eval (self.expr))
         except Exception, e:
             # we can close to zero, etc.
             print e

     def reset (self, widget):
         self.expr = ''

     def quit (self, widget):
         gtk.main_quit ()

     def put_text (self, widget):
         text = widget.get_label ()
         expr = self.expr
         if not expr [-1:]. isdigit () and not text.isdigit ():
             # so that you cannot write 8 / * 2, etc.
             return
         self.expr + = text

     def key_press (self, widget, event):
         # get the name of the button from its code
         key = gtk.gdk.keyval_name (event.keyval)
         if key == 'BackSpace':
             if self.expr:
                 self.expr = self.expr [: - 1]
         elif key == 'Escape':
             self.reset (None)

 if __name__ == '__main__':
     calculator = Calculator ()
     gtk.main ()


demo.py
demo.ui

Run python demo.py:


If the topic is interesting, in the next article I think to describe the creation of a browser based on pygtk and pywebkitgtk , for which you can write extensions in python including. in the interactive console (ipython); integration of python and javascript.

Source: https://habr.com/ru/post/87327/


All Articles