如何创建只读文本控件但支持复制粘贴事件

1 投票
3 回答
9093 浏览
提问于 2025-04-16 04:08

在我的应用程序中,我有一个文本控件。
我希望这个文本控件是只读的,但当有人右键点击时,他们能够从这个控件中复制内容,然后可以把这个内容粘贴到其他文本控件中。

如果我把这个文本控件设置为只读(用 wx.TE_READONLY),那么复制和粘贴就不管用了。

我需要处理其他类型的 wx 事件吗?或者在创建文本控件对象时,我需要设置更多的 wx 样式标志吗?

提前谢谢你。

3 个回答

0

其实我也遇到过类似的问题。我需要一个文本框,让用户可以粘贴信息(或者通过菜单打开文件并读取)。然后这个应用会分析这些信息的正确性。不过,我不想让文本框可以编辑——这样会让人觉得可以在同一个文本框里进行修改,而这个应用只是用来分析的。是的,我知道这就是需求。

奇怪的是,我可以在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()            
1

我们应该把 wx.EVT_TEXT_COPY 和 wx.EVT_TEXT_PASTE 这两个事件和文本控件绑定在一起。这样,即使文本控件是只读模式,用户也可以从这个文本控件中复制和粘贴数据。

4

嗯,我在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()

撰写回答