2012-06-21 19 views
8

calendar-menu-screenshot¿Mostrando un gtk.Calendar en un menú?

Quiero construir un menú contextual con un elemento de menú para seleccionar una fecha. (El caso de uso es seleccionar un grupo de elementos en una vista de árbol y luego establecer una nueva fecha de vencimiento para todos los artículos.)

Como un elemento de menú es un Gtk.Bin, puedo especificar cualquier widget en lugar de una etiqueta. Sin embargo, no puedo interactuar con el widget. Si hago clic en cualquier parte del menú, el elemento de menú recibe el clic. Entonces, no puedo seleccionar una fecha en particular, ni navegar meses o años. ¿Cómo puedo hacer que el calendario obtenga la actividad del mouse?

Además, hay un relleno externo alrededor del exterior del calendario, y cuando se coloca sobre él se vuelve naranja. ¿Cómo puedo eliminar el relleno y/o no resaltar el color naranja?

#!/usr/bin/env python 

import gobject 
import pygtk 
pygtk.require('2.0') 
import gtk 
import time 


class ContextMenu(gtk.Menu): 
    def __init__(self): 
     gtk.Menu.__init__(self) 

    def add_calendar_submenu_item(self, text, callback, uuids, data=None): 
     calendar = gtk.Calendar() 
     calendar.show() 
     calendar_item = gtk.MenuItem() 
     calendar_item.add(calendar) 
     calendar_item.show() 

     submenu = gtk.Menu() 
     submenu.append(calendar_item) 
     submenu_item = gtk.MenuItem("%s..." %(text)) 
     submenu_item.set_submenu(submenu) 
     submenu_item.show() 
     submenu_item.connect("activate", self.on_calendar_activate) 
     self.append(submenu_item) 

    def on_calendar_activate(self, widget): 
     print "activate" 


if __name__ == "__main__": 
    class CalendarExample: 
     def __init__(self): 
      window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
      window.set_title("Calendar Example") 
      window.set_border_width(5) 
      window.set_size_request(200, 100) 
      window.set_resizable(False) 
      window.stick() 
      window.connect("destroy", lambda x: gtk.main_quit()) 

      menu = ContextMenu() 
      menu.add_calendar_submenu_item("date", self.on_date, ['123']) 

      root_menu = gtk.MenuItem("Calendar Menu") 
      root_menu.show() 
      root_menu.set_submenu(menu) 

      vbox = gtk.VBox(False, 10) 
      window.add(vbox) 
      vbox.show() 

      menu_bar = gtk.MenuBar() 
      vbox.pack_start(menu_bar, False, False, 2) 
      menu_bar.append (root_menu) 
      menu_bar.show() 

      button = gtk.Button("Push Me") 
      button.connect("clicked", self.on_menu_push, menu) 
      vbox.pack_start(button, False, True, 10) 
      button.show() 

      window.show() 

     def on_menu_push(self, widget, menu): 
      menu.popup(None, None, None, 0, 0) 

     def on_action(self, widget, uuids, text): 
      print "Item %s pressed" %(text) 

     def on_date(self, widget, uuids, text): 
      print "Calendar activated with %s" %(text) 

    CalendarExample() 
    gtk.main() 

[Actualización]

Lo que voy a es algo parecido al indicador de fecha menú de Ubuntu/calendario de tiempo.

Ubuntu Calendar

+0

Eso es feo, ya que no hay más elementos de menú, ¿por qué acaba de poner el calendario dentro de una ventana emergente? – saeedgnu

+0

También puede poner muchos botones o incluso una barra de herramientas en esa ventana emergente (si desea tener más acciones en la ventana emergente) – saeedgnu

+0

Intenté primero un acercamiento de ventana emergente, pero al colocar el menú emergente en la posición correcta parecía que sería demasiado complicado , especialmente teniendo en cuenta que las dimensiones del menú pueden variar según el idioma del usuario y las preferencias de fuente, etc. Lo mantendré como una opción alternativa si no se puede hacer que lo anterior funcione. – bryce

Respuesta

6

Como ya se ha mencionado por ilius en los comentarios, menú no está diseñado para sostener widget de arbitraria. También se ha discutido en this SO post. Tendrá que ir con la opción de la ventana emergente.
El applet del reloj en Ubuntu que está tratando de emular utiliza la ventana emergente. Puede verificar esto usando xwininfo. Si tiene el calendario desplegado y luego selecciónelo (para la utilidad xwininfo), puede ver que es una ventana separada y no es lo mismo que el panel.
Además, esto se puede confirmar mirando source. El applet del reloj que se muestra es toggle button que en toggle muestra/oculta la ventana emergente con calendario (más preciso es un widget personalizado CalendarWindow que se extiende GtkWindow y adds GtkCalendar de manera apropiada cuando se crea). Una aplicación crudo de la misma idea sobre la base de su código es el siguiente (Por favor, perdona mi conocimiento limitado pitón):

