I need help getting accelerators to work

I really don't grok accelerators and menus, and could use some help.
Their use seems totally unintuitive to me.

What I want is an standard Edit menu with Cut, Copy, and Paste. I then
have two TextCtrl widgets that I want to bind to these menu items. I
can't seem to make it work. Can someone tell me what I'm doing wrong?

Here's what I've got so far. It's just a condensed version of a bigger
program where different widgets may have different implementations of
OnCopy, OnCut, OnPaste. When I run this code on RHEL, wxPython
2.8.9.1, python 2.5, pressing control-c in either of the text controls
doesn't seem to do anything.

import wx
import wx.aui as aui

class CustomTextCtrl(wx.TextCtrl):
    def __init__(self, parent, id, text):
        wx.TextCtrl.__init__(self, parent, id, text,
style=wx.TE_MULTILINE, size=(200,100))
        self.Bind(wx.EVT_MENU, self.OnCut, id=wx.ID_CUT)
        self.Bind(wx.EVT_MENU, self.OnCopy, id=wx.ID_PASTE)
        self.Bind(wx.EVT_MENU, self.OnPaste, id=wx.ID_PASTE)

    def OnCopy(self, event): print id, "OnCopy..."
    def OnCut(self, event): print id, "OnCut..."
    def OnPaste(self, event): print id, "OnPaste..."

class TabPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)

        sizer = wx.BoxSizer(wx.VERTICAL)
        one = CustomTextCtrl(self, wx.ID_ANY, "hello, world\n")
        two = CustomTextCtrl(self, wx.ID_ANY, "Lorem Ipsum\n")

        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(one, 1, wx.EXPAND|wx.ALL, 5)
        sizer.Add(two, 1, wx.EXPAND|wx.ALL, 5)

        self.SetSizer(sizer)

class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY,
                          "AGW AUI Notebook Tutorial",
                          size=(500,200))

        self._mgr = aui.AuiManager()
        self._mgr.SetManagedWindow(self)

        notebook = aui.AuiNotebook(self)
        panel = TabPanel(notebook)
        notebook.AddPage(panel, "Whatever", False)
        self._mgr.AddPane(notebook)
        self._mgr.Update()

        editMenu = wx.Menu()
        editMenu.Append(wx.ID_CUT)
        editMenu.Append(wx.ID_COPY)
        editMenu.Append(wx.ID_PASTE)
        mb = wx.MenuBar()
        mb.Append(editMenu, "&Edit")
        self.SetMenuBar(mb)

if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

Hi Bryan,

    editMenu = wx\.Menu\(\)
    editMenu\.Append\(wx\.ID\_CUT\)
    editMenu\.Append\(wx\.ID\_COPY\)
    editMenu\.Append\(wx\.ID\_PASTE\)
    mb = wx\.MenuBar\(\)
    mb\.Append\(editMenu, "&Edit"\)
    self\.SetMenuBar\(mb\)

You should write:
editMenu.Append(wx.ID_CUT, u"Cut\tCTRL+X", u"menu Cut")

In the wx Doc, you have for Menu Append:
Append(id, string, helpStr="", checkable=false)
.../...
The accelerator string follows the item label and is separated from it
by a TAB stringacter ('\t'). Its general syntax is any combination of
CTRL, ALT and SHIFT strings (case doesn’t matter) separated by either
'-' or '+' stringacters and followed by the accelerator itself.

The accelerator may be any alphanumeric string character, any function
key (from F1 to F12) or one of the special string characters listed in
the table below (again, case doesn’t matter):
.../...

I haven't looked further but that way it should work.

Dominique

···

On Apr 13, 4:44 pm, Bryan Oakley <bryan.oak...@gmail.com> wrote:

My old tutorial might help you grok menus and accelerators a bit
better:

···

On Apr 13, 9:44 am, Bryan Oakley <bryan.oak...@gmail.com> wrote:

I really don't grok accelerators and menus, and could use some help.
Their use seems totally unintuitive to me.

What I want is an standard Edit menu with Cut, Copy, and Paste. I then
have two TextCtrl widgets that I want to bind to these menu items. I
can't seem to make it work. Can someone tell me what I'm doing wrong?

Here's what I've got so far. It's just a condensed version of a bigger
program where different widgets may have different implementations of
OnCopy, OnCut, OnPaste. When I run this code on RHEL, wxPython
2.8.9.1, python 2.5, pressing control-c in either of the text controls
doesn't seem to do anything.

import wx
import wx.aui as aui

class CustomTextCtrl(wx.TextCtrl):
def __init__(self, parent, id, text):
wx.TextCtrl.__init__(self, parent, id, text,
style=wx.TE_MULTILINE, size=(200,100))
self.Bind(wx.EVT_MENU, self.OnCut, id=wx.ID_CUT)
self.Bind(wx.EVT_MENU, self.OnCopy, id=wx.ID_PASTE)
self.Bind(wx.EVT_MENU, self.OnPaste, id=wx.ID_PASTE)

def OnCopy\(self, event\): print id, &quot;OnCopy\.\.\.&quot;
def OnCut\(self, event\): print id, &quot;OnCut\.\.\.&quot;
def OnPaste\(self, event\): print id, &quot;OnPaste\.\.\.&quot;

class TabPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)

    sizer = wx\.BoxSizer\(wx\.VERTICAL\)
    one = CustomTextCtrl\(self, wx\.ID\_ANY, &quot;hello, world\\n&quot;\)
    two = CustomTextCtrl\(self, wx\.ID\_ANY, &quot;Lorem Ipsum\\n&quot;\)

    sizer = wx\.BoxSizer\(wx\.HORIZONTAL\)
    sizer\.Add\(one, 1, wx\.EXPAND|wx\.ALL, 5\)
    sizer\.Add\(two, 1, wx\.EXPAND|wx\.ALL, 5\)

    self\.SetSizer\(sizer\)

class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"AGW AUI Notebook Tutorial",
size=(500,200))

    self\.\_mgr = aui\.AuiManager\(\)
    self\.\_mgr\.SetManagedWindow\(self\)

    notebook = aui\.AuiNotebook\(self\)
    panel = TabPanel\(notebook\)
    notebook\.AddPage\(panel, &quot;Whatever&quot;, False\)
    self\.\_mgr\.AddPane\(notebook\)
    self\.\_mgr\.Update\(\)

    editMenu = wx\.Menu\(\)
    editMenu\.Append\(wx\.ID\_CUT\)
    editMenu\.Append\(wx\.ID\_COPY\)
    editMenu\.Append\(wx\.ID\_PASTE\)
    mb = wx\.MenuBar\(\)
    mb\.Append\(editMenu, &quot;&amp;Edit&quot;\)
    self\.SetMenuBar\(mb\)

if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show()
app.MainLoop()

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

Hmmm. I thought the whole idea with using the standard IDs was that I
didn't have to specify accelerators or labels -- that they would use
whatever was standard for that platform.

Also, that made no difference.

···

On Tue, Apr 13, 2010 at 11:09 AM, Dominique <mydomdom@gmail.com> wrote:

Hi Bryan,

On Apr 13, 4:44 pm, Bryan Oakley <bryan.oak...@gmail.com> wrote:

        editMenu = wx.Menu()
        editMenu.Append(wx.ID_CUT)
        editMenu.Append(wx.ID_COPY)
        editMenu.Append(wx.ID_PASTE)
        mb = wx.MenuBar()
        mb.Append(editMenu, "&Edit")
        self.SetMenuBar(mb)

You should write:
editMenu.Append(wx.ID_CUT, u"Cut\tCTRL+X", u"menu Cut")

No, that didn't help. I still have the same problem that I can't have
a menu accelerator and have that accelerator call widget-specific
methods depending on which widget has focus.

···

On Tue, Apr 13, 2010 at 12:54 PM, Mike Driscoll <kyosohma@gmail.com> wrote:

My old tutorial might help you grok menus and accelerators a bit
better:

The menu events from accelerators are delivered to the frame that the menu bar is attached to, not to the window with the focus. If you want to do that then you can add an event handler in the frame class that looks something like this:

def OnCopy(self, evt):
     focus = wx.Window.FindFocus()
     if focus and hasattr(focus, 'OnCopy'):
         focus.OnCOpy(evt)

Or you can try making a wx.AcceleratorTable for each of the textctrls and assigning it to them with SetAcceleratorTable.

···

On 4/13/10 11:40 AM, Bryan Oakley wrote:

On Tue, Apr 13, 2010 at 12:54 PM, Mike Driscoll<kyosohma@gmail.com> wrote:

My old tutorial might help you grok menus and accelerators a bit
better:

http://www.blog.pythonlibrary.org/2008/07/02/wxpython-working-with-menus-toolbars-and-accelerators/

No, that didn't help. I still have the same problem that I can't have
a menu accelerator and have that accelerator call widget-specific
methods depending on which widget has focus.

--
Robin Dunn
Software Craftsman

I'm pretty sure Robin meant: focus.OnCopy(evt), not focus.OnCOpy(evt)

···

On Apr 13, 3:51 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 4/13/10 11:40 AM, Bryan Oakley wrote:

> On Tue, Apr 13, 2010 at 12:54 PM, Mike Driscoll<kyoso...@gmail.com> wrote:

>> My old tutorial might help you grok menus and accelerators a bit
>> better:

>http://www.blog.pythonlibrary.org/2008/07/02/wxpython-working-with-me

> No, that didn't help. I still have the same problem that I can't have
> a menu accelerator and have that accelerator call widget-specific
> methods depending on which widget has focus.

The menu events from accelerators are delivered to the frame that the
menu bar is attached to, not to the window with the focus. If you want
to do that then you can add an event handler in the frame class that
looks something like this:

def OnCopy(self, evt):
focus = wx.Window.FindFocus()
if focus and hasattr(focus, 'OnCopy'):
focus.OnCOpy(evt)

Or you can try making a wx.AcceleratorTable for each of the textctrls
and assigning it to them with SetAcceleratorTable.

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

-------------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

It turns out that's (almost) exactly what I did. Based on experience
with other toolkits I figured there must be an easier way, but
apparently not. <shrug>

Thanks.

···

On Tue, Apr 13, 2010 at 3:51 PM, Robin Dunn <robin@alldunn.com> wrote:

The menu events from accelerators are delivered to the frame that the menu
bar is attached to, not to the window with the focus. If you want to do
that then you can add an event handler in the frame class that looks
something like this:

def OnCopy(self, evt):
focus = wx.Window.FindFocus()
if focus and hasattr(focus, 'OnCopy'):
focus.OnCOpy(evt)

Or you can try making a wx.AcceleratorTable for each of the textctrls and
assigning it to them with SetAcceleratorTable.