简体   繁体   中英

Bind menu event handlers in another module in wxPython

I'm building a menu for a frame with wxPython (python3). I want to separate the main.py from the menus.py - have these two separated files so the code is organized into smaller pieces.

I need to be able to pass control back to the main.py from menus.py. In particular, I need that the handlers for the events I bind for menu items (in menus.py) will reside in main.py, or, alternatively, have the handlers in menus.py, but reference objects in main.py (for example, to Close() the application for the "Exit" menu item.

This is what I have so far, and I tried both ways with no success. How is this achieved?

main.py

import wx
import menus

class MainFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "My App Title", size=(1200, 800))
        self.panel = wx.Panel(self, wx.ID_ANY)

        mainMenu = menus.MainMenu()
        mainMenu.build_main_menu(self)


    def onExit(self):
        self.Close()


if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    frame.Show()
    app.MainLoop()

menus.py

from wx import Menu, MenuBar, MenuEvent, MenuItem, Frame, EVT_MENU

class MainMenu(object):
    def build_main_menu(self, frame):

        self.fileMenu = Menu()
        exitMenuItem = self.fileMenu.Append(101, "E&xit", "Close the application")


        menuBar = MenuBar()
        menuBar.Append(self.fileMenu, "&File")
        frame.Bind(EVT_MENU, MainFrame.onExit(frame), exitMenuItem)
        frame.SetMenuBar(menuBar)

        return self

You are really close, but just not quite there. For this sort of thing, there is no need to wrap the menu creation code inside a class, so I changed that to just a function. Here's menu.py :

from wx import Menu, MenuBar, MenuEvent, MenuItem, Frame, EVT_MENU


def build_main_menu(frame):

    fileMenu = Menu()
    exitMenuItem = fileMenu.Append(101, "E&xit", "Close the application")

    menuBar = MenuBar()
    menuBar.Append(fileMenu, "&File")
    frame.Bind(EVT_MENU, frame.onExit, exitMenuItem)
    frame.SetMenuBar(menuBar)

Note that you need to call the onExit using the frame instance, not by trying to call it via a class ( MainFrame ) that you haven't even imported. Also you do not call an event handler in the bind operation. It will get called when the button is pressed.

Next I updated your main.py :

import wx
import menus

class MainFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "My App Title", size=(1200, 800))
        self.panel = wx.Panel(self, wx.ID_ANY)

        mainMenu = menus.build_main_menu(self)

    def onExit(self, event):
        self.Close()


if __name__ == "__main__":
    app = wx.App(False)
    frame = MainFrame()
    frame.Show()
    app.MainLoop()

There are two changes here. First we don't need to create an instance of the menu module's class as there is no class any longer. Secondly event handlers take two arguments: self and event .

Now it works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM