Disabling Drag and Drop in a RichTextCtrl

I have been investigating how to add the capability of using double-click and drag to select a word in a RichTextCtrl and then extend the selection to the right or left while keeping the mouse button pressed. That is standard behaviour in the TextCtrl and StyleTextCtrl, but not in the RichTextCtrl.

Anyhow, I managed to get my scheme to work, but I noticed a strange behaviour relating to drag and drop.

If I double-click on a word, and then wait for a second or so and then click on the word and start dragging the mouse, the cursor changes to indicate a drag operation is happening. However, when I release the mouse button an error dialog appears which says “An error occurred during drag and drop operation”. When you click on the Details button, it says “Could not write the buffer to an XML stream. You may have forgotten to add the XML file handler”.

It seems rather bizarre that it checks for an XML stream after allowing the drag and drop operation, rather than before!

The application I am working on doesn’t need drag and drop, so I wish to prevent it from being triggered. I have found that if I bind EVT_MOTION and then call self.rtc.SetPreDrag(False) in the event handler, it does prevent the drag and drop from happening. If the code below is run it shows the default drag and drop behaviour. If you uncomment the self.rtc.Bind() call in __init__(), drag and drop should be disabled.

Have I missed a more obvious way to switch off drag and drop?

import wx
import wx.richtext as rt

TEXT = (
    "Lorem IPSUM dolor sit amet, consectetur adipiscing elit, "
    "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
    "Vestibulum lectus mauris ultrices eros in cursus turpis. "
    "Dui vivamus arcu felis bibendum ut. "
    "Ac turpis egestas integer eget aliquet nibh praesent tristique magna. "
    "Mauris ultrices eros in cursus turpis massa tincidunt dui. "
    "Mi bibendum neque egestas congue. "
    "Nunc sed augue lacus viverra vitae congue eu consequat. "
    "Consectetur adipiscing elit pellentesque habitant morbi. "
    "Pellentesque elit ullamcorper dignissim cras tincidunt lobortis feugiat vivamus at. "
    "Ut lectus arcu bibendum at varius. "
    "Pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum odio. "
    "Eget aliquet nibh praesent tristique. "
    "Sit amet aliquam id diam maecenas ultricies mi eget. "
    "Iaculis nunc sed augue lacus viverra vitae congue eu. "
    "Fames ac turpis egestas sed tempus urna. A diam maecenas sed enim ut sem. "
    "Aenean pharetra magna ac placerat vestibulum lectus mauris ultrices. "
    "Velit egestas dui id ornare arcu odio ut sem nulla. "
    "Placerat duis ultricies lacus sed. "
    "Libero enim sed faucibus turpis in eu mi bibendum. "
)

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((600, 300))
        self.SetTitle("Test drag & drop")
        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.ALL | wx.EXPAND, 4)
        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)

        # UNCOMMENT THE FOLLOWING LINE TO PREVENT DRAG AND DROP
        # self.rtc.Bind(wx.EVT_MOTION, self.OnMotion)

        self.rtc.SetValue(TEXT)


    def OnClose(self, _event):
        self.Destroy()


    def OnMotion(self, event):
        # Prevent drag & drop
        self.rtc.SetPreDrag(False)
        event.Skip()


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()

I am using Python 3.8.10 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.3

Hi, RichardT

Same as Windows 10… DnD on RichTextCtrl doesn’t seem to work (bug?).
To disable DnD, just add one line

self.rtc.DropTarget = None

Similarly, in my use case, I always set this when using wx.stc to prevent a crash bug in PyFilling.
(cf. https://github.com/wxWidgets/Phoenix/issues/2043)

1 Like

Hi Kazuya,

Thanks for your reply and information.

I have now raised an issue for this at https://github.com/wxWidgets/Phoenix/issues/2094

Although the dialog shows ERROR icon, the inappropriate message dialog can be suppressed by

wx.Log.EnableLogging(False)

Cheers

1 Like