Skip navigation.
Home

Menus

strict warning: Only variables should be passed by reference in /home/tal/rox/htdocs/desktop/modules/book/book.module on line 559.

Here we give our clock applet/application a popup menu.

If you have trouble understanding how the clock part works, read the (very short) applet tutorial.

menus

The application so far

Here's our old clock application, but written using a more object-oriented style. ClockWindow is defined as a special type of Window (ie, one which displays a clock, by adding a Clock widget when it's created). The functionality is the same as before. AppRun now looks like this:

#!/usr/bin/env python
 
import findrox; findrox.version(1, 9, 8)
import rox
import clock
 
class ClockWindow(rox.Window):
        def __init__(self):
                rox.Window.__init__(self)
                self.add(clock.Clock())
 
window = ClockWindow()
window.show_all()
rox.mainloop()

A Clock widget is a special type of Label (one which displays the current time). It's defined in a new clock.py file:

import time
import rox
from rox import g
 
class Clock(g.Label):
        def __init__(self):
                g.Label.__init__(self, '')
                self.update_time()
                timeout = g.timeout_add(1000, self.update_time)
                def destroyed(self):
                        g.timeout_remove(timeout)
                self.connect('destroy', destroyed)
 
        def update_time(self):
                self.set_text(time.ctime())
                return True

Adding a menu

Because keyboard short-cuts can be bound to menu items, we need to say where these settings should be loaded from and saved to. We do this using set_save_name() (in this case, <Choices>/MiniClock/menus will be used).
Then, we create the menu. Each menu we define has to be given a unique name (here main). This used to identify it in the shortcuts save file. Each item in the menu has a path (such as /Options) and the name of a method to call to handle it. The third argument is the type of the item (used for submenus and other special items). A default key can be given with the optional fourth argument.

#!/usr/bin/env python
 
import findrox; findrox.version(1, 9, 8)
import rox
from rox import g, Menu
import clock
Menu.set_save_name('MiniClock')
 
menu = Menu.Menu('main', [
        ('/Options',            'show_options', ''),
        ('/Quit',               'quit',         ''),
        ])

We need to detect button-3 clicks on the window, and open the menu when we get one. By default, windows aren't sensitive to button events, so we need to use add_events to change that. Now, any button press over the window will cause a button-press-event signal to be emitted.

We then connect to the button-press-event signal, check that button-3 was used, and open the menu if so. We pass self to the popup function; this is the object which will actually implement the various menu functions (in our case, this is the ClockWindow).

Finally, we 'attach' the menu to the window. This means that keypress events on the window will be checked against shortcuts defined in the menu. We pass both the widget to listen for events on (window) and the object which implements the menu functions (window again).

class ClockWindow(rox.Window):
        def __init__(self):
                rox.Window.__init__(self)
                self.add(clock.Clock())
                self.add_events(g.gdk.BUTTON_PRESS_MASK)
                self.connect('button-press-event', self.button_press)
                menu.attach(self, self)
 
        def button_press(self, window, event):
                if event.button == 3:
                        menu.popup(self, event)
 
window = ClockWindow()
window.show_all()
rox.mainloop()

Notice that we only create the menu once, but must do the signal and attaching code for every window created (in a multi-window application).

Implementing the menu functions

You should now be able to open the menu and choose something. When you do, an error box appears complaining that the function isn't implemented.

Unless you've got user-definable shortcuts disabled, you should also be able to trigger the error by setting a shortcut (open the menu, point at Quit and press Ctrl-Q, for example) and then pressing the shortcut when the window has the focus. Shortcuts will be automatically loaded and saved.

The error box is rather fun; if you click on the Details button then you get a complete stack-trace of where the error happened. When you select a stack frame, you are shown all the local variables for that frame and you can use the box at the bottom to evaluate expressions in the context of that frame. This
can be very useful for debugging.

In our case, however, it's obvious what the problem is (we haven't written the code yet ;-). We just need to define functions with the names given when we created the menu, eg:

        def quit(self):
                self.destroy()
 
        def show_options(self):
                rox.edit_options()

We'll see how to add the options dialog box in the next tutorial.

Note: you should also connect to the popup-menu signal. This is called when the user presses the open-menu key (some keyboards have a special key for this, or Shift+F10 is the default). This is mainly for disabled users (without mouse access). However, you still have to connect to button-press-event as well, because when the mouse is used you need to pass the event to popup (CVS ROX-Lib allows it to be None for the keyboard case).

Syndicate content