如何创建只读文本控件但支持复制粘贴事件
在我的应用程序中,我有一个文本控件。
我希望这个文本控件是只读的,但当有人右键点击时,他们能够从这个控件中复制内容,然后可以把这个内容粘贴到其他文本控件中。
如果我把这个文本控件设置为只读(用 wx.TE_READONLY),那么复制和粘贴就不管用了。
我需要处理其他类型的 wx 事件吗?或者在创建文本控件对象时,我需要设置更多的 wx 样式标志吗?
提前谢谢你。
3 个回答
其实我也遇到过类似的问题。我需要一个文本框,让用户可以粘贴信息(或者通过菜单打开文件并读取)。然后这个应用会分析这些信息的正确性。不过,我不想让文本框可以编辑——这样会让人觉得可以在同一个文本框里进行修改,而这个应用只是用来分析的。是的,我知道这就是需求。
奇怪的是,我可以在MacOSX上创建一个只读的TextCtrl,它可以粘贴(但不能编辑),但在Windows上却不行。
为了兼容两个系统,我最终创建了一个可读写的文本框(MyWin, self).init(None, size=(800,600)),这样在Windows上就可以粘贴了,并且我还绑定了wx.EVT_TEXT事件(除了wx.EVT_TEXT_PASTE用于处理粘贴)。当文本框的内容发生变化时,会触发EVT_TEXT处理器,它会弹出一个对话框,告诉你不允许这样做。
在这个应用中,有一个布尔值this.painted起着重要作用:当this.painted为真时,就不允许修改文本框的内容。所以,粘贴处理器首先将this.painted设为假,然后修改TextCtrl的内容,最后再把this.painted设为真(否则在粘贴事件中也会弹出警告对话框,而我希望允许粘贴)。不幸的是,当EVT_TEXT处理器被触发时,窗口的内容已经被用户按键修改了。因此,应用还需要一个备份缓冲区,以便在检测到这种编辑时可以恢复到TextCtrl中。
根据Python文档,TextCtrl.ChangeValue()而不是SetValue()不应该触发EVT_TEXT事件(这本来会很方便),但我没能让它工作,可能是我没有足够的时间去调查,因为这件事本该昨天就完成。
这不是一个优雅的解决方案,但能用。
import wx
class MyWin(wx.Frame):
def __init__(self):
super(MyWin, self).__init__(None, size=(800,600))
self.painted = True
self.backup = ''
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.HSCROLL)
self.text.Bind(wx.EVT_TEXT_PASTE, self.onpaste)
self.text.Bind(wx.EVT_TEXT, self.ontextchange)
self.Show()
def onpaste(self, event):
if not wx.TheClipboard.IsOpened():
buf = wx.TextDataObject()
wx.TheClipboard.Open()
success = wx.TheClipboard.GetData(buf)
wx.TheClipboard.Close()
if success:
self.painted = False
self.backup = buf.GetText()
self.text.SetValue(self.backup)
self.painted = True
def ontextchange(self, event):
if self.painted:
dlg = wx.MessageDialog(self, 'Editing not allowed', '', wx.OK)
dlg.ShowModal()
dlg.Destroy()
self.painted = False
self.text.SetValue(self.backup)
self.painted = True
app = wx.App()
frame = MyWin()
app.MainLoop()
我们应该把 wx.EVT_TEXT_COPY 和 wx.EVT_TEXT_PASTE 这两个事件和文本控件绑定在一起。这样,即使文本控件是只读模式,用户也可以从这个文本控件中复制和粘贴数据。
嗯,我在Windows 7上,复制一个设置了wx.READ_ONLY
样式的textCtrl
时没有遇到任何问题。
你说你想把内容粘贴到另一个textCtrl
里——显然,你不能在你想要粘贴的textCtrl
上设置wx.READ_ONLY
样式。
试试下面的演示,你应该能从左边的textCtrl
(这是只读的)复制内容到右边的那个(这个没有设置只读样式)。
import wx
class MainWindow(wx.Frame):
def __init__(self, parent, id=-1):
wx.Frame.__init__(self,parent,id, size=(200,200))
self.panel = wx.Panel(self,wx.ID_ANY)
bsizer = wx.BoxSizer()
read_only_txtCtrl = wx.TextCtrl(self,-1,
"This textCtrl is read only",
style=wx.TE_MULTILINE|wx.TE_READONLY)
editable_txtCtrl = wx.TextCtrl(self,-1,
"This textCtrl is editable",
style=wx.TE_MULTILINE)
bsizer.Add(read_only_txtCtrl, 1, wx.EXPAND)
bsizer.Add(editable_txtCtrl, 1, wx.EXPAND)
self.SetSizerAndFit(bsizer)
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MainWindow(None)
frame.SetSize((200,200))
frame.Show()
app.MainLoop()