如何在wxPython中管理动态、不断变化的主菜单?

如何在wxPython中管理动态、不断变化的主菜单?,python,wxpython,Python,Wxpython,我正在用wxPython编写一个基于文档的应用程序,这意味着用户可以在多个窗口或选项卡中同时打开多个文档。有多种类型的文档,文档都可以处于不同的“状态”,这意味着主菜单中应该有不同的可用菜单选项 我知道如何使用wx.EVT\u UPDATE\u UI事件禁用和启用菜单项,但我不知道如何打开一个主菜单,根据当前有焦点的文档大幅更改结构和内容。我的主要问题之一是主菜单是在顶层窗口中创建的,它必须调用grand children和great grand children中的方法,这些方法甚至还没有创建

我正在用wxPython编写一个基于文档的应用程序,这意味着用户可以在多个窗口或选项卡中同时打开多个文档。有多种类型的文档,文档都可以处于不同的“状态”,这意味着主菜单中应该有不同的可用菜单选项

我知道如何使用
wx.EVT\u UPDATE\u UI
事件禁用和启用菜单项,但我不知道如何打开一个主菜单,根据当前有焦点的文档大幅更改结构和内容。我的主要问题之一是主菜单是在顶层窗口中创建的,它必须调用grand children和great grand children中的方法,这些方法甚至还没有创建


人为的例子;打开“JPEG”类型的文档时,主菜单应如下所示:

File Edit Compression Help 文件编辑压缩帮助 当用户将焦点(CTRL+Tab)切换到“PDF”类型的文档时,主菜单应更改为:

File Edit PDF Publish Help 文件编辑PDF发布帮助 “编辑”菜单应该包含一些与“JPEG”文档处于焦点时不同的选项



当前我只是在顶层窗口中的一个名为
create_main_menu
的函数中创建菜单,文档面板无法控制它。要实现我上面描述的主菜单方案,特别是在wxPython中,需要做些什么?

使用标准wx.menu可能唯一的方法是销毁并重新创建整个菜单栏。不过你也许可以把它藏起来。不管是哪种方式,我认为将一组方法放在一起,根据需要创建每个菜单栏都是最简单的。然后你可以摧毁一个,创造另一个


您还可以看看FlatMenu,因为它是纯Python的,更容易破解。

使用标准wx.Menu可能唯一的方法是销毁并重新创建整个菜单栏。不过你也许可以把它藏起来。不管是哪种方式,我认为将一组方法放在一起,根据需要创建每个菜单栏都是最简单的。然后你可以摧毁一个,创造另一个


您还可以看看FlatMenu,因为它是纯Python的,更容易破解。

使用标准wx.Menu可能唯一的方法是销毁并重新创建整个菜单栏。不过你也许可以把它藏起来。不管是哪种方式,我认为将一组方法放在一起,根据需要创建每个菜单栏都是最简单的。然后你可以摧毁一个,创造另一个


您还可以看看FlatMenu,因为它是纯Python的,更容易破解。

我找到了一种非常简洁的方法来实现这一点。首先,我创建“基本”主菜单栏,其中包含文件和帮助菜单项。然后我定义了一个类
EditorPanel
than,它是
wx.Panel
的一个子类,并定义了方法
bind\u main\u menu\u bar
release\u main\u menu\u bar
。当面板聚焦时,第一个方法接收主菜单栏,并向其中添加一些项目。以下是我的一个实现:

def bind_main_menu_bar(self, main_menu_bar):
    main_frame = wx.GetApp().GetTopWindow()

    self.main_menu_bar = main_menu_bar

    # Create the edit menu.
    self.edit_menu = edit_menu = shared.create_menu([
        (const.ID_UNDO, self.LABEL_UNDO_EMPTY),
        (const.ID_REDO, self.LABEL_REDO_EMPTY)
    ])

    # Create the tools menu.
    self.tools_menu = tools_menu = shared.create_menu([
        (const.ID_SELECT_ADDRESS_COLUMNS, 'Select address columns...'),
        (),
        (const.ID_VALIDATE_ADDRESSES, 'Validate selected addresses'),
        (const.ID_VALIDATE_ALL_ADDRESSES, 'Validate all addresses')
    ])

    # Bind some menu event handlers to the main frame.
    main_frame.Bind(wx.EVT_MENU, self.on_menu)
    main_frame.Bind(wx.EVT_UPDATE_UI, self.on_menu_update)

    # Insert the new menus into the main menu bar.
    main_menu_bar.Insert(1, edit_menu, 'Edit')
    main_menu_bar.Insert(2, tools_menu, 'Tools')
现在,当编辑器面板打开时,主菜单将收到一个编辑菜单和一个工具菜单,该菜单绑定到
EditorPanel
中的事件处理程序,这非常方便。当编辑器失去焦点时,将调用
release\u main\u menu\u bar
方法,该方法应将主菜单栏恢复到其原始状态。这是上述代码的对应项:

def release_main_menu_bar(self):
    main_frame = wx.GetApp().GetTopWindow()

    # Unbind the menu event handlers from the main frame.
    main_frame.Unbind(wx.EVT_MENU, handler=self.on_menu)
    main_frame.Unbind(wx.EVT_UPDATE_UI, handler=self.on_menu_update)

    # Remove the edit and tools menu from the main menu bar.
    self.main_menu_bar.Remove(1)
    self.main_menu_bar.Remove(1)

    # Reset the fields used for the menu.
    self.edit_menu = None
    self.tools_menu = None
    self.main_menu_bar = None

