在wxpython中,TextCtrl上下文菜单的默认行为是插入符号移动到右键单击的TextCtrl中的位置。当我覆盖EVT_CONTEXT_MENU事件并创建自己的菜单时,此行为将丢失。有什么简单的方法可以改变这一点吗?
我的目标是允许标记右键单击的句子或段落,但当前的行为要求用户首先左键单击相关的句子/段落以移动插入符号,然后右键单击以选择要标记的内容。
相关代码:
self.textbox.Bind(wx.EVT_CONTEXT_MENU, self.textbox_context_menu)
def textbox_context_menu(self, event):
""" show context menu when right-clicking on text """
menu = wx.Menu()
menu.Append(self.mark_sentence_id, "mark sentence")
menu.Append(self.mark_paragraph_id, "mark paragraph")
self.PopupMenu(menu)
编辑:这里有一个可以执行的极简主义例子:
import wx
import wx.richtext as rt
class MCVE(wx.App):
""" App """
def OnInit(self):
frame = Frame()
frame.Show()
return True
class Frame(wx.Frame):
""" Frame """
def __init__(self):
style = wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.RESIZE_BORDER
super(Frame, self).__init__(parent=None, title="LabelingTool", style=style, size=(800, 600))
self.panel = Panel(parent=self)
class Panel(wx.Panel):
""" Panel """
def __init__(self, parent):
super(Panel, self).__init__(parent)
# textbox
hboxsizer = wx.BoxSizer(wx.HORIZONTAL)
text = "Lorem IpsumnnLorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eget enim vitae elit convallis ultrices. Sed vestibulum in metus id tempus. Phasellus tincidunt risus elit, id sagittis erat placerat quis. Donec ac porta tortor, non varius purus. Suspendisse euismod auctor maximus. Suspendisse nec orci vel dui posuere ultrices. Vivamus dictum vel enim nec interdum. Nunc tincidunt nulla sed facilisis suscipit. Nunc eget nisi ut turpis venenatis faucibus.nnInteger mauris nulla, malesuada quis lacus vitae, condimentum tincidunt dui. Aliquam non nisi aliquam, vulputate dolor ut, fringilla ligula. Nulla vitae tellus sit amet nulla ultrices pellentesque eu vitae lectus. Aliquam fringilla mauris tortor, et maximus lorem bibendum quis. Nam in magna gravida, accumsan libero accumsan, feugiat nisl. Donec tincidunt, tortor ut aliquam convallis, urna odio imperdiet ligula, dignissim vulputate ligula diam sit amet tortor. Ut a eros risus.nnCras et erat sodales, tempus nulla a, vulputate metus. Maecenas lacinia, nulla ac congue pharetra, lorem nibh pharetra metus, eu porttitor turpis leo ut lectus. Proin luctus rutrum mi id pharetra. Suspendisse aliquet id est nec efficitur. Maecenas dolor dui, vulputate et pulvinar at, venenatis id lorem. Praesent vel nisi ultrices massa rhoncus vestibulum. Nunc imperdiet consectetur pharetra. In cursus nec massa nec finibus. Aliquam et ligula bibendum, sodales mauris a, efficitur sapien. Ut mattis et ipsum eget sodales. Vestibulum maximus libero id ipsum placerat interdum at luctus risus. In finibus accumsan nunc, vitae posuere est interdum quis. Vivamus sed neque metus. Etiam fringilla efficitur lacus, vel aliquam purus lobortis vitae. Donec ut placerat orci. Etiam efficitur efficitur eleifend.nnAenean in imperdiet nisl. Donec dapibus neque tincidunt, fringilla velit vel, vestibulum velit. Sed at lorem id tortor accumsan interdum eu ut orci. Aenean convallis aliquet libero eu congue. In dapibus posuere massa, quis finibus neque volutpat et. Integer non massa tristique, gravida justo id, accumsan nibh. Ut ac nisl purus. Integer vestibulum sem in ante pellentesque, ac interdum augue faucibus.nnInteger bibendum eros vitae aliquam venenatis. Integer feugiat orci eu metus placerat, ut dictum leo posuere. Vivamus eget ligula vitae ante porttitor cursus. Nulla consectetur enim eu nisi aliquam mollis. Aliquam elementum consequat mauris, dignissim tempus libero sodales eu. In ultrices ullamcorper nulla, vel aliquet est vestibulum non. Nullam nec est ante. Phasellus eleifend lacinia nulla nec ultricies."
self.textbox = rt.RichTextCtrl(parent=self, value=text, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.textbox.Bind(wx.EVT_CONTEXT_MENU, self.textbox_context_menu)
hboxsizer.Add(self.textbox, proportion=1, flag=wx.EXPAND)
self.SetSizerAndFit(hboxsizer)
# event handling
self.tag_sentence_id = 100
self.tag_paragraph_id = 200
self.Bind(wx.EVT_MENU, self.menu_event)
def textbox_context_menu(self, event):
""" show context menu when right-clicking on text """
menu = wx.Menu()
menu.Append(self.tag_sentence_id, "tag sentence")
menu.Append(self.tag_paragraph_id, "tag paragraph")
self.PopupMenu(menu)
def menu_event(self, event):
""" handle context menu events """
event_id = event.GetId()
self.tag(event_id)
def tag(self, event_id):
# get caret position
caret_position = self.textbox.GetCaretPosition()+1
# tag by event
if event_id == self.tag_paragraph_id:
paragraph = self.find_paragraph(caret_position)
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
self.apply_tag((start, end))
elif event_id == self.tag_sentence_id:
sentence = self.find_sentence(caret_position)
start = self.textbox.GetValue().find(sentence.strip())
end = start + len(sentence.strip())
self.apply_tag((start, end))
def apply_tag(self, position):
self.textbox.SetStyle(position[0], position[1], wx.TextAttr(colText=wx.WHITE, colBack=wx.BLACK))
def find_paragraph(self, caret_position):
paragraphs = self.textbox.GetValue().split("nn")
for paragraph in paragraphs:
paragraph = paragraph.strip()
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
if start < caret_position < end:
return paragraph
def find_sentence(self, caret_position):
sentences = self.find_paragraph(caret_position).split(".")
for sentence in sentences:
sentence = sentence.strip()
start = self.textbox.GetValue().find(sentence)
end = start + len(sentence)
# append dot if applicable
if self.textbox.GetValue()[end] == ".":
sentence += "."
if start < caret_position < end:
return sentence
if __name__ == "__main__":
app = MCVE()
app.MainLoop()
如果注释掉self.textbox.Bind(wx.EVT_CONTEXT_MENU, self.textbox_context_menu)
行,则获得默认上下文菜单,该菜单具有在打开上下文菜单之前将插入符号移动到文本中右键单击的位置的所需行为;标记";用鼠标右键单击的句子/段落,而不首先用鼠标左键单击。
使用SetContextMenu并在之前创建菜单
import wx
import wx.richtext as rt
class MCVE(wx.App):
""" App """
def OnInit(self):
frame = Frame()
frame.Show()
return True
class Frame(wx.Frame):
""" Frame """
def __init__(self):
style = wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.RESIZE_BORDER
super(Frame, self).__init__(parent=None, title="LabelingTool", style=style, size=(800, 600))
self.panel = Panel(parent=self)
class Panel(wx.Panel):
""" Panel """
def __init__(self, parent):
super(Panel, self).__init__(parent)
# textbox
hboxsizer = wx.BoxSizer(wx.HORIZONTAL)
text = "Lorem IpsumnnLorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eget enim vitae elit convallis ultrices. Sed vestibulum in metus id tempus. Phasellus tincidunt risus elit, id sagittis erat placerat quis. Donec ac porta tortor, non varius purus. Suspendisse euismod auctor maximus. Suspendisse nec orci vel dui posuere ultrices. Vivamus dictum vel enim nec interdum. Nunc tincidunt nulla sed facilisis suscipit. Nunc eget nisi ut turpis venenatis faucibus.nnInteger mauris nulla, malesuada quis lacus vitae, condimentum tincidunt dui. Aliquam non nisi aliquam, vulputate dolor ut, fringilla ligula. Nulla vitae tellus sit amet nulla ultrices pellentesque eu vitae lectus. Aliquam fringilla mauris tortor, et maximus lorem bibendum quis. Nam in magna gravida, accumsan libero accumsan, feugiat nisl. Donec tincidunt, tortor ut aliquam convallis, urna odio imperdiet ligula, dignissim vulputate ligula diam sit amet tortor. Ut a eros risus.nnCras et erat sodales, tempus nulla a, vulputate metus. Maecenas lacinia, nulla ac congue pharetra, lorem nibh pharetra metus, eu porttitor turpis leo ut lectus. Proin luctus rutrum mi id pharetra. Suspendisse aliquet id est nec efficitur. Maecenas dolor dui, vulputate et pulvinar at, venenatis id lorem. Praesent vel nisi ultrices massa rhoncus vestibulum. Nunc imperdiet consectetur pharetra. In cursus nec massa nec finibus. Aliquam et ligula bibendum, sodales mauris a, efficitur sapien. Ut mattis et ipsum eget sodales. Vestibulum maximus libero id ipsum placerat interdum at luctus risus. In finibus accumsan nunc, vitae posuere est interdum quis. Vivamus sed neque metus. Etiam fringilla efficitur lacus, vel aliquam purus lobortis vitae. Donec ut placerat orci. Etiam efficitur efficitur eleifend.nnAenean in imperdiet nisl. Donec dapibus neque tincidunt, fringilla velit vel, vestibulum velit. Sed at lorem id tortor accumsan interdum eu ut orci. Aenean convallis aliquet libero eu congue. In dapibus posuere massa, quis finibus neque volutpat et. Integer non massa tristique, gravida justo id, accumsan nibh. Ut ac nisl purus. Integer vestibulum sem in ante pellentesque, ac interdum augue faucibus.nnInteger bibendum eros vitae aliquam venenatis. Integer feugiat orci eu metus placerat, ut dictum leo posuere. Vivamus eget ligula vitae ante porttitor cursus. Nulla consectetur enim eu nisi aliquam mollis. Aliquam elementum consequat mauris, dignissim tempus libero sodales eu. In ultrices ullamcorper nulla, vel aliquet est vestibulum non. Nullam nec est ante. Phasellus eleifend lacinia nulla nec ultricies."
self.textbox = rt.RichTextCtrl(parent=self, value=text, style=wx.TE_MULTILINE | wx.TE_READONLY)
# event handling
self.tag_sentence_id = 100
self.tag_paragraph_id = 200
self.menu = wx.Menu()
self.menu.Append(self.tag_sentence_id, "tag sentence")
self.menu.Append(self.tag_paragraph_id, "tag paragraph")
self.textbox.SetContextMenu(self.menu)
hboxsizer.Add(self.textbox, proportion=1, flag=wx.EXPAND)
self.SetSizerAndFit(hboxsizer)
self.Bind(wx.EVT_MENU, self.menu_event)
def menu_event(self, event):
""" handle context menu events """
event_id = event.GetId()
self.tag(event_id)
def tag(self, event_id):
# get caret position
caret_position = self.textbox.GetCaretPosition()+1
# tag by event
if event_id == self.tag_paragraph_id:
paragraph = self.find_paragraph(caret_position)
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
self.apply_tag((start, end))
elif event_id == self.tag_sentence_id:
sentence = self.find_sentence(caret_position)
start = self.textbox.GetValue().find(sentence.strip())
end = start + len(sentence.strip())
self.apply_tag((start, end))
def apply_tag(self, position):
self.textbox.SetStyle(position[0], position[1], wx.TextAttr(colText=wx.WHITE, colBack=wx.BLACK))
def find_paragraph(self, caret_position):
paragraphs = self.textbox.GetValue().split("nn")
for paragraph in paragraphs:
paragraph = paragraph.strip()
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
if start < caret_position < end:
return paragraph
def find_sentence(self, caret_position):
sentences = self.find_paragraph(caret_position).split(".")
for sentence in sentences:
sentence = sentence.strip()
start = self.textbox.GetValue().find(sentence)
end = start + len(sentence)
# append dot if applicable
if self.textbox.GetValue()[end] == ".":
sentence += "."
if start < caret_position < end:
return sentence
if __name__ == "__main__":
app = MCVE()
app.MainLoop()