python - 在 Gtk.PopoverMenu 中创建单选操作

标签 python gtk gtk3 pygobject

enter image description here

在我之前的问题( actually the answer )中,我可以找到一种方法来创建带有一些 ModelButtons (正常和切换)的 Gtk.PopoverMenu 。但我真的很苦恼如何以这种方式创建单选按钮。

Older examples使用 Gtk.ActionGroups,但它们 have been deprecated从 GTK 3.10 开始。我不知道如何构建 Gio.ActionGroup ( https://lazka.github.io/pgi-docs/#Gio-2.0/interfaces/ActionGroup.html#Gio.ActionGroup ):

action_group = Gio.ActionGroup()
NotImplementedError: ActionGroup can not be constructed

action_group = Gio.ActionGroup.new()
AttributeError: type object 'ActionGroup' has no attribute 'new'

对于Gio.ActionMap ( https://lazka.github.io/pgi-docs/#Gio-2.0/interfaces/ActionMap.html#Gio.ActionMap ) 也是如此:

actionmap = Gio.ActionMap()
NotImplementedError: ActionMap can not be constructed

和:

actionmap = Gio.ActionMap.new()
AttributeError: type object 'ActionMap' has no attribute 'new'

我不确定为什么会这样:

    actionmap = Gio.ActionMap.add_action(self, action_yes)
    actionmap = Gio.ActionMap.add_action(self, action_no)

希望有人能帮助我,让我在脑海中解决这个问题:

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)
        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("actionmap_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)

        action_print = Gio.SimpleAction.new("print", None)
        action_print.connect("activate", self.print_something)
        app.add_action(action_print)

        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)

        action_yes = Gio.SimpleAction.new("yes", None)
        action_yes.connect("activate", self.print_something)
        app.add_action(action_yes)

        action_no = Gio.SimpleAction.new("no", None)
        action_no.connect("activate", self.print_something)
        app.add_action(action_no)
        actionmap = Gio.ActionMap.add_action(self, action_yes)
        actionmap = Gio.ActionMap.add_action(self, action_no)
        #action_group = Gio.ActionGroup.new()

        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):

<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>
          <child>
            <object class="GtkModelButton" id="mp_yes">
              <property name="visible">True</property>
              <property name="action-name">app.yes</property>
              <property name="can_focus">True</property>
              <property name="receives_default">True</property>
              <property name="label" translatable="yes">Yes</property>
            </object>
          </child>
          <child>
            <object class="GtkModelButton" id="mp_no">
              <property name="visible">True</property>
              <property name="action-name">app.no</property>
              <property name="can_focus">True</property>
              <property name="receives_default">True</property>
              <property name="label" translatable="yes">No</property>
            </object>
          </child>
        </object>
      </child>
    </object>
</interface>

还有一个example here 。但它也没有展示如何正确地使用 radio 。正如我上面的示例所示,切换似乎很简单。

最佳答案

我最近与 mgedmin 交谈过,他有一个放射组的工作示例( https://github.com/gtimelog/gtimelog/blob/da38b1ac9fc8b81a2b92884a755f311a99e22d0e/mockup.py )。我相应地从问题中调整了我的例子。请注意 XML 接口(interface)的不同结构。

Python:

import gi
gi.require_version("Gtk", "3.0")

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


class MainApplication(Gtk.Application):

    def __init__(self):
        Gtk.Application.__init__(self,
                                 application_id="needs.dots",
                                 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)
        app.add_window(self.window)

        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")
        button_settings.set_menu_model(\
                        self.builder.get_object('options-menu'))

        # Add radiobutton group that includes all actions that
        # are named ***.radiogroup, 'radio-two' is the default
        # choice.
        detail_level = Gio.SimpleAction.new_stateful("radiogroup", \
                           GLib.VariantType.new("s"), \
                           GLib.Variant("s", "radio-two"))
        detail_level.connect("activate", self.radio_response)
        self.window.add_action(detail_level)

        # 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 radio_response(self, act_obj, act_lbl):
        # Not sure if this is the correct way of doing this.
        # but it seems to work.
        act_obj.set_state(act_lbl)

    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)

UI 文件:

<interface>
  <menu id="options-menu">
    <section>
      <item>
    <attribute name="label">Print Message</attribute>
    <attribute name="action">app.print</attribute>
      </item>
    </section>
    <section>
      <item>
    <attribute name="label">Night Mode</attribute>
    <attribute name="action">app.toggle</attribute>
      </item>
    </section>
    <section>
      <item>
    <attribute name="label">Choice 1</attribute>
    <attribute name="action">win.radiogroup</attribute>
    <attribute name="target">radio-one</attribute>
      </item>
      <item>
    <attribute name="label">Choice 2</attribute>
    <attribute name="action">win.radiogroup</attribute>
    <attribute name="target">radio-two</attribute>
      </item>
      <item>
    <attribute name="label">Choice 3</attribute>
    <attribute name="action">win.radiogroup</attribute>
    <attribute name="target">radio-three</attribute>
      </item>
    </section>
  </menu>
</interface>

生成的界面:

enter image description here

关于python - 在 Gtk.PopoverMenu 中创建单选操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31162398/

相关文章:

python - 使用 matplotlib 创建热图

c++ - GtkImage 不会更新并且 opencv 不会释放图像

Python 和 GTK3 : How to create a Liststore

Python Peewee MySQL 批量更新

python - 获取仅 7 :00 hrs 的数据的最 Pythonic 方法是什么

python - OpenCV Python GTK错误

linux - 如何创建没有标题栏的 gtk+ 窗口?

C++ GTKmm - 将文本插入到具有多个缓冲区和更改文本的 TextView

haskell - 管道.并发: Sent signal is delivered one click later than expected

python - 使用 selenium 单击元素时出现问题