Menus
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.
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).
- Printer-friendly version
- Login to post comments
Recent comments
2 years 8 weeks ago
2 years 17 weeks ago
3 years 1 week ago
3 years 5 weeks ago
3 years 9 weeks ago
3 years 10 weeks ago
3 years 10 weeks ago
3 years 14 weeks ago
3 years 14 weeks ago
3 years 15 weeks ago