Подтвердить что ты не робот

Qt 4.x: как реализовать перетаскивание на рабочий стол или в папку?

Я написал небольшое приложение для передачи файлов, написанное на С++, используя Qt 4.x... он регистрируется на сервере, показывает пользователю список файлов, доступных на сервере, и позволяет пользователю загружать или скачивать файлы.

Все это прекрасно работает; вы даже можете перетащить файл с рабочего стола (или из открытой папки), а при удалении значка файла в виде списка серверов файлов выгруженный файл будет загружен на сервер.

Теперь у меня есть запрос на противоположное действие... мои пользователи хотели бы, чтобы вытащить файл из списка файлов-серверов и на рабочий стол или в окно открытой папки, и этот файл загрузится в это место.

Это похоже на разумный запрос, но я не знаю, как его реализовать. Есть ли способ для приложения Qt найти каталог, соответствующий тому, где произошло событие "drop event", когда значок был сброшен на рабочий стол или в окно открытой папки? В идеале это был бы основанный на Qt механизм, основанный на платформе, но если этого не существует, то достаточно механизмов платформы для MacOS/X и Windows (XP или выше).

Любые идеи?

4b9b3361

Ответ 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);
        }
    }
}

Извините, это довольно неполно, я надеюсь, что это поможет немного.