wxpython 工具栏菜单键盘导航

wxpython toolbarmenu keyboard navigation

我一直在为盲人开发一个应用程序,所以我决定 python 和 wxPython 用于 GUI。问题是我无法使用制表符导航 wx.toolbar。这是我的实际代码。

    menuToolBar = self.CreateToolBar(style=wx.TB_FLAT)
    menuToolBar.AddSeparator()
    menuToolBar.AddTool(ID_NUEVO, "Nuevo Archivo", wx.Bitmap(
        os.path.join(self.__rutaPrincipal, "img/nueva pagina.png")), "Nuevo Archivo")
    menuToolBar.AddSeparator()
    menuToolBar.AddTool(ID_GUARDAR_ARCHIVO, "Guardar Archivo", wx.Bitmap(
        os.path.join(self.__rutaPrincipal, "img/guardar pagina.png")),  "Guardar Archivo")
    menuToolBar.AddTool(ID_ABRIR_ARCHIVO, "Abrir Página", wx.Bitmap(
        os.path.join(self.__rutaPrincipal, "img/abrir pagina.png")), "Abrir Página")
    menuToolBar.AddSeparator()
    menuToolBar.AddTool(ID_FOCUS_PANEL_ESCRITURA, "Foco Escritura", wx.Bitmap(
        os.path.join(self.__rutaPrincipal, "img/panel escritura.png")), "Foco Escritura")
    menuToolBar.AddTool(ID_FOCUS_PANEL_RESULTADO, "Foco Resultado", wx.Bitmap(
        os.path.join(self.__rutaPrincipal, "img/panel resultado.png")), "Foco Resultado")
    menuToolBar.AddSeparator()
    menuToolBar.AddTool(ID_CERRAR_PAGINA, "Cerrar Página", wx.Bitmap(
        os.path.join(self.__rutaPrincipal, "img/cerrar pagina.png")), "Cerrar Página")
    menuToolBar.AddSeparator()

    menuToolBar.Realize()

有什么配置可以实现吗?或者是否有其他组件可以帮助我? P.D。我是 python 开发和 Whosebug

的新手

您需要在您的 MenuBar 中实施 Accelerators,可能还需要在您的 MenuItem 中实施。

An accelerator table allows the application to specify a table of keyboard shortcuts for menu or button commands.

通常,这些是使用菜单项中的文本设置的,绕过了 wx.AcceleratorTable

p1 = wx.MenuItem(playm, wx.NewIdRef(), '&Play\tCtrl+P')

此处&Play设置P为菜单快捷键,Ctrl+P为菜单项所代表功能的热键。
换句话说,当浏览菜单时,按 P 将 select 播放菜单项。不导航菜单时,只需按 Ctrl+P 即可 运行 该功能。
N.B.

  • 您不必同时设置两者。
  • 不要在单个菜单或菜单栏中将 & 符号多次放在同一个字母之前,因为只有第一个有效。
    例如“&Save”和“Save&ve as”可以工作,使用 S 作为“Save”,使用 V 作为“Save as”

To access the Menu shortcuts Press the Alt button and then any of the underlined letters.

一些带有菜单加速器但没有分配热键的最小代码:

import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(200, 100))
        self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
        # A Statusbar in the bottom of the window
        self.CreateStatusBar()

        # Setting up the menus
        '''Define main items'''
        filemenu = wx.Menu()
        editmenu = wx.Menu()
        infomenu = wx.Menu()
        '''Items'''
        # file menu
        menu_open = filemenu.Append(wx.ID_OPEN, "Open")
        filemenu.Append(wx.ID_NEW, "New")
        filemenu.Append(wx.ID_SAVE, "Save")
        filemenu.Append(wx.ID_SAVEAS, "Save as")
        filemenu.Append(wx.ID_EXIT, '&Quit', 'Quit application')
        filemenu.AppendSeparator()
        filemenu.Append(wx.ID_PRINT, "&Print")
        filemenu.Append(wx.ID_PRINT_SETUP, "Print setup")
        filemenu.Append(wx.ID_PREVIEW, "Preview")
        # edit menu
        editmenu.Append(wx.ID_COPY, "Copy")
        editmenu.Append(wx.ID_CUT, "Cut")
        editmenu.Append(wx.ID_PASTE, "Paste")
        editmenu.AppendSeparator()
        editmenu.Append(wx.ID_UNDO, "Undo")
        editmenu.Append(wx.ID_REDO, "Re-do it")
        # info menu
        infomenu.Append(wx.ID_ABOUT, "About")
        '''Bind items for activation'''
        # bind file menu
        self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT)
        self.Bind(wx.EVT_MENU, self.OnOpen)

        # Creating the menubar.
        menuBar = wx.MenuBar()
        # Add menus
        menuBar.Append(filemenu, "&File")
        menuBar.Append(editmenu, "&Edit")
        menuBar.Append(infomenu, "&Help")
        # Adding the MenuBar to the Frame content.
        self.SetMenuBar(menuBar)
        self.Show(True)

    def OnOpen(self, event):
        print ("Menu item selected")
        # event skip as we want to continue checking events in case Quit was chosen
        event.Skip()

    def OnExit(self, event):
        self.Destroy()


app = wx.App(False)
frame = MainWindow(None, "Sample editor")
app.MainLoop()

运行 此代码并按 Alt 键,按未划线字母 F、E 或 H 之一,然后使用箭头键或任何带下划线的字母导航菜单。

N.B。某些功能会自动分配热键,例如Ctrl+Q 退出。

