问题
I am trying to make an example of a proper Gtk.HeaderBar
with Gtk.PopoverMenus
that shows how the different widgets are used. I looked at a lot of examples and code, but can't figure out, how to work the Gtk.ModelButton
.
Especially this sentence makes no sense to me:
When the action is specified via the “action-name” and “action-target” properties, the role of the button (i.e. whether it is a plain, check or radio button) is determined by the type of the action and doesn't have to be explicitly specified with the “role” property.
In any case, here is my attempt to just use normal widgets in the PopoverMenu, leading to inconsistent highlighting (the whole row should be highlighted):
So my question is: How are ModelButtons
subclassed, so they appear as proper PopoverMenu
-widgets?
Here is the Python code:
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()
And here is the model for the 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>
回答1:
I managed to solve most of what my question was. Most importantly it seems that one has to use Gtk.Application
and Gtk.ApplicationWindow
. I can't say that I fully understand why, but that makes it possible to add Actions
in the form of Gio.SimpleActions
to the application. Gtk.Builder
parses the XML
of the menu, and one can simply add it tot the menu using the set_popover
-method. Then for each action defined in the XML (don't forget the app.
-prefix in the XML) a Gio.SimpleAction
is created (without the app.
-prefix as name) in the Python-code and added to the application. I got a normal button, and a checkbutton to work. Still struggling with the radiobutton, but that might be another question.
Here is the Python-code:
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)
and the XML-file for the menu:
<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>
来源:https://stackoverflow.com/questions/31012645/properly-structure-and-highlight-a-gtkpopovermenu-using-pygobject