Drag and Drop at wxTreeCtrl

September 26th, 2009 Begemot Posted in Использование

Добавлял тут drag and drop к дереву, для своего легкого менеджера заметок, порядком намучался. А все оказывается не так и сложно, надо просто делать так как доктор прописал.

Задача была такая – есть дерево, хочу что бы перетаскивать можно было:

  1. Ветви внутри дерева
  2. Данные (текст) из дерева наружу
  3. Текст снаружи в дерево.

Где-то в вверху

 static const wxChar * FlashnoteTreeItemFormatId = wxT("FlashnoteTreeItemFormat");

Разумеется приходится писать своего наследника wxDropTarget, а вот порождать что-то свое от wxDataObject в итоге не пришлось, хотя сначала я и там нагородил целый класс:) Обошелся просто wxCustomDataObject. Итак упрощенный код, упрощенный потому что для решения реальной задачи приходится писать еще кучу кода, которая сейчас только затруднит понимание реализации перетаскивания.

Итак наш класс для DropTarget:

class FlashnoteTreeDropTarget : public wxDropTarget
{
public:
    FlashnoteTreeDropTarget(CMyFNTreeCtrl * _tree) : wxDropTarget(new wxDataObjectComposite), tree(_tree)
    {
        ((wxDataObjectComposite*)GetDataObject())->Add(new wxCustomDataObject(FlashnoteTreeItemFormatId));
        ((wxDataObjectComposite*)GetDataObject())->Add(new wxTextDataObject);
    }

    // override base class (pure) virtuals
    virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def)  { return OnDragOver(x, y, def); }
    virtual void OnLeave()  { }

    virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
    {
        if (!GetData())
        {  
            wxLogError(wxT("Failed to get drag and drop data"));  
            return wxDragNone; 
        }

        wxDataObjectComposite * data = (wxDataObjectComposite*) GetDataObject();

        const wxDataFormat format = data->GetReceivedFormat();
        const int size = data->GetDataSize(format);

        if (format == wxDataFormat(FlashnoteTreeItemFormatId))
        {
            wxTreeItemId item;
            data->GetDataHere(format, &item);
            wxASSERT(item.IsOk());
            wxLogDebug(wxT("Received  our format : id - %i, string id - %s, date item - %i"), format.GetFormatId(), format.GetId().c_str(), item);
        }
        else if (format.GetFormatId() == wxDF_UNICODETEXT)
        {
            wxString text;
            data->GetDataHere(format, text.GetWriteBuf(size));
            text.UngetWriteBuf(size);
            wxLogDebug(wxT("Received Text : format id - %i, data size = %i, text - %s"), format.GetFormatId(), size, text.c_str());
        }
        else wxFAIL_MSG(wxString::Format(_T("What format - %i"), format.GetFormatId()));

//      wxTreeItemId item = tree->HitTest(wxPoint(x, y));
        return def;
    }

private:
    CMyFNTreeCtrl  * tree;
};

Разумеется не забываем сделать SetDropTarget(new FlashnoteTreeDropTarget(this)); в процессе создание дерева. Дальше код обработчик начала перетаскивания EVT_TREE_BEGIN_DRAG(wxID_ANY, CMyFNTreeCtrl::OnBeginDrag)

    wxDataObjectComposite myData;  
   
    wxCustomDataObject * myIDData = new wxCustomDataObject(FlashnoteTreeItemFormatId);
    wxTreeItemId  item = event.GetItem();
    wxLogDebug(_T("send item - %i"), item);
    myIDData->SetData(sizeof(wxTreeItemId), &item);
    myData.Add(myIDData);

    wxTextDataObject * myTextData = new wxTextDataObject(wxT("Этот текст будет перемещен."));
    myData.Add(myTextData);

 
    wxDropSource dragSource(this);
    dragSource.SetData(myData);
    //wxDragResult result =
    dragSource.DoDragDrop(wxDrag_AllowMove);

За 100% компилируемость и рабочесть кода не ручаюсь, надергал из проекта, не проверял – может что забыл. Но идея должна быть понятна.

Related:

2 Responses to “Drag and Drop at wxTreeCtrl”

  1. Ух.. а чего у тебя такого произошло с синтакс хайлайтером?

  2. А он лайаут портит.