2012-06-21 10 views
8

calendar-menu-screenshotMostrando un gtk.Calendar in un menu?

Voglio costruire un menu di scelta rapida con una voce di menu per selezionare una data. (Il caso d'uso è selezionare un gruppo di elementi in una vista ad albero e quindi impostare una nuova data di scadenza per tutti gli articoli.)

Poiché un menu è un Gtk.Bin, è possibile specificare qualsiasi widget al posto di un'etichetta. Tuttavia, non riesco a far interagire con il widget. Se faccio clic in qualsiasi punto del menu, il menu visualizza il clic. Quindi, non posso selezionare una data particolare, né navigare mesi o anni. Come posso fare in modo che il calendario ottenga l'attività del mouse?

Inoltre, vi è una spaziatura esterna estranea al calendario e al passaggio del mouse diventa arancione. Come posso rimuovere l'imbottitura e/o non fare l'evidenziazione arancione?

#!/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() 

[Update]

Quello che sto andando per è qualcosa di simile a indicatore di data del menu di Ubuntu/calendario di tempo.

Ubuntu Calendar

+0

Questo è brutto, dal momento che non ci sono più voci di menu, perché è sufficiente inserire il calendario in una finestra popup? – saeedgnu

+0

Puoi anche mettere molti pulsanti o anche una barra degli strumenti in quella finestra popup (se vuoi avere più azioni nel popup) – saeedgnu

+0

Ho tentato prima un approccio a finestra popup, ma ottenere il menu popup posizionato correttamente sembrava troppo complicato , soprattutto considerando che le dimensioni del menu possono variare in base alla lingua dell'utente e alle preferenze dei caratteri e così via. Lo terrò come opzione di fallback se non si riesce a far funzionare il suddetto. – bryce

risposta

6

Come già menzionati da ilius nei commenti, menu non è progettata per contenere widget di arbitrario. È stato anche discusso in this SO post. Dovrai andare con l'opzione finestra pop-up.
L'applet di orologio in Ubuntu che si sta tentando di emulare utilizza una finestra pop-up. È possibile verificare questo utilizzando xwininfo. Se hai il calendario visualizzato, selezionalo (per l'utilità xwininfo) puoi vedere che si tratta di una finestra separata e non uguale al pannello.
Inoltre, questo può essere confermato guardando lo source. L'applet orologio che è mostrata è una toggle button che su toggle mostra/nasconde la finestra pop-up con il calendario (più preciso è un widget personalizzato CalendarWindow che estende GtkWindow e adds GtkCalendar in modo appropriato quando viene creato). Un'implementazione grezza della stessa idea, sulla base di codice è il seguente (Si prega di perdonare la mia conoscenza python limitata):

#!/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() 

Spero che questo aiuti!

+0

Questo aiuta, anche con c ... –

Problemi correlati