Showing a gtk.Calendar in a menu?

后端 未结 1 1038
梦谈多话
梦谈多话 2021-02-06 05:12

\"calendar-menu-screenshot\"

I want to construct a context menu with a menu item for selecting a date. (The use ca

1条回答
  •  抹茶落季
    2021-02-06 05:36

    As already mentioned by ilius in the comments, menu is not designed to hold arbitrary widget. It has also been discussed in this SO post. You will have to go with the pop-up window option.
    The clock applet in Ubuntu which you are trying to emulate uses pop-up window. You can verify this using xwininfo. If you have the calendar displayed then select it (for xwininfo utility) you can see that it is a separate window and not the same as the panel.
    Further, this can be confirmed by looking at the source. The clock applet which is shown is a toggle button which on toggle shows/hides the pop-up window with calendar (more precise it is a custom widget CalendarWindow which extends GtkWindow and adds GtkCalendar appropriately when created). A crude implementation of the same idea based on your code is as follows (Please pardon my limited python knowledge):

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

    Hope this helps!

    0 讨论(0)
提交回复
热议问题