如何让菜单选项在 WxPython 中做不同的事情?

How do I make menu options do different things in WxPython?

我的 WxPython 菜单有问题!在文件头中,我有 'File',其中有 2 个选项,'Save' 和 'Close'...当我单击保存时,我希望它打印“已保存”,当我计时时退出,应用程序应打印“已关闭”并关闭...但是如果我单击甚至保存它正在关闭!那么你能帮帮我吗?这是我的代码的一部分:

menubar = wx.MenuBar()
fileMenu = wx.Menu()

menubar.Append ( fileMenu, '&File' )

m1 = fileMenu.Append ( wx.ID_EXIT, 'Save' )
self.Bind ( wx.EVT_MENU, self.OnSave, m1 )

m2 = fileMenu.Append ( wx.ID_EXIT, 'Quit' )
self.Bind ( wx.EVT_MENU, self.OnQuit, m2 )

self.SetMenuBar ( menubar )

以及函数:

def OnSave ( self, event ):
    
    text = self.text_ctrl.GetValue()
    
    fil.write ( text )
    print ( "Saved file")

def OnQuit ( self, event ):
    
    print ( "Closed" )
    self.Close()

fileMenu.Append的第一个参数很重要。它用于区分一个菜单项和另一个菜单项,但您对两者使用了相同的值。

    m1 = fileMenu.Append(wx.ID_SAVE, 'Save')
    self.Bind(wx.EVT_MENU, self.OnSave, m1)
    
    m2 = fileMenu.Append(wx.ID_EXIT, 'Quit')
    self.Bind(wx.EVT_MENU, self.OnQuit, m2)

在我的程序中,我更喜欢使用 wx.NewId() 从系统获取免费 ID。如果您有这些“库存”菜单条目,ID_SAVE 和 ID_EXIT 就很有意义,但如果您自己创建条目,则可以:

    m3 = fileMenu.Append(wx.NewId(), 'My own menu item')
    self.Bind(wx.EVT_MENU, self.OnMyOwnFunction, m3)
    m4 = fileMenu.Append (wx.NewId(), 'Another menu item')
    self.Bind(wx.EVT_MENU, self.OnAnotherFunction, m4)

您对两个菜单项使用相同的 Id,即 wx.ID_EXIT,正如@Petr Blahos 指出的那样,这导致了您的问题。
然而,Petr 的回答存在一个问题,虽然在技术上是正确的,
wx.NewId 现在是 Deprecated,虽然它仍然有效,但已被 wx.NewIdRef 取代。

wx.NewId()
Generates an integer identifier unique to this run of the program.

Return type
int

Deprecated IDs generated by this function can possibly conflict with IDs used elsewhere in the application code. It is recommended to instead use the wx.ID_ANY ID to assign generated IDs for the controls, menu items and etc. that you create in the application. These IDs are guaranteed to not conflict with the other IDs that are in use in the application. For those cases where you need to create an ID that can be used more than once then please see wx.NewIdRef.

wx.NewIdRef(count=1)
Reserves a new Window ID (or range of WindowIDs) and returns a wx.WindowIDRef object (or list of them) that will help manage the reservation of that ID.

This function is intended to be a drop-in replacement of the old and deprecated wx.NewId function, with the added benefit that the ID should never conflict with an in-use ID or other IDs generated by this function.

wx.NewIdRef还有一个count的功能,所以可以用来grab一组你按需使用的id。即

>>> myIds = wx.NewIdRef(count=6)
>>> myIds
[WindowIDRef: -31973, WindowIDRef: -31972, WindowIDRef: -31971, WindowIDRef: -31970, WindowIDRef: -31969, WindowIDRef: -31968]
>>> useId = myIds[3].Id
>>> useId
-31970

请注意,wx.NewIdRefwx.ID_ANY-1 都可以在此菜单上下文中使用。看这个简单的例子:

import wx

class Test(wx.Frame):

    def __init__(self,parent):
        wx.Frame.__init__(self,parent,title="Frame aka Window",size = (300,200))
        panel = wx.Panel(self)
        self.status=self.CreateStatusBar()
        self.status.SetStatusText("Status bar text")
        menubar=wx.MenuBar()
        firstm=wx.Menu()
        secondm=wx.Menu()

        fm1 = wx.MenuItem(firstm, wx.NewIdRef(), 'New Window\tAlt+N')
        firstm.Append(fm1)
        self.Bind(wx.EVT_MENU, self.OnMenu1, id=fm1.GetId())
        fm2 = wx.MenuItem(firstm, wx.NewIdRef(), 'Open', "Text for the statusbar")
        firstm.Append(fm2)
        self.Bind(wx.EVT_MENU, self.OnMenu2, id=fm2.GetId())
        fm3 = wx.MenuItem(firstm, -1, 'Quit\tAlt+Q')
        firstm.Append(fm3)
        self.Bind(wx.EVT_MENU, self.OnMenu3, id=fm3.GetId())

        sm1 = wx.MenuItem(firstm, wx.ID_ANY, 'Re-Do', "Statusbar Re-Do")
        secondm.Append(sm1)
        self.Bind(wx.EVT_MENU, self.OnsMenu1, id=sm1.GetId())
        sm2 = wx.MenuItem(secondm, wx.ID_ANY, 'Un-Do', "Statusbar Un-Do")
        secondm.Append(sm2)
        self.Bind(wx.EVT_MENU, self.OnsMenu2, id=sm2.GetId())

        menubar.Append(firstm,"File")
        menubar.Append(secondm,"Edit")

        self.SetMenuBar(menubar)

        t = wx.StaticText(panel,-1,"Hello i'm a test", pos=(10,20))

    def OnMenu1(self, event):
        print("Menu item 1",event.GetId())

    def OnMenu2(self, event):
        print("Menu item 2",event.GetId())
        
    def OnMenu3(self, event):
        print("Menu item 3 Quit",event.GetId())
        self.Destroy()
                
    def OnsMenu1(self, event):
        print("2nd Menu item 1",event.GetId())

    def OnsMenu2(self, event):
        print("2nd Menu item 2",event.GetId())

if __name__=='__main__':
    app=wx.App()
    frame=Test(None)
    frame.Show()
    app.MainLoop()