Qt 4.x: как реализовать перетаскивание на рабочий стол или в папку? - PullRequest
18 голосов
/ 27 апреля 2010

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

Это все отлично работает; Вы даже можете перетащить файл с рабочего стола (или из открытой папки), и когда вы перетаскиваете значок файла в представление server-files-list-view, удаленный файл загружается на сервер.

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

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

Есть идеи?

Ответы [ 3 ]

7 голосов
/ 28 апреля 2010

Посмотрите на 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
    }
  }
}

Примеры кодирования с задержкой демонстрируют этот принцип.

Вам, вероятно, также придется переопределить hasFormat и formats, чтобы обеспечить соответствующие типы, application/octet-stream, вероятно, тот, который может принести вам наибольшую игру, вам, вероятно, придется прочитать о том, как конкретно Windows обрабатывает перетащите с помощью MIME типов.

Я не знаю, как вы будете указывать имя файла, под которым он будет сохранен, но вам, вероятно, придется столкнуться с проблемой Windows. Просмотр источника QWindowsMime также может помочь. Там может быть многоэтапный процесс, где вы получите запросы на text/uri-list данные для имен файлов, а затем application/octet-stream для данных.

Надеюсь, это поможет

3 голосов
/ 28 апреля 2010

Я думаю, вы делаете это неправильно.

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

Посмотрите на пример Dropsite , чтобы увидеть, как работают данные mime из других источников ...

Edit:

Похоже, что метод двойного копирования является стандартным, если вы не пишете расширение оболочки (по крайней мере, для Windows). Filezilla и 7zip оба делают это, они возвращают тип MIME "text / uri-list" с временным местоположением. Таким образом проводник копирует данные из временного местоположения в реальное. Ваше приложение может сделать то же самое, создать временный файл (или просто имя) без данных. Используя пример отложенного кодирования , создайте данные в раскрывающемся списке. Похоже, вся эта операция очень зависит от платформы. В Linux (под управлением KDE) я могу перетаскивать объекты только в зависимости от типа MIME. Похоже, что окна не так гибки.

2 голосов
/ 28 апреля 2010

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

Вы создаете QMimeData , не уверен, какой тип, но из того, что я видел здесь и здесь , возможно, "application / octet-stream" с вашим файлом как данные в QByteArray или «text / uri-list» с URL-адресом вашего файла.

Вы создаете QDrag и используете его метод setMimeData () и exec () (не уверены, какой QT :: DropAction выбрать).

Вот пример (дисклеймер: я сделал это с цветом, а не с файлами):

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);
        }
    }
}

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

...