Unlike the StyledTextCtrl, when you right-click in a RichTextCtrl, the caret is not automatically moved to the point in the text where you clicked before the context menu is displayed.
If I bind EVT_CONTEXT_MENU to a custom handler, I can get the coordinates of the point that was clicked from the event object and I can convert that position to client coordinates. However, I have not been able to find a way to convert those coordinates into a caret position.
The reason I want to be able to do this is so that I can dynamically add spelling options to the context menu before it is displayed. The options would depend on whether there was a spelling error at the point that was clicked and, if so, include a list of suggested corrections.
Can anyone suggest a way to get the position in the text?
I have included a simple application to demonstrate this issue.
import wx
import wx.richtext as rt
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.SetSize((400, 200))
self.SetTitle("Context Menu")
self.panel_1 = wx.Panel(self, wx.ID_ANY)
sizer_1 = wx.BoxSizer(wx.VERTICAL)
self.rtc = rt.RichTextCtrl(self.panel_1, wx.ID_ANY)
sizer_1.Add(self.rtc, 1, wx.EXPAND, 0)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_1.Add(sizer_2, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM | wx.TOP, 8)
self.close_button = wx.Button(self.panel_1, wx.ID_ANY, "Close")
sizer_2.Add(self.close_button, 0, 0, 0)
self.panel_1.SetSizer(sizer_1)
self.Layout()
self.Bind(wx.EVT_BUTTON, self.OnClose, self.close_button)
self.rtc.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)
self.rtc.SetValue("01234567890")
def OnClose(self, _event):
self.Destroy()
def OnContextMenu(self, event):
cp = self.rtc.GetCaretPosition()
ip = self.rtc.GetInsertionPoint()
print("Caret: %d Insertion: %d" % (cp, ip))
context_menu = self.rtc.GetContextMenu()
point = event.GetPosition()
point = self.ScreenToClient(point)
# How to access the text at the point that was clicked?
pass
self.rtc.PopupMenu(context_menu, point)
class MyApp(wx.App):
def OnInit(self):
self.frame = MyFrame(None, wx.ID_ANY, "")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
if __name__ == "__main__":
app = MyApp(0)
app.MainLoop()