我没有删除现有的答案,它实际上回答了一个不同的问题,而是将其保留在原地,因为我个人认为它在相关方面很有用。

这里是我在评论中提到的一个示例,关于制作您自己的工具栏,您可以使用 Tab、向左和向右箭头键进行导航。
它应该足以让您入门。

它使用一个普通按钮和一些通用位图按钮,两者都可以工作,因为我们需要说明当前哪个按钮具有焦点,这是通过为每个按钮使用至少 2 个不同的位图来实现的。一个普通,一个专注。

import wx
import wx.lib.buttons as buttons

Valid_keys = [wx.WXK_F1,wx.WXK_RETURN,wx.WXK_TAB,wx.WXK_LEFT,wx.WXK_RIGHT]

class MainFrame(wx.Frame):

#----------------------------------------------------------------------
    def __init__(self):

        self.funcs={"Button1":self.OnButton1,
                    "Button2":self.OnButton2,
                    "Button3":self.OnButton3,
                    "Button4":self.OnButton4}
        
        wx.Frame.__init__(self, None, title="Self defined Toolbar", size=(400,400))

        tool_panel = wx.Panel(self,-1,name="tool_panel")
        tool_panel.SetBackgroundColour("lightgreen")
        tool_panel.SetToolTip("Press F1 or Tab to Access Toolbar")

        panel = wx.Panel(self,-1,size=(400,300), name="Main_panel")
        panel.SetBackgroundColour("lightblue")

        bmp = wx.Bitmap("Discord.png", wx.BITMAP_TYPE_ANY)
        bmp1 = wx.Bitmap("Discord1.png", wx.BITMAP_TYPE_ANY)
        bmp2 = wx.Bitmap("Discord2.png", wx.BITMAP_TYPE_ANY)

        self.Button1 = buttons.GenBitmapButton(tool_panel,bitmap=bmp,size=(40,40),name="Button1")
        self.Button2 = buttons.GenBitmapButton(tool_panel,bitmap=bmp,size=(40,40),name="Button2")
        self.Button3 = buttons.GenBitmapButton(tool_panel,bitmap=bmp,size=(40,40),name="Button3")
        self.Button4 = wx.Button(tool_panel,-1, label="",size=(40,40),name="Button4")
        self.Button4.SetBitmap(wx.Bitmap('test.png'))
        self.Button4.SetBitmapFocus(wx.Bitmap('testfocus.png'))

        self.Text = wx.TextCtrl(panel, -1, size=(400,300), style=wx.TE_MULTILINE)

        self.Button1.SetToolTip("Function1")
        self.Button2.SetToolTip("Function2")
        self.Button3.SetToolTip("Function3")
        self.Button4.SetToolTip("Function4")

        self.BitmapButtons = [self.Button1,self.Button2,self.Button3]
        for i in range(0,len(self.BitmapButtons)):
            self.BitmapButtons[i].SetBitmapLabel(bmp)
            self.BitmapButtons[i].SetBitmapFocus(bmp2)
            self.BitmapButtons[i].SetBitmapSelected(bmp1)

        self.Bind(wx.EVT_BUTTON, self.OnButton)
        self.Bind(wx.EVT_CHAR_HOOK, self.OnKey)

        tool_sizer=wx.BoxSizer(wx.HORIZONTAL)
        main_sizer=wx.BoxSizer(wx.VERTICAL)
        tool_sizer.Add(self.Button1)
        tool_sizer.Add(self.Button2)
        tool_sizer.Add(self.Button3)
        tool_sizer.Add(self.Button4)
        tool_panel.SetSizer(tool_sizer)
        
        main_sizer.Add(tool_panel,0,wx.EXPAND)                
        main_sizer.Add(panel,0,wx.EXPAND,0)
        self.SetSizer(main_sizer)                
        self.Text.SetFocus() 
        self.Show()

    def OnButton(self, event):
        Id = event.GetId()
        btn = event.GetEventObject()
        x = self.funcs[btn.GetName()]
        x()
        self.Text.SetFocus()

    def OnButton1(self):
        print("Button 1")
    def OnButton2(self):
        print("Button 2")  
    def OnButton3(self):
        print("Button 3")
    def OnButton4(self):
        print("Button 4")        

    def OnKey(self, event):
        key = event.GetKeyCode()
        if key not in Valid_keys: #Ignore all keys except F1, Enter and Navigation keys
            event.Skip()
            return
        if key not in [wx.WXK_F1,wx.WXK_RETURN]:
            event.Skip()
            return
        if key == wx.WXK_F1: #F1 focuses on the First Toolbar button 
            self.Button1.SetFocus()
            return
        i = self.get_focus()
        if i == 1:
            id="Button1"
        elif i == 2:
            id="Button2"
        elif i == 3: 
            id="Button3"
        elif i == 4: 
            id="Button4"            
        if i > 0: #Focus was a toolbar button, execute button function
            x = self.funcs[id]
            x()
            self.Text.SetFocus()
        event.Skip()

    def get_focus(self):
        focused = wx.Window.FindFocus()
        if focused == self.Button1:
            return 1
        elif focused == self.Button2:
            return 2
        elif focused == self.Button3:
            return 3
        elif focused == self.Button4:
            return 4            
        else:#Something other than the toolbar buttons has focus return Fail
            return -1
        
#----------------------------------------------------------------------
if __name__ == "__main__":
      app = wx.App()
      frame = MainFrame()
      app.MainLoop()