如何在 Gtk StackSwitcher 中使用键盘快捷键?

How do I use keyboard shortcuts with Gtk StackSwitcher?

我想做的是做一个快捷键在Page 1和Page 2之间切换,比如按Ctrl+S 会带我到第 1 页,如果我不在那里,同样按 Ctrl+R 会带我到第 2 页。我搜索了documentation 但我找不到任何与我需要的相关的东西。有没有办法实现它?请看下图:

堆栈切换器

这是片段:

class App(Gtk.Application):
def __init__(self, *args, **kwargs):
    super(App, self).__init__(*args, **kwargs)
    self.connect('activate', self.on_activate)

    self.send_stack = None
    self.receive_stack = None
    self.send_receive_stack = None
    self.header_button_handler_id = None
    self.pre_sign_widget = None

def on_activate(self, app):
    ui_file_path = os.path.join(
        os.path.dirname(os.path.abspath(__file__)),
        "app.ui")
    appwindow = 'applicationwindow1'
    builder = Gtk.Builder()
    builder.add_objects_from_file(ui_file_path, [appwindow])
    window = builder.get_object(appwindow)
    window.set_wmclass ("sign", "sign")
    window.set_title("sign")
    window.connect("delete-event", self.on_delete_window)
    self.headerbar = window.get_titlebar()
    self.header_button = builder.get_object("back_refresh_button")
    self.header_button.connect('clicked', self.on_header_button_clicked)

    sw = builder.get_object('stackswitcher1')
    # I want to be able to press Alt+S and Alt+R respectively
    # to switch the stack pages to Send and Receive.
    # sw.get_children()
    self.stack_switcher = sw

    self.send_receive_stack = builder.get_object("send_receive_stack")
    self.send_receive_stack.connect('notify::visible-child',
        self.on_sr_stack_switch)

    ## Load Send part
    self.send = SendApp()
    ss = self.send.stack
    p = ss.get_parent()
    if p:
        p.remove(ss)
    ss.connect('notify::visible-child', self.on_send_stack_switch)
    ss.connect('map', self.on_send_stack_mapped)
    klw = self.send.klw
    klw.connect("key-activated", self.on_key_activated)
    klw.connect("map", self.on_keylist_mapped)
    klw.props.margin_left = klw.props.margin_right = 15
    self.send_stack = ss
    ## End of loading send part

    # Load Receive part
    self.receive = PswMappingReceiveApp(self.on_presign_mapped)
    rs = self.receive.stack

    rs.connect('notify::visible-child',
        self.on_receive_stack_switch)


    scanner = self.receive.scanner
    scanner.connect("map", self.on_scanner_mapped)
    self.receive_stack = rs

    self.send_receive_stack.add_titled(self.send_stack,
        "send_stack", _("Send"))
    self.send_receive_stack.add_titled(rs,
        "receive_stack", _("Receive"))

    accel_group = Gtk.AccelGroup()
    window.add_accel_group(accel_group)
    self.receive.accept_button.add_accelerator("clicked", accel_group, ord('o'), Gdk.ModifierType.MOD1_MASK,
                                               Gtk.AccelFlags.VISIBLE)
    self.receive.accept_button.set_can_default(True)

    window.show_all()
    self.add_window(window)

这是一种获取堆栈的第一个和最后一个 children 的 hacky 方法,其中包含两个 children:

#!/usr/bin/env python

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, Gdk
import os, sys

class GUI:
    def __init__(self):

        self.stack  = Gtk.Stack()
        switcher = Gtk.StackSwitcher()
        switcher.set_stack(self.stack)
        label1 = Gtk.Label("label 1")
        label2 = Gtk.Label("label 2")
        label3 = Gtk.Label("label 3")
        self.stack.add_titled (label1, "1", "Page 1")
        self.stack.add_titled (label2, "2", "Page 2")
        self.stack.add_titled (label3, "3", "Page 3")
        box = Gtk.Box()
        box.pack_start(switcher, True, False, 0)
        box.pack_start(self.stack, True, True, 0)
        box.set_orientation(Gtk.Orientation.VERTICAL)
        window = Gtk.Window()
        window.add(box)

        window.show_all()
        window.connect("key-press-event", self.key_press)

    def key_press (self, window, event):
        keyname = Gdk.keyval_name(event.keyval)
        if not Gdk.ModifierType.CONTROL_MASK:
            #only continue when the CTRL key is down
            return         

        #get the last child

        if keyname == "r":
            for child in self.stack.get_children(): 
                self.stack.set_visible_child(child)

        #get the first child

        if keyname == "s":
            for child in self.stack.get_children():
                self.stack.set_visible_child(child)
                return

    def on_window_destroy(self, window):
        Gtk.main_quit()

def main():
    app = GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())

这是一种通过超过两个 children 的堆栈向前和向后滚动的 hacky 方法:

#!/usr/bin/env python

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GdkPixbuf, Gdk
import os, sys

class GUI:
    def __init__(self):

        self.stack  = Gtk.Stack()
        switcher = Gtk.StackSwitcher()
        switcher.set_stack(self.stack)
        label1 = Gtk.Label("label 1")
        label2 = Gtk.Label("label 2")
        label3 = Gtk.Label("label 3")
        self.stack.add_titled (label1, "1", "Page 1")
        self.stack.add_titled (label2, "2", "Page 2")
        self.stack.add_titled (label3, "3", "Page 3")
        box = Gtk.Box()
        box.pack_start(switcher, True, False, 0)
        box.pack_start(self.stack, True, True, 0)
        box.set_orientation(Gtk.Orientation.VERTICAL)
        window = Gtk.Window()
        window.add(box)

        window.show_all()
        window.connect("key-press-event", self.key_press)

    def key_press (self, window, event):
        keyname = Gdk.keyval_name(event.keyval)
        if not Gdk.ModifierType.CONTROL_MASK:
            #only continue when the CTRL key is down
            return         

        #forward scroll

        #variable to capture the active widget
        previous_child_active = False  
        if keyname == "r":
            #iterate over the stack children
            for child in self.stack.get_children(): 
                if previous_child_active == True: 
                    # the last widget was the one that was active
                    self.stack.set_visible_child(child)
                    #finished
                    return                          
                #remember if the previous child was active
                previous_child_active = self.stack.get_visible_child() == child

        #reverse scroll

        #variable to capture the last widget we iterated
        previous_child = None        
        if keyname == "s":
            #iterate over the stack children
            for child in self.stack.get_children():
                if self.stack.get_visible_child() == child and previous_child != None: 
                    #this is the active widget, so we set the previous active
                    self.stack.set_visible_child(previous_child)
                    #finished
                    return                    
                #remember the last widget       
                previous_child = child       

    def on_window_destroy(self, window):
        Gtk.main_quit()

def main():
    app = GUI()
    Gtk.main()

if __name__ == "__main__":
    sys.exit(main())