使用 Wxpython 实现工具栏按钮下的菜单定位

112 阅读2分钟

在使用 Wxpython 开发 GUI 程序时,用户希望在工具栏按钮上弹出菜单。但是,当用户点击按钮时,菜单会弹出在工具栏下方,而不是与按钮对齐。用户需要一种方法来获取按钮的准确位置,以便将菜单定位在正确的位置。

2、解决方案

为了解决这个问题,用户可以利用 PopupMenu 方法来实现菜单定位。PopupMenu 方法可以指定菜单弹出位置的坐标,并且它会使用鼠标当前位置作为默认值。如果用户希望菜单弹出在预设位置,而不是依赖鼠标位置,则需要计算工具栏的位置,并添加一定的偏移量来获取按钮的准确位置。

代码示例:

import wx

class ViewApp(wx.App):
    def OnInit(self):
        self.frame = ToolFrame(None, -1, "Test App")    
        self.frame.Show(True)
        return True        

class MyPopupMenu(wx.Menu):
    def __init__(self, parent):
        wx.Menu.__init__(self)

        self.parent = parent

        minimize = wx.MenuItem(self, wx.NewId(), 'Minimize')
        self.AppendItem(minimize)
        self.Bind(wx.EVT_MENU, self.OnMinimize, id=minimize.GetId())

    def OnMinimize(self, event):
        self.parent.Iconize()

class ToolFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(350, 250))

        self.toolbar = self.CreateToolBar()
        self.tool_id = wx.NewId()
        for i in range(3):
            tool_id = wx.NewId()
            self.toolbar.AddCheckLabelTool(tool_id, 'Tool', wx.EmptyBitmap(10,10))
            self.toolbar.Bind(wx.EVT_MENU, self.OnTool, id=tool_id)
        self.toolbar.Realize()
        self.Centre()
        self.Show()

    def OnTool(self, event):
        if event.IsChecked():
            # 获取工具栏相对于窗口的屏幕位置
            bar_pos = self.toolbar.GetScreenPosition()-self.GetScreenPosition()

            # 获取工具在工具栏中的位置索引
            tool_index = self.toolbar.GetToolPos(event.GetId())

            # 获取工具的大小
            tool_size = self.toolbar.GetToolSize()

            # 计算工具的左上角位置
            upper_left_pos = (bar_pos[0]+tool_size[0]*tool_index, bar_pos[1])

            # 计算工具的右下角位置
            lower_right_pos = (bar_pos[0]+tool_size[0]*(tool_index+1), bar_pos[1]+tool_size[1])

            # 在窗口中绘制工具的位置标记
            dc = wx.WindowDC(self)
            dc.SetPen(wx.Pen("BLACK", 4))
            dc.DrawCircle(bar_pos[0], bar_pos[1], 4)        
            dc.SetPen(wx.Pen("BLUE", 4))
            dc.DrawCircle(upper_left_pos[0], upper_left_pos[1], 4)        
            dc.SetPen(wx.Pen("GREEN", 4))
            dc.DrawCircle(lower_right_pos[0], lower_right_pos[1], 4)        

            # 计算菜单的弹出位置
            menu_pos = (lower_right_pos[0]-bar_pos[0],lower_right_pos[1]-bar_pos[1])

            # 弹出菜单
            self.PopupMenu(MyPopupMenu(self), menu_pos)

if __name__ == "__main__": 
    app = ViewApp(0)
    app.MainLoop()

在上述代码中,我们首先创建了一个 ViewApp 类,该类继承自 wx.App,负责初始化应用程序并创建主窗口。然后,我们创建了一个 MyPopupMenu 类,该类继承自 wx.Menu,负责定义弹出菜单的内容和行为。接下来,我们创建了一个 ToolFrame 类,该类继承自 wx.Frame,负责创建工具栏和处理工具按钮点击事件。在 OnTool 方法中,我们计算了工具的位置并绘制了位置标记。最后,我们创建了一个 app 对象并调用其 MainLoop 方法来启动应用程序。

通过使用 PopupMenu 方法和计算按钮位置,我们成功地实现了工具栏按钮下的菜单定位,从而解决了用户的问题。