2012-06-21 17 views
8

Wyświetlanie gtk.Calendar w menu?

Chcę skonstruować menu kontekstowe z elementem menu do wyboru daty. (Przypadek użycia wybiera grupę elementów w widoku drzewa, a następnie ustawia nowy termin dla wszystkich elementów.)

Ponieważ menuitem to Gtk.Bin, mogę podać dowolny widżet zamiast etykiety. Jednak nie mogę wydawać się interakcji z widżetem. Jeśli kliknę w dowolnym miejscu menu, menuitem otrzyma kliknięcie. Nie mogę więc wybrać konkretnej daty ani nawigować przez miesiące ani lata. Jak sprawić, by kalendarz działał jak mysz?

Ponadto poza obrysem kalendarza znajduje się obcy materiał, który po obróceniu się zmienia kolor na pomarańczowy. Jak mogę usunąć wyściółkę i/lub nie zrobić pomarańczowego światła?

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

[Aktualizacja]

Co Idę jest coś podobnego do Ubuntu wskaźnik daty menu/kalendarz czasu.

Ubuntu Calendar

+0

To brzydkie, skoro nie ma już żadnych pozycji w menu, dlaczego właśnie umieszczasz kalendarz w wyskakującym okienku? – saeedgnu

+0

Możesz również umieścić wiele przycisków lub nawet pasek narzędzi w tym wyskakującym okienku (jeśli chcesz mieć więcej akcji w wyskakującym okienku) – saeedgnu

+0

Najpierw podjąłem próbę wyskakującego okienka, ale prawidłowe ustawienie menu wyskakującego wyglądało na zbyt trudne. , zwłaszcza biorąc pod uwagę, że wymiary menu mogą się różnić w zależności od preferencji językowych i czcionek użytkownika i tak dalej. Zachowuję to jako opcję awaryjną, jeśli powyższe nie może zostać wprowadzone do działania. – bryce

Odpowiedz

6

Jak już wspomniano przez ilius w komentarzach, menu nie jest przeznaczone do przechowywania dowolny widget. Zostało to również omówione w this SO post. Będziesz musiał przejść do okna pop-up.
Aplet zegara w Ubuntu, który próbujesz emulować, używa wyskakującego okienka. Możesz to sprawdzić, używając xwininfo. Jeśli masz wyświetlony kalendarz, a następnie wybierz go (dla narzędzia xwininfo), zobaczysz, że jest to oddzielne okno, a nie to samo, co panel.
Co więcej, można to potwierdzić, patrząc na source. Pokazany aplet zegara to toggle button, który na toggle pokazuje/ukrywa wyskakujące okienko z kalendarzem (dokładniej jest to widget niestandardowy CalendarWindow, który rozszerza odpowiednio GtkWindow i i adds GtkCalendar). Prosta implementacja tego samego pomysłu na podstawie Twojego kodu jest następująca (przepraszam za moją ograniczoną wiedzę pytona):

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

Mam nadzieję, że to pomoże!

+0

Pomaga to, także przy użyciu c ... –

Powiązane problemy