how to automate menu generation ?

jonhattan escribió:

Hi,

Stef Mientki escribió:

hello,

I want to automate the generation of my form menu:

So I'ld like to put something like this in my form

   # --- text --- --- extension for "ID_" and "OnMenu_" ---
   menus = {
     '&File': ( ( '&New/Open\tCtrl+O', 'Open'),
                ( '&Save\tCtrl+S', 'Save') ),
     '&Help': ( ( 'Signal WorkBench', 'Help'),
                ( '&About', 'About'))
     }

       generate_menu ( self, menus )

So generate_menu looks something like this:

def generate_menu ( form, menus ) :
   # Prepare the menu bar
   menuBar = wx.MenuBar()

   for menu in menus:
     menu_top = wx.Menu ()
     for item in menus [ menu ] :
       menu_item = menu_top.Append ( wx.ID_ANY, item[0] )
       line = 'ID_' + item[1] + ' = menu_item.GetId()'
       exec line
       line = 'self.Bind ( wx.EVT_MENU, self.OnMenu_' + item[1]+ ',id=ID_' + item[1] + ')'
==> #exec line
     line = 'menuBar.Append ( menu_top, "' + menu + '")'
     exec line

   # apply the menubar
   self.SetMenuBar ( menuBar )

I'll do something as:

for menu in menus:
   menu_top = wx.Menu ()
   for item in menus [ menu ] :
       menu_item = menu_top.Append ( wx.ID_ANY, item[0] )

       # the name of the attribute that will hold the menu ID
       menuid = 'ID_%s' % item[1]

       # set the menuid attribute to self (or perhaps store it in a dict)
       setattr(self, menuid, menu_item.GetId())

       # the name of the method to bind the menu event
       menufunc = 'OnMenu_%s' % item[1]

       # try to get such method from self. Otherwise, the dummy method
       func = getattr(self, menufunc, self.OnMenuDummy)

       # do the binding: we have the method to bind and the menu id
       self.Bind(wx.EVT_MENU, func, item[1])

last line is wrong. correct is :
       self.Bind(wx.EVT_MENU, func, menu_item.GetId())

or
       self.Bind(wx.EVT_MENU, func, getattr(self, menuid))

        # finally, append to the menubar
   menuBar.Append ( menu_top, menu)

Maybe I'm asking too much,
but I have the feeling that these kinds of automations (I've few others in my head),
should be possible in Python.

You are asking an interesting question. In gui development, a lot of repetitive code is written for common tasks, think of writting data input forms. I've written a minute ago this snnipet of code for a king of "AddressCtrl" to use in my applications:

this also is wrong :stuck_out_tongue: I mean a KIND of "AddressCtrl"

EOF

···

      #pais
       l = wx.StaticText(self, -1, u"País:")
       w = wx.ComboBox(self, choices = [u'España', ])
       sizer.Add(l, (0, 0), flag = wx.ALIGN_RIGHT)
       sizer.Add(w, (0, 1), flag = wx.EXPAND)
            #provincia
       l = wx.StaticText(self, -1, "Provincia:")
       w = wx.ComboBox(self, choices = ['Las Palmas',], style = wx.CB_READONLY)
       sizer.Add(l, (0, 2), flag = wx.ALIGN_RIGHT)
       sizer.Add(w, (0, 3), flag = wx.EXPAND)
             #cp
       l = wx.StaticText(self, -1, "Código Postal:")
       w = IntCtrl(self)
       sizer.Add(l, (1, 0), flag = wx.ALIGN_RIGHT)
       sizer.Add(w, (1, 1), flag = wx.EXPAND)
                     #población
       l = wx.StaticText(self, -1, u"Población:")
       w = wx.ComboBox(self, choices = ['Las Palmas de G.C.',])
       sizer.Add(l, (1, 2), flag = wx.ALIGN_RIGHT)
       sizer.Add(w, (1, 3), flag = wx.EXPAND)
             #domicilio
       l = wx.StaticText(self, -1, "Domicilio:")
       w = wx.TextCtrl(self, style = wx.TE_MULTILINE, size = (0, 50))
       sizer.Add(l, (2, 0), flag = wx.ALIGN_RIGHT)
       sizer.Add(w, (2, 1), flag = wx.EXPAND)
       sizer.SetItemSpan(w, (1, 3))

this is only the basics, 4 lines for each piece of data in the form... without validators, event binding, styling,...
a total of 10 lines (being (very) generous) for each pice of data...
To avoid writting so much (DRY / WET) is one of my targets. I've written some code similar to the automated menu generation you ask.. for automated widgets creation based on a dict with decriptive info. Someday when I have the time I'll clean it up and make publicly available.

greetings,
jonhattan

thanks,
Stef Mientki

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Christopher Barker escribió:

jonhattan wrote:

       self.Bind(wx.EVT_MENU, func, item[1])

last line is wrong. correct is :

are you sure?

no, just pseudo-codding :slight_smile:

···

      self.Bind(wx.EVT_MENU, func, menu_item.GetId())

or
      self.Bind(wx.EVT_MENU, func, getattr(self, menuid))

self.Bind(wx.EVT_MENU, func, menu_item)

should work. If you pass in an item for the 3rd argument instead of an ID, it should pull the id from it.

The nice thing about all that is that you don't need to worry about IDs at all - just store a reference to the menu item itself in a dict or somewhere, and use that.

-Chris