#!/usr/bin/env python 

import gobject 
import pygtk 
pygtk.require('2.0') 
import gtk 
import time 

class CalendarExample: 
    def __init__(self): 
     window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
     window.set_title("Calendar Example") 
     window.set_border_width(5) 
     window.set_size_request(200, 100) 
     window.set_resizable(False) 
     window.stick() 
     window.connect("destroy", lambda x: gtk.main_quit()) 

     vbox = gtk.VBox(False, 10) 
     window.add(vbox) 

     # Could have used WINDOW_POPUP to create below window, but trying to emulate the same properties as the window 
     # in applet. 
     cal_window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
     cal_window.set_decorated(False) 
     cal_window.set_resizable(False) 
     cal_window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK) 
     cal_window.stick() 
     cal_vbox = gtk.VBox(False, 10) 
     cal_window.add(cal_vbox) 
     cal_vbox.pack_start(gtk.Calendar(), True, False, 0) 
     cal_vbox.pack_start(gtk.Button("Dummy locations"), True, False, 0) 

     toggle_button = gtk.ToggleButton("Show Calendar") 
     vbox.pack_start(toggle_button, False, True, 10) 
     toggle_button.connect("toggled", self.on_toggle, cal_window) 

     # Track movements of the window to move calendar window as well 
     window.connect("configure-event", self.on_window_config, toggle_button, cal_window) 
     window.show_all() 

    # Calendar window co ordinates without off-screen correction: 
    #   Window origin (x, y) 
    #   | 
    #   V 
    #   --------------------------------- 
    #   | Main Window     | 
    #   |        | 
    #   |        | 
    #   |Toggle button's (x, y)   | 
    #   |(relative to parent window) | 
    #   | |        | 
    #   | V        | 
    #   | ......................... | 
    # Calendar | | Toggle Button   | | 
    # window's | |       | | 
    # (x, y)---+> ......................... | 
    #   |(Calendar window will be here) | 
    #   |        | 
    #   |        | 
    #   --------------------------------- 
    # Calendar Window's screen coordinates: 
    # x = Window's origin x + Toggle Button's relative x 
    # y = Window's origin y + Toggle Button's relative y + Toggle Button's height 

    # "toggle" callback which shows & hides calendar window. 
    def on_toggle(self, toggle_button, cal_window): 
     if toggle_button.get_active(): 
      rect = toggle_button.get_allocation() 
      main_window = toggle_button.get_toplevel() 
      [win_x, win_y] = main_window.get_window().get_origin() 
      cal_x = win_x + rect.x 
      cal_y = win_y + rect.y + rect.height 
      [x, y] = self.apply_screen_coord_correction(cal_x, cal_y, cal_window, toggle_button) 
      cal_window.move(x, y) 
      cal_window.show_all() 
      toggle_button.set_label("Hide Calendar") 
     else: 
      cal_window.hide_all() 
      toggle_button.set_label("Show Calendar") 

    # "configure-event" callback of main window, try to move calendar window along with main window. 
    def on_window_config(self, widget, event, toggle_button, cal_window): 
     # Maybe better way to find the visiblilty 
     if cal_window.get_mapped(): 
      rect = toggle_button.get_allocation() 
      cal_x = event.x + rect.x 
      cal_y = event.y + rect.y + rect.height 
      [x, y] = self.apply_screen_coord_correction(cal_x, cal_y, cal_window, toggle_button) 
      cal_window.move(x, y) 

    # This function "tries" to correct calendar window position so that it is not obscured when 
    # a portion of main window is off-screen. 
    # Known bug: If the main window is partially off-screen before Calendar window 
    # has been realized then get_allocation() will return rect of 1x1 in which case 
    # the calculations will fail & correction will not be applied 
    def apply_screen_coord_correction(self, x, y, widget, relative_widget): 
     corrected_y = y 
     corrected_x = x 
     rect = widget.get_allocation() 
     screen_w = gtk.gdk.screen_width() 
     screen_h = gtk.gdk.screen_height() 
     delta_x = screen_w - (x + rect.width) 
     delta_y = screen_h - (y + rect.height) 
     if delta_x < 0: 
      corrected_x += delta_x 
     if corrected_x < 0: 
      corrected_x = 0 
     if delta_y < 0: 
      corrected_y = y - rect.height - relative_widget.get_allocation().height 
     if corrected_y < 0: 
      corrected_y = 0 
     return [corrected_x, corrected_y] 

if __name__ == "__main__": 
    CalendarExample() 
    gtk.main() 

Espero que esto ayude!

+0

Esto ayuda, con c también ... –

Cuestiones relacionadas