I have a TreeCtrl object for which I want to implement a context menu n right-click. On Windows everything works but on Linux I have a problem:
On Linux, the wx.EVT_TREE_ITEM_RIGHT_CLICK method does not get called when I right-click, instead the wx.EVT_TREE_SEL_CHANGED gets called. If I remove the binding for wx.EVT_TREE_SEL_CHANGED the right-click method does get called.
I have tried using EVT_LEFT_UP and EVT_LEFT_UP instead of SEL_CHANGED but it makes no difference.
I have been searching for a couple of days to try and find out what is happening but cannot find anything relevant.
Any help gratefully received!
here is my code
self.Bind(
wx.EVT_TREE_SEL_CHANGED,
self.on_item_selected,
self._tree
)
self.Bind(
wx.EVT_TREE_ITEM_ACTIVATED,
self.on_item_activated,
self._tree
)
self.Bind(
wx.EVT_TREE_ITEM_RIGHT_CLICK,
self.on_tree_right_click,
self._tree
)
When I run the code below using wxPython 4.2.1 gtk3 (phoenix) wxWidgets 3.2.4 + Python 3.12.3 + Linux Mint 22
and right click on an item in the TreeCtrl
, both the EVT_TREE_SEL_CHANGED
and EVT_TREE_ITEM_RIGHT_CLICK
do get triggered and the popup menu is displayed.
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.tree = wx.TreeCtrl(self)
self.root = self.tree.AddRoot("Root")
self.tree.SetItemData(self.root, None)
for x in range(8):
self.tree.AppendItem(self.root, f"Tree Item {x}")
self.tree.Expand(self.root)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.tree, 1, wx.EXPAND, 0)
self.SetSizer(sizer)
self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeSelection)
self.tree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnTreeItemRightClick)
self.createPopupMenu()
def createPopupMenu(self):
self.popup_menu = wx.Menu()
for i in range(3):
label = f"Menu Item {i+1}"
item = self.popup_menu.Append(-1, label)
self.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item)
def OnPopupItemSelected(self, evt):
item = self.popup_menu.FindItemById(evt.GetId())
text = item.GetItemLabelText()
print(f"Menu item '{text}' selected")
def OnTreeSelection(self, evt):
print(f"Selected: '{self.tree.GetItemText(evt.GetItem())}'")
def OnTreeItemRightClick(self, evt):
pos = evt.GetPoint()
self.PopupMenu(self.popup_menu, pos)
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.panel = MyPanel(self)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, _evt):
self.Destroy()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
Works perfectly. Thank you!
I need to read up on the difference between self.Bind(… item) and self.item.Bind(…)
Paul