Home > Software engineering >  How can I use Keyboard Shortcuts in WxPython?
How can I use Keyboard Shortcuts in WxPython?

Time:09-30

Well, I have a simple text editor, the code will be published below. So, I wish I could call File/Open for CTRL o, File/Save for CTRL s, File/Save as for CTRL Shift s. But in addition, I need that when I press CTRL 1, CTRL 2, CTRL 3, CTRL 4, I have the ability to use code other than WxPython. As I know, WxPython has a KeyEvent class with these key events, but to use it, as I understood, I need to use bind. Well, I've tried Keyboard Shortcuts (Accelerators), but it doesn't work. Can someone help me please?

import os
import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(800,600))
        self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
        self.CreateStatusBar()
        filemenu = wx.Menu()
        menuOpen = filemenu.Append(wx.ID_OPEN, "&Open"," Open a file")
        menuSave = filemenu.Append(wx.ID_SAVE, "&Save"," Save a file")
        menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "&Save as"," Save a file as")
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
        menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File")
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
        self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
        self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
        exit_id = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnKeyExit, id=exit_id)
        a_tbl = wx.AcceleratorTable([(wx.ACCEL_CTRL,  ord('Q'), exit_id )])
        self.SetAcceleratorTable(a_tbl)
        self.Show(True)
...
    def onKeyExit(self, e):
            self.Close()
app = wx.App(False)
frame = MainWindow(None, "Test")
app.MainLoop()

CodePudding user response:

You are probably looking for wx.EVT_KEY_DOWN

Bind this either to self or self.control.

You will need to check both the key and check if a modifier key is also depressed.

import os
import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(800,600))
        self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
        self.CreateStatusBar()
        filemenu = wx.Menu()
        menuOpen = filemenu.Append(wx.ID_OPEN, "&Open"," Open a file")
        menuSave = filemenu.Append(wx.ID_SAVE, "&Save"," Save a file")
        menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "&Save as"," Save a file as")
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
        menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File")
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
        self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
        self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)

        self.control.Bind(wx.EVT_KEY_DOWN, self.OnKey)

        self.Show(True)

    def OnKey(self, event):
        key = event.KeyCode
        print("Testing key ", chr(key))
        if key < 49 or key > 52:
            event.Skip()
            return
        # Test modifier key there is no wx.WXK_CONTROL_0....9
        if event.ControlDown():
            self.OnOther(key)
        event.Skip()

    def OnOther(self, key):
        print("Control >>>>>>>>>>>>>>>>>>>>>>>>>>", chr(key))

    def OnOpen(self, e):
        self.dirname = ''
        dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.filename = dlg.GetFilename()
            self.dirname = dlg.GetDirectory()
            f = open(os.path.join(self.dirname, self.filename), 'r', encoding="utf8")
            self.control.SetValue(f.read())
            f.close()
        dlg.Destroy()
    def OnSave(self, e):
        try:
            f = open(os.path.join(self.dirname, self.filename), 'w', encoding='utf8')
            f.write(self.control.GetValue())
            f.close()
        except:
            try:
                dlg = wx.FileDialog(self, "Save to file:", ".", "", "*.*", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
                if (dlg.ShowModal() == wx.ID_OK):
                    self.filename = dlg.GetFilename()
                    self.dirname = dlg.GetDirectory()
                    f = open(os.path.join(self.dirname, self.filename), 'w', encoding='utf8')
                    f.write(self.control.GetValue())
                    f.close()
                dlg.Destroy()
            except:
                pass
    def OnSaveAs(self, event):
        try:
            dlg = wx.FileDialog(self, "Save to file:", ".", "", "*.*", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
            if (dlg.ShowModal() == wx.ID_OK):
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'w', encoding='utf8')
                f.write(self.control.GetValue())
                f.close()
            dlg.Destroy()
        except:
            pass
    def OnAbout(self, e):
        dlg = wx.MessageDialog(self, "A Record text editor", "About Sample Editor", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()
    def OnExit(self, e):
        self.Close(True)
app = wx.App(False)
frame = MainWindow(None, "Test")
app.MainLoop()

CodePudding user response:

If on the other hand, you wish to restrict yourself to using menu accelerators, you include the keys required after a tab character in the menu label.
Additionally there is the option to use an accelerator table (https://docs.wxpython.org/wx.AcceleratorTable.html)

import os
import wx

class MainWindow(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(800,600))
        self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
        self.CreateStatusBar()
        filemenu = wx.Menu()
        othermenu = wx.Menu()
        menuOpen = filemenu.Append(wx.ID_OPEN, "&Open"," Open a file")
        menuSave = filemenu.Append(wx.ID_SAVE, "&Save"," Save a file")
        menuSaveAs = filemenu.Append(wx.ID_SAVEAS, "&Save as"," Save a file as")
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
        menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")

        menuOth1 = othermenu.Append(wx.ID_ANY, "Option &1\tCtrl 1"," Run option 1")
        menuOth2 = othermenu.Append(wx.ID_ANY, "Option &2\tCtrl 2"," Run option 2")
        menuOth3 = othermenu.Append(wx.ID_ANY, "Option &3\tCtrl 3"," Run option 3")
        menuOth4 = othermenu.Append(wx.ID_ANY, "Option &4\tCtrl 4"," Run option 4")
                        
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"&File")
        menuBar.Append(othermenu,"&Other")
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
        self.Bind(wx.EVT_MENU, self.OnOpen, menuOpen)
        self.Bind(wx.EVT_MENU, self.OnSave, menuSave)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, menuSaveAs)
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)

        self.Bind(wx.EVT_MENU, self.OnOtherKey, id=menuOth1.GetId())
        self.Bind(wx.EVT_MENU, self.OnOtherKey, id=menuOth2.GetId())
        self.Bind(wx.EVT_MENU, self.OnOtherKey, id=menuOth3.GetId())
        self.Bind(wx.EVT_MENU, self.OnOtherKey, id=menuOth4.GetId())                

        self.Show(True)

    def OnOtherKey(self, event):
        obj = event.GetEventObject()
        label = obj.GetLabel(event.Id)
        print(label)

    def OnOpen(self, e):
        self.dirname = ''
        dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.filename = dlg.GetFilename()
            self.dirname = dlg.GetDirectory()
            f = open(os.path.join(self.dirname, self.filename), 'r', encoding="utf8")
            self.control.SetValue(f.read())
            f.close()
        dlg.Destroy()

    def OnSave(self, e):
        try:
            f = open(os.path.join(self.dirname, self.filename), 'w', encoding='utf8')
            f.write(self.control.GetValue())
            f.close()
        except:
            try:
                dlg = wx.FileDialog(self, "Save to file:", ".", "", "*.*", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
                if (dlg.ShowModal() == wx.ID_OK):
                    self.filename = dlg.GetFilename()
                    self.dirname = dlg.GetDirectory()
                    f = open(os.path.join(self.dirname, self.filename), 'w', encoding='utf8')
                    f.write(self.control.GetValue())
                    f.close()
                dlg.Destroy()
            except:
                pass

    def OnSaveAs(self, event):
        try:
            dlg = wx.FileDialog(self, "Save to file:", ".", "", "*.*", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
            if (dlg.ShowModal() == wx.ID_OK):
                self.filename = dlg.GetFilename()
                self.dirname = dlg.GetDirectory()
                f = open(os.path.join(self.dirname, self.filename), 'w', encoding='utf8')
                f.write(self.control.GetValue())
                f.close()
            dlg.Destroy()
        except:
            pass

    def OnAbout(self, e):
        dlg = wx.MessageDialog(self, "A Record text editor", "About Sample Editor", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, e):
        self.Close(True)

app = wx.App(False)
frame = MainWindow(None, "Test")
app.MainLoop()
  • Related