我想构build一个菜单项select一个date的上下文菜单。 (用例是在树视图中select一堆项目,然后为所有项目设置一个新的到期date。)
由于menuitem是一个Gtk.Bin,我可以指定任何小部件来代替标签。 但是,我似乎无法与小部件进行交互 。 如果我点击菜单上的任何地方,菜单项会获得点击。 所以,我不能select一个特定的date,也不能浏览几个月或几年。 我如何让日历获得鼠标活动?
此外,在日历的外面还有一些额外的填充,当它hover时,它会变成橙色。 我怎样才能删除填充和/或不做橙色突出显示?
#!/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()
[更新]
我要做的是类似Ubuntu的指标菜单date/时间日历。
正如ilius在评论中已经提到的,菜单不是用来保存任意的小部件的。 在这个SO职位上也讨论过这个问题 。 你将不得不去弹出窗口选项。
Ubuntu试图模拟的时钟小程序使用弹出式窗口。 你可以使用xwininfo
来验证。 如果你有日历显示然后选择它(对于xwininfo
实用程序),你可以看到它是一个单独的窗口,不同于面板。
此外,这可以通过查看来源来确认。 显示的时钟小程序是一个切换按钮 ,它在日历上显示/隐藏弹出窗口(更确切地说,它是一个自定义小部件CalendarWindow
,它扩展了GtkWindow
并在创建时适当地添加了GtkCalendar
)。 基于你的代码的一个粗略的实现如下(请原谅我有限的Python知识):
#!/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()
希望这可以帮助!