Wxpython:在工具栏按钮下定位菜单
我在一个wx.ToolBar里有一个CheckLabelTool,我想在鼠标点击时让一个菜单直接弹出在它正下方。我正在尝试获取这个工具的位置,以便设置菜单的位置,但我试过的所有方法(比如GetEventObject、GetPosition等)都只给我工具栏的位置,所以菜单就会在工具栏下方弹出,但离这个工具很远。有没有什么建议?我需要这个工具能够切换状态和显示图标,但如果有其他更合适的工具,我也不一定非要用CheckLabelTool。
谢谢!
1 个回答
6
请阅读wxpython.org上关于PopupMenu方法的部分内容:
“在指定的坐标位置弹出给定的菜单,这个位置是相对于当前窗口的。当用户关闭菜单后,控制权会返回。如果选择了菜单项,就会生成相应的菜单事件,并像往常一样处理。如果没有指定位置,系统会使用鼠标光标的当前位置。”
你需要绑定到你的检查工具的EVT_MENU事件。一旦工具按钮被选中,你就可以弹出菜单。如果你不指定弹出菜单的位置,它会使用鼠标的当前位置,这正是你想要的。
如果你想让菜单在一个预先设定的位置弹出,而不依赖于鼠标的位置,你可以获取工具栏的屏幕位置,然后加上一个偏移量。
让我们来看一下代码:
[编辑:为了展示如何计算工具上任意点的位置,我修改了代码,使其在你点击工具后计算并显示工具栏上的各种点。菜单会出现在被点击按钮的右下角。在Windows上我测试是有效的。我很好奇在其他平台上是否也能正常工作。]
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():
# Get the position of the toolbar relative to
# the frame. This will be the upper left corner of the first tool
bar_pos = self.toolbar.GetScreenPosition()-self.GetScreenPosition()
# This is the position of the tool along the tool bar (1st, 2nd, 3rd, etc...)
tool_index = self.toolbar.GetToolPos(event.GetId())
# Get the size of the tool
tool_size = self.toolbar.GetToolSize()
# This is the upper left corner of the clicked tool
upper_left_pos = (bar_pos[0]+tool_size[0]*tool_index, bar_pos[1])
# Menu position will be in the lower right corner
lower_right_pos = (bar_pos[0]+tool_size[0]*(tool_index+1), bar_pos[1]+tool_size[1])
# Show upper left corner of first tool in black
dc = wx.WindowDC(self)
dc.SetPen(wx.Pen("BLACK", 4))
dc.DrawCircle(bar_pos[0], bar_pos[1], 4)
# Show upper left corner of this tool in blue
dc.SetPen(wx.Pen("BLUE", 4))
dc.DrawCircle(upper_left_pos[0], upper_left_pos[1], 4)
# Show lower right corner of this tool in green
dc.SetPen(wx.Pen("GREEN", 4))
dc.DrawCircle(lower_right_pos[0], lower_right_pos[1], 4)
# Correct for the position of the tool bar
menu_pos = (lower_right_pos[0]-bar_pos[0],lower_right_pos[1]-bar_pos[1])
# Pop up the menu
self.PopupMenu(MyPopupMenu(self), menu_pos)
if __name__ == "__main__":
app = ViewApp(0)
app.MainLoop()
这段代码的部分内容来自这里。