因此,每个想要编辑主菜单的编辑器只需对这两个方法进行子类化,它们就拥有完全的控制权。主框架将监视用户何时在编辑器之间切换并相应地调用方法。最大的问题是找出编辑器面板何时接收并失去焦点,这是我另一个问题的主题:

我想出了一个非常干净的方法来实现这一点。首先,我创建“基本”主菜单栏,其中包含文件和帮助菜单项。然后我定义了一个类
EditorPanel
than,它是
wx.Panel
的一个子类,并定义了方法
bind\u main\u menu\u bar
release\u main\u menu\u bar
。当面板聚焦时,第一个方法接收主菜单栏,并向其中添加一些项目。以下是我的一个实现:

def bind_main_menu_bar(self, main_menu_bar):
    main_frame = wx.GetApp().GetTopWindow()

    self.main_menu_bar = main_menu_bar

    # Create the edit menu.
    self.edit_menu = edit_menu = shared.create_menu([
        (const.ID_UNDO, self.LABEL_UNDO_EMPTY),
        (const.ID_REDO, self.LABEL_REDO_EMPTY)
    ])

    # Create the tools menu.
    self.tools_menu = tools_menu = shared.create_menu([
        (const.ID_SELECT_ADDRESS_COLUMNS, 'Select address columns...'),
        (),
        (const.ID_VALIDATE_ADDRESSES, 'Validate selected addresses'),
        (const.ID_VALIDATE_ALL_ADDRESSES, 'Validate all addresses')
    ])

    # Bind some menu event handlers to the main frame.
    main_frame.Bind(wx.EVT_MENU, self.on_menu)
    main_frame.Bind(wx.EVT_UPDATE_UI, self.on_menu_update)

    # Insert the new menus into the main menu bar.
    main_menu_bar.Insert(1, edit_menu, 'Edit')
    main_menu_bar.Insert(2, tools_menu, 'Tools')
现在,当编辑器面板打开时,主菜单将收到一个编辑菜单和一个工具菜单,该菜单绑定到
EditorPanel
中的事件处理程序,这非常方便。当编辑器失去焦点时,将调用
release\u main\u menu\u bar
方法,该方法应将主菜单栏恢复到其原始状态。这是上述代码的对应项:

def release_main_menu_bar(self):
    main_frame = wx.GetApp().GetTopWindow()

    # Unbind the menu event handlers from the main frame.
    main_frame.Unbind(wx.EVT_MENU, handler=self.on_menu)
    main_frame.Unbind(wx.EVT_UPDATE_UI, handler=self.on_menu_update)

    # Remove the edit and tools menu from the main menu bar.
    self.main_menu_bar.Remove(1)
    self.main_menu_bar.Remove(1)

    # Reset the fields used for the menu.
    self.edit_menu = None
    self.tools_menu = None
    self.main_menu_bar = None

因此,每个想要编辑主菜单的编辑器只需对这两个方法进行子类化,它们就拥有完全的控制权。主框架将监视用户何时在编辑器之间切换并相应地调用方法。最大的问题是找出编辑器面板何时接收并失去焦点,这是我另一个问题的主题:

我想出了一个非常干净的方法来实现这一点。首先,我创建“基本”主菜单栏,其中包含文件和帮助菜单项。然后我定义了一个类
EditorPanel
than,它是
wx.Panel
的一个子类,并定义了方法
bind\u main\u menu\u bar
release\u main\u menu\u bar
。当面板聚焦时,第一个方法接收主菜单栏,并向其中添加一些项目。以下是我的一个实现:

def bind_main_menu_bar(self, main_menu_bar):
    main_frame = wx.GetApp().GetTopWindow()

    self.main_menu_bar = main_menu_bar

    # Create the edit menu.
    self.edit_menu = edit_menu = shared.create_menu([
        (const.ID_UNDO, self.LABEL_UNDO_EMPTY),
        (const.ID_REDO, self.LABEL_REDO_EMPTY)
    ])

    # Create the tools menu.
    self.tools_menu = tools_menu = shared.create_menu([
        (const.ID_SELECT_ADDRESS_COLUMNS, 'Select address columns...'),
        (),
        (const.ID_VALIDATE_ADDRESSES, 'Validate selected addresses'),
        (const.ID_VALIDATE_ALL_ADDRESSES, 'Validate all addresses')
    ])

    # Bind some menu event handlers to the main frame.
    main_frame.Bind(wx.EVT_MENU, self.on_menu)
    main_frame.Bind(wx.EVT_UPDATE_UI, self.on_menu_update)

    # Insert the new menus into the main menu bar.
    main_menu_bar.Insert(1, edit_menu, 'Edit')
    main_menu_bar.Insert(2, tools_menu, 'Tools')
现在,当编辑器面板打开时,主菜单将收到一个编辑菜单和一个工具菜单,该菜单绑定到
EditorPanel
中的事件处理程序,这非常方便。当编辑器失去焦点时,将调用
release\u main\u menu\u bar
方法,该方法应将主菜单栏恢复到其原始状态。这是上述代码的对应项:

def release_main_menu_bar(self):
    main_frame = wx.GetApp().GetTopWindow()

    # Unbind the menu event handlers from the main frame.
    main_frame.Unbind(wx.EVT_MENU, handler=self.on_menu)
    main_frame.Unbind(wx.EVT_UPDATE_UI, handler=self.on_menu_update)

    # Remove the edit and tools menu from the main menu bar.
    self.main_menu_bar.Remove(1)
    self.main_menu_bar.Remove(1)

    # Reset the fields used for the menu.
    self.edit_menu = None
    self.tools_menu = None
    self.main_menu_bar = None
<