wxWidgets drag and drop tutorial

posted on: 2010-05-04 11:00:21



In this tutorial I am going to teach you how to implement drag and drop with you wxWidget application. The ability to drag and drop is something which people ask a lot of questions about but there aren't many tutorials (if any! Other than the dnd source sample) so I decided to write this tutorial. This tutorial is focused on the wxTextDataObject for dragging text between controls. wxTextDataObject is derived from wxDataObject which can be used for passing objects other than simple text.

Dave Nicholas drag drop wxWidgets

The first thing that you must do is initiate the drag sequence. You will usually want to do this from the control that you are using to drag/copy/move the data from, although you can initiate the drag from any control. In my coded example I use the left mouse button event to initiate the drag. You must declare a wxTextDataObject variable and assign it a string that you wish to send. Then you declare a wxDropSource object, in which you pass a reference to the control sending the data. In my case I simply pass “this” as I am calling it from the control sending the data. You must then use the wxDropSource.SetData(wxDataObject& ) function passing it your data object. Lastly you need to call wxDropSource.DoDragDrop(int) to commence the drag (this function returns the following results if you need to know outcome of the drag: wxDragCopy, wxDragMove, wxDragLink, wxDragCancel or wxDragNone).

The contents of TextCtrlSource.h

class TextCtrlSource : public wxTextCtrl
{
	public:
		TextCtrlSource(wxWindow* parent, wxWindowID id, 
			const wxString& value , const wxPoint& pos , 
			const wxSize& size );

		void OnLeftDown(wxMouseEvent& event);
};

The contents of TextCtrlSource.cpp

TextCtrlSource::TextCtrlSource(wxWindow* parent, wxWindowID id, 
	const wxString& value , const wxPoint& pos, 
	const wxSize& size ) : wxTextCtrl(parent, id, value, pos, size)
{
	this->SetEditable(false);
	this->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( TextCtrlSource::OnLeftDown ), NULL, this );
}

void TextCtrlSource::OnLeftDown(wxMouseEvent& event)
{
	std::cout << "dragging" << std::endl;
	wxTextDataObject dragData(this->GetValue());
    	wxDropSource dragSource( this );
	dragSource.SetData( dragData );
	wxDragResult result = dragSource.DoDragDrop( TRUE );
}

Now that we have a have a drag source and the ability to send the data object. All we now need is the ability to receive it. In order to receive data your control needs to inherit wxDropTarget and implement the OnData member. In this tutorial for simplicity I am inheriting the wxTextDropTarget class which is derived from wxDropTarget, and I am implementing the OnDropText member. How this works is pretty straight forward, when the drop event occurs the OnDropText member is invoked. In my example I take the receiving wxString and append it to a wxListBox.

The contents of TextDropTarget.h

class TextDropTarget : public wxTextDropTarget
{
	public:
		TextDropTarget(wxListBox *listbox) { m_listbox = listbox; }

		virtual bool OnDropText(wxCoord x, wxCoord y, const wxString& text);

	private:
		wxListBox *m_listbox;
};

The contents of TextDropTarget.cpp

bool TextDropTarget::OnDropText(wxCoord x, wxCoord y, const wxString& text)
{
	std::cout << "recieving" << std::endl;
	
	m_listbox->Append(text);

	return true;
}

Dave Nicholas drag drop wxWidgets

The only other thing left to do now is to bind your wxDropTarget object to the wxListBox. You do this by calling the SetDropTarget member which inherited functionality from the wxWindow class. wxWindow is the base class for all visual controls, so you can assign any visual control a drop target.

Function called from constructor of MainDialogBase class.

void MainDialogBase::InitializeControls()
{
	this->m_listbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(200,200));
	
	this->m_textDropTarget = new TextDropTarget(this->m_listbox);
	this->m_listbox->SetDropTarget(this->m_textDropTarget);
	
	this->m_text1 = new TextCtrlSource(this, wxID_ANY, wxT("dragable text 1"), wxDefaultPosition, wxSize(150,50));
	this->m_text2 = new TextCtrlSource(this, wxID_ANY, wxT("dragable text 2"), wxDefaultPosition, wxSize(150,50));
	this->m_text3 = new TextCtrlSource(this, wxID_ANY, wxT("dragable text 3"), wxDefaultPosition, wxSize(150,50));
	
}

I hope you have found this tutorial useful as usual please forward me with any questions.

source and binary for this tutorial dn_drag_drop.tar.gz