Qt 4.x: как реализовать перетаскивание на рабочий стол или в папку?
Я написал небольшое приложение для передачи файлов, написанное на С++, используя Qt 4.x... он регистрируется на сервере, показывает пользователю список файлов, доступных на сервере, и позволяет пользователю загружать или скачивать файлы.
Все это прекрасно работает; вы даже можете перетащить файл с рабочего стола (или из открытой папки), а при удалении значка файла в виде списка серверов файлов выгруженный файл будет загружен на сервер.
Теперь у меня есть запрос на противоположное действие... мои пользователи хотели бы, чтобы вытащить файл из списка файлов-серверов и на рабочий стол или в окно открытой папки, и этот файл загрузится в это место.
Это похоже на разумный запрос, но я не знаю, как его реализовать. Есть ли способ для приложения Qt найти каталог, соответствующий тому, где произошло событие "drop event", когда значок был сброшен на рабочий стол или в окно открытой папки? В идеале это был бы основанный на Qt механизм, основанный на платформе, но если этого не существует, то достаточно механизмов платформы для MacOS/X и Windows (XP или выше).
Любые идеи?
Ответы
Ответ 1
Посмотрите QMimeData
и его документацию, он имеет виртуальную функцию
virtual QVariant retrieveData ( const QString & mimetype, QVariant::Type type ) const
это означает, что вы перетаскиваете наружу, чтобы реализовать эти функции соответственно.
class DeferredMimeData : public QMimeData
{
DeferredMimeData(QString downloadFilename) : m_filename(downloadFilename)
virtual QVariant retrieveData (const QString & mimetype, QVariant::Type type) const
{
if (mimetype matches expected && type matches expected)
{
perform download with m_filename
}
}
}
Примеры delayed encoding показывают этот принцип.
Возможно, вам также придется переопределить hasFormat
и formats
, чтобы предоставить соответствующие типы, application/octet-stream
, возможно, тот, который может вам больше всего поиграть, вам, вероятно, придется прочитать, как окна специально обрабатывают перетаскивание с использованием типов mime.
Я не знаю, как вы укажете имя файла, под которым файл будет сохранен, но вам, вероятно, придется попасть в окна. Также может помочь просмотр источника QWindowsMime
. Там может быть многоступенчатый процесс, в котором вы получите запросы для text/uri-list
данных для имен файлов, а затем application/octet-stream
для данных.
Надеюсь, что это поможет
Ответ 2
Я думаю, вы идете об этом не так.
Вам все равно, куда падает, вы просто знаете, что он был сброшен. В DropEvent загрузите файл во временное место, а затем установите данные mime как загруженные. Конечно, это может закончиться второй копией на жесткий диск, с самого начала это будет кросс-платформа. После этого вы сможете оптимизировать его с помощью специальных вызовов на платформе.
Взгляните на пример Dropsite, чтобы узнать, как работают данные mime из других источников...
Edit:
Похоже, что метод двойной копии является стандартным, если вы не пишете расширение оболочки (по крайней мере для окон). Filezilla и 7zip оба делают это, они возвращают тип mime "text/uri-list" с временным расположением. Таким образом, исследователь копирует данные из временного местоположения в реальное. Ваше приложение может сделать то же самое, создать временный файл (или просто имя) без данных. Используя пример замедленного кодирования, создайте данные о падении. Вся эта операция очень специфична для платформы. В Linux (работает KDE) я могу перетаскивать только на основе типа mime. Похоже, что окна не так гибки.
Ответ 3
Вы просто реализуете часть перетаскивания. Вам не нужно знать, где происходит падение, потому что приложение, получающее его, будет обрабатывать его и решать, где хранить ваш файл.
Вы создаете QMimeData, не знаете, какой тип, но из того, что я увидел здесь и здесь, может быть, "application/octet-stream" с вашим файлом в виде данных в QByteArray или "text/uri-list" с URL-адресом вашего файла.
Вы создаете QDrag и используете его метод setMimeData() и exec() (не уверены в том, какой QT:: DropAction выбрать).
Вот пример (disclamer: я сделал это с цветами не файлов):
void DraggedWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
start_pos = event->pos();
}
void DraggedWidget::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
int distance = (event->pos() - start_pos).manhattanLength();
if (distance >= QApplication::startDragDistance())
{
/* Drag */
QMimeData *mime_data = new QMimeData;
mime_data->setData( ... );
QDrag *drag = new QDrag(this);
drag->setMimeData(mime_data);
drag->exec(Qt::CopyAction);
}
}
}
Извините, это довольно неполно, я надеюсь, что это поможет немного.