Вопрос по pygtk, python, gtk, ubuntu – Отображение gtk.Calendar в меню?

8

calendar-menu-screenshot

Я хочу построить контекстное меню с пунктом меню для выбора даты. (Вариант использования: выбор набора элементов в виде дерева и установка новой даты выполнения для всех элементов.)

Поскольку пункт меню является Gtk.Bin, я могу указать любой виджет вместо метки. Тем не менее, я не могуinteract с виджетом. Если я щелкаю в любом месте меню, пункт меню получает щелчок. Таким образом, я не могу выбрать конкретную дату, ни перемещаться по месяцам или годам. Как я могу заставить календарь получать мышиную активность?

Кроме того, вокруг календаря есть посторонние отступы, а при наведении на них он становится оранжевым. Как я могу удалить отступы и / или не сделать оранжевую подсветку?

#!/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.

Ubuntu Calendar

В Ubuntu на стандартном дисплее даты / времени появляется меню с интерактивным меню. Я думаю, что это выглядит хорошо, но эстетика и уместность, конечно, кажется,possibleи поэтому я хотел бы знать, как это сделать. bryce
Вы также можете поместить много кнопок или даже панель инструментов в это всплывающее окно (если вы хотите иметь больше действий во всплывающем окне) saeedgnu
Меню не должно содержать большие виджеты, особенно когда они взаимодействуют (и не толькоactivateing Пункты меню). Даже если вам удастся заставить его работать, это не стандартно и приятно. saeedgnu
Это уродливо, поскольку больше нет пунктов меню, почему вы просто помещаете Календарь во всплывающее окно? saeedgnu
Сначала я попытался использовать подход всплывающего окна, но правильное расположение всплывающего меню выглядело бы слишком сложным, особенно учитывая, что размеры меню могут различаться в зависимости от языка, предпочтений пользователя и шрифта и так далее. Я оставляю это как запасной вариант, если вышеописанное не может быть выполнено. bryce

Ваш Ответ

1   ответ
6

Ilius в комментариях меню не предназначено для хранения произвольных виджетов. Это также обсуждалось вэтот ТАК пост, Вам придется пойти с опцией всплывающего окна.
Апплет часов в 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()

Надеюсь это поможет!

Это помогает, с т тоже ...

Похожие вопросы