Правильно структурируйте и выделите GtkPopoverMenu с помощью PyGObject.

Я пытаюсь сделать пример правильного Gtk.HeaderBar с Gtk.PopoverMenus, который показывает, как используются разные виджеты. Я просмотрел множество примеров и кода, но не могу понять, как работать с Gtk.ModelButton.

Особенно это предложение не имеет для меня никакого смысла:

Когда действие задается с помощью свойств «имя действия» и «цель действия», роль кнопки (т. е. простая, галочка или радиокнопка) определяется типом действия и не должны быть явно указаны в свойстве «роль».

В любом случае, вот моя попытка просто использовать обычные виджеты в PopoverMenu, что приводит к непоследовательному выделению (должна быть выделена вся строка):

введите здесь описание изображения

Итак, мой вопрос: как ModelButtons подразделяются на подклассы, чтобы они отображались как правильные PopoverMenu-виджеты?

Вот код Python:

from gi.repository import Gtk, Gio

class HeaderBarWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="HeaderBar & PopoverMenu")
        self.set_border_width(10)
        self.set_default_size(400, 400)
        builder = Gtk.Builder()
        objects = builder.add_objects_from_file("popovermenu_layout.xml", ("pom_options", ""))
        pom_opt = builder.get_object("pom_options")
        builder.connect_signals(self)

        hb = Gtk.HeaderBar()
        hb.set_show_close_button(True)
        hb.props.title = "HeaderBar & PopoverMenu"
        self.set_titlebar(hb)

        def on_click(button, popovermenu):
            """
            Toggles the respective popovermenu.
            """
            if popovermenu.get_visible():
                popovermenu.hide()
            else:
                popovermenu.show_all()

        button_opt = Gtk.Button()
        icon = Gio.ThemedIcon(name="format-justify-fill-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
        button_opt.add(image)
        hb.pack_end(button_opt)
        pom_opt.set_relative_to(button_opt)
        button_opt.connect("clicked", on_click, pom_opt)

        self.add(Gtk.TextView())

    def print_something(self, modelbutton, event):
        print("you pressed a button")

    def night_mode_switcher(self, switch, state):
        Gtk.Settings.get_default().set_property("gtk-application-prefer-dark-theme", state)

win = HeaderBarWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

А вот модель для PopoverMenu:

<interface>
    <object class="GtkPopoverMenu" id ="pom_options">
      <child>
        <object class="GtkBox">
          <property name="visible">True</property>
          <property name="margin">10</property>
          <property name="orientation">vertical</property>
          <child>
            <object class="GtkModelButton" id="mb_print">
              <property name="visible">True</property>
              <property name="text" translatable="yes">Print</property>
              <property name="can_focus">True</property>
              <property name="receives_default">True</property>
              <signal name="button-press-event" handler="print_something" swapped="no"/>
            </object>
          </child>
          <child>
            <object class="GtkCheckButton" id="checkbutton1">
              <property name="label" translatable="yes">checkbutton</property>
              <property name="visible">True</property>
              <property name="can_focus">True</property>
              <property name="receives_default">False</property>
              <property name="draw_indicator">True</property>
            </object>
          </child>
          <child>
              <object class="GtkBox" id="box1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <child>
                  <object class="GtkSwitch" id="switch1">
                    <property name="visible">True</property>
                    <property name="can_focus">True</property>
                    <signal name="state-set" handler="night_mode_switcher" swapped="no"/>
                    <property name="margin_start">9</property>
                    <property name="margin_end">9</property>
                  </object>
                  <packing>
                    <property name="expand">False</property>
                    <property name="fill">True</property>
                    <property name="position">0</property>
                  </packing>
                </child>
                <child>
                  <object class="GtkModelButton" id="mb_night">
                    <property name="text" translatable="yes">Night Mode</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="margin_start">9</property>
                    <property name="margin_end">9</property>
                  </object>
                  <packing>
                    <property name="expand">True</property>
                    <property name="fill">True</property>
                    <property name="position">1</property>
                  </packing>
                </child>
              </object>
          </child>
        </object>
      </child>
    </object>
</interface>

person tobias47n9e    schedule 23.06.2015    source источник


Ответы (1)


Мне удалось решить большую часть моего вопроса. Самое главное кажется, что нужно использовать Gtk.Application и Gtk.ApplicationWindow. Не могу сказать, что до конца понимаю почему, но это дает возможность добавить в приложение Actions в виде Gio.SimpleActions. Gtk.Builder анализирует XML меню, и его можно просто добавить в меню, используя set_popover-метод. Затем для каждого действия, определенного в XML (не забудьте префикс app. в XML), создается Gio.SimpleAction (без префикса app. в качестве имени) в коде Python и добавляется в приложение. У меня есть нормальная кнопка и галочка для работы. Все еще борюсь с радиокнопкой, но это может быть другой вопрос.

Вот Python-код:

from gi.repository import Gio, Gtk, GLib
import sys


class MainApplication(Gtk.Application):

    def __init__(self):
        Gtk.Application.__init__(self,
                                 application_id="needs.dot",
                                 flags=Gio.ApplicationFlags.FLAGS_NONE)
        #https://developer.gnome.org/gio/unstable/GApplication.html#g-application-id-is-valid
        self.connect("activate", self.activate_window)

    def activate_window(self, app):
        """
        The activate signal of Gtk.Application passes the MainApplication class
        to the window. The window is then set as a window of that class.
        """
        self.window = Gtk.ApplicationWindow()
        self.window.set_default_size(500, 400)

        self.hb = Gtk.HeaderBar()
        self.hb.set_show_close_button(True)
        self.hb.props.title = "HeaderBar & PopOverMenu"
        self.window.set_titlebar(self.hb)

        button_settings = Gtk.MenuButton()
        icon = Gio.ThemedIcon(name="format-justify-fill-symbolic")
        image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
        button_settings.add(image)
        self.hb.pack_end(button_settings)

        self.builder = Gtk.Builder()
        self.builder.add_from_file("popovermenu_layout.xml")
        pom_options = self.builder.get_object("pom_options")
        button_settings.set_popover(pom_options)
        #self.builder.connect_signals(self) #Not needed because of using actions?

        app.add_window(self.window)

        #Connects to the action. The first part of the XML name is left away:
        #<property name="action-name">app.print</property>
        #becomes simply "print".
        action_print = Gio.SimpleAction.new("print", None)
        action_print.connect("activate", self.print_something)
        app.add_action(action_print)

        #app.toggle becomes -> toggle
        action_toggle = Gio.SimpleAction.new_stateful("toggle", None, GLib.Variant.new_boolean(False))
        action_toggle.connect("change-state", self.toggle_toggled)
        app.add_action(action_toggle)

        btn = Gtk.Button("Button")
        self.window.add(btn)
        self.window.show_all()

    def print_something(self, action, variable):
        print("something")

    def toggle_toggled(self, action, state):
        action.set_state(state)
        Gtk.Settings.get_default().set_property("gtk-application-prefer-dark-theme", state)

    def on_action_quit_activated(self, action):
        self.app.quit()


if __name__ == "__main__":
    """
    Creates an instance of the MainApplication class that inherits from
    Gtk.Application.
    """
    app = MainApplication()
    app.run(sys.argv)

и XML-файл для меню:

<interface>
    <object class="GtkPopoverMenu" id ="pom_options">
      <child>
        <object class="GtkBox">
          <property name="visible">True</property>
          <property name="margin">10</property>
          <property name="orientation">vertical</property>
          <child>
            <object class="GtkModelButton" id="mb_print">
              <property name="visible">True</property>
              <property name="action-name">app.print</property>
              <property name="can_focus">True</property>
              <property name="receives_default">True</property>
              <property name="label" translatable="yes">Print</property>
            </object>
          </child>
          <child>
            <object class="GtkModelButton" id="mp_toggle">
              <property name="visible">True</property>
              <property name="action-name">app.toggle</property>
              <property name="can_focus">True</property>
              <property name="receives_default">True</property>
              <property name="label" translatable="yes">Night Mode</property>
            </object>
          </child>
        </object>
      </child>
    </object>
</interface>
person tobias47n9e    schedule 01.07.2015
comment
Вместо форматирования-выравнивания-заполнения-символа, возможно, использовать символ открытия-меню в качестве значка для кнопки меню? - person Marius Gedminas; 03.09.2015
comment
Спасибо. Я просто схватил первый, который выглядел правильно :) - person tobias47n9e; 03.09.2015
comment
Я только что обнаружил, что символ открытого меню довольно новый (появился в GTK+ 3.14?), поэтому, если вы хотите, чтобы ваше программное обеспечение нормально работало, скажем, в Ubuntu 14.04 LTS, вы не можете его использовать. :/ - person Marius Gedminas; 17.09.2015