Russian Qt Forum

Qt => Общие вопросы => Тема начата: gueRRero от Май 04, 2009, 20:52



Название: Drag and Drop
Отправлено: gueRRero от Май 04, 2009, 20:52
Сразу прошу прощение за название, не отражающее сущности вопроса (другого не придумал))) и за размеры вопроса (с лаконичностью у меня так же плохо, как и с фантазией).
Итак, проблема следующая:
Нужно было наладить drag and drop между двумя списками. Для этого я написал класс, унаследованный от QListWidget (своего, собственно, ничего не придумал, а подсмотрел в книжке Жасмин Бланшет "Qt4: Программирование GUI на C++"):
Код
C++ (Qt)
List.h
 
#ifndef LIST_H
#define LIST_H
 
#include <QListWidget>
 
class List : public QListWidget
{
Q_OBJECT
 
public:
List(QWidget *prnt = 0);
 
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
 
private:
void startDrag();
QPoint startPos;
};
 
#endif //LIST_H

Код
C++ (Qt)
List.cpp
 
#include "List.h"
 
#include <QtGui/QApplication>
#include <QMouseEvent>
 
//--------------------------------------------------------------------------------------
 
List::List(QWidget *prnt /* = 0 */): QListWidget(prnt)
{
 
setSelectionMode(QAbstractItemView::SingleSelection);
setDragEnabled(true);
viewport()->setAcceptDrops(true);
setDropIndicatorShown(true);
 
}
 
//--------------------------------------------------------------------------------------
//---------------------------------Events-----------------------------------------------
//--------------------------------------------------------------------------------------
 
void List::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
startPos=event->pos();
QListWidget::mousePressEvent(event);
}
 
//--------------------------------------------------------------------------------------
 
void List::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton)
{
int distance = (event->pos() - startPos).manhattanLength();
if(distance >= QApplication::startDragDistance())
startDrag();
}
QListWidget::mouseMoveEvent(event);
}
 
//--------------------------------------------------------------------------------------
 
void List::dragEnterEvent(QDragEnterEvent *event)
{
List* source = qobject_cast<List *>(event->source());
if(source && source != this)
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
 
//--------------------------------------------------------------------------------------
 
void List::dragMoveEvent(QDragMoveEvent *event)
{
List* source = qobject_cast<List *>(event->source());
if(source && source != this)
{
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
 
//--------------------------------------------------------------------------------------
 
void List::dropEvent(QDropEvent *event)
{
List* source = qobject_cast<List *>(event->source());
if(source && source != this)
{
addItem(event->mimeData()->text());
event->setDropAction(Qt::MoveAction);
event->accept();
}
}
 
//--------------------------------------------------------------------------------------
//----------------------------------Functions-------------------------------------------
//--------------------------------------------------------------------------------------
 
void List::startDrag()
{
QListWidgetItem*  _item = currentItem();
if(_item)
{
QMimeData* mimeData = new QMimeData;
mimeData->setText(_item->text());
QDrag* drag = new QDrag(this);
drag->setMimeData(mimeData);
if(drag->exec(Qt::MoveAction) == Qt::MoveAction)
delete _item;
}
 
}

Все нормально работает, но меня смущает следующее место:
Код
C++ (Qt)
void List::startDrag()
{
QListWidgetItem*  _item = currentItem();
if(_item)
{
QMimeData* mimeData = new QMimeData;
mimeData->setText(_item->text());
QDrag* drag = new QDrag(this);
drag->setMimeData(mimeData);
if(drag->exec(Qt::MoveAction) == Qt::MoveAction)
delete _item;
}
 
}

mimeData и drag создаются, но нигде не удаляются. Не будет ли утечки памяти? Или я ошибаюсь, и они все-таки где-то удаляются?

З.Ы.: Попытка сделать их auto_ptr не удалась:
Код
C++ (Qt)
//List.h
.....
   std::auto_ptr<QMimeData> mimeData;
   std::auto_ptr<QDrag> drag;
.....
 
//List.cpp
......
void List::startDrag()
{
QListWidgetItem*  _item = currentItem();
if(_item)
{
mimeData.reset(new QMimeData);
mimeData->setText(_item->text());
drag.reset(new QDrag(this));
drag->setMimeData(mimeData.get());
if(drag->exec(Qt::MoveAction) == Qt::MoveAction)
delete _item;
}
 
}
Данная функция нормально срабатывает один раз, но на второй - падает на mimeData.reset(new QMimeData). Буду благодарен, если кто-нибудь объяснит, почему это происходит.


Название: Re: Drag and Drop
Отправлено: Rcus от Май 04, 2009, 21:10
Assistant -> Drag and Drop:
Цитировать
Drag and Drop Actions

In the simplest case, the target of a drag and drop action receives a copy of the data being dragged, and the source decides whether to delete the original. This is described by the CopyAction action. The target may also choose to handle other actions, specifically the MoveAction and LinkAction actions. If the source calls QDrag::exec(), and it returns MoveAction, the source is responsible for deleting any original data if it chooses to do so. The QMimeData and QDrag objects created by the source widget should not be deleted - they will be destroyed by Qt. The target is responsible for taking ownership of the data sent in the drag and drop operation; this is usually done by keeping references to the data.


Название: Re: Drag and Drop
Отправлено: gueRRero от Май 04, 2009, 21:18
Спасибо огромное. Везет же тем, кто знает английский. Понял не все, но главное, что they will be destroyed by Qt. Кстати, нету ли где-нибудь случайно Assistant на русском?


Название: Re: Drag and Drop
Отправлено: spirit от Май 04, 2009, 21:20
http://www.doc.crossplatform.ru/qt/4.5.0/ (http://www.doc.crossplatform.ru/qt/4.5.0/)


Название: Re: Drag and Drop
Отправлено: pastor от Май 04, 2009, 21:21
Кстати, нету ли где-нибудь случайно Assistant на русском?

В этом же разделе несколькими темами выше -  документация по Qt4 на русском )))


Название: Re: Drag and Drop
Отправлено: gueRRero от Май 04, 2009, 21:23
Пардон, туплю)))))


Название: Re: Drag and Drop
Отправлено: ритт от Май 05, 2009, 00:33
а давайте создадим прямо отдельный раздел "документация по Qt на русском" и закрепим там соответствующую ветку? /* и там же ещё можно было бы закрепить "как пользоваться поиском" :) */


Название: Re: Drag and Drop
Отправлено: gueRRero от Май 06, 2009, 19:12
В продолжение вопроса (Извините, если опять спрашиваю глупости). Могут ли функции setMimeData и exec бросить исключение, если могут, то что при этом будет с указателем?
В исходниках (qt/src/gui/kernel/gdrag.cpp) я исключений не увидел, но хотелось бы уточнить у специалистов (вдруг я не туда смотрел).


Название: Re: Drag and Drop
Отправлено: gueRRero от Май 06, 2009, 21:00
И еще. Вот только что обнаружил:
При перетаскивании, когда кнопку мыши отпускаешь, при этом мышь не двигая (совсем, чтоб даже не дрогнула), перетаскиваемый объект остается возле указателя мыши. Только когда мышку чуть шевельнешь, тогда только объект отпускается на нужное место.  Иногда все нормально, иногда так вот странно...
Это наблюдается и при использовании ранее приведенного кода и при использовании стандартных QListWidget, QTreeWidget.
Никто с таким не сталкивался? В чем может быть проблема? Как с ней бороться?