Russian Qt Forum

Qt => Вопросы новичков => Тема начата: koldun90 от Июнь 24, 2014, 08:53



Название: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 24, 2014, 08:53
Добрый день форумчане есть проблема в реализации драг дропа папок (драг дроп осуществляется treeview И treeview_2
в которых представлена файловая система)

Собственно treeview

Код:
model1->setRootPath(QDir::currentPath());
    model1->setFilter(QDir::AllDirs | QDir::Files |QDir::NoDot);
    model1->setReadOnly(false);    /
    ui->treeview->setModel(model1);

Собственно treeview_2

Код:
model2->setRootPath(QDir::currentPath());
    model2->setFilter(QDir::AllDirs | QDir::Files |QDir::NoDot);
    model2->setReadOnly(false);
    ui->treeview_2->setModel(model2);

Разрешаю виджетам принимать дропы

Код:
ui->treeView->setAcceptDrops(true);  
ui->treeView_2->setAcceptDrops(true);

В общем treeview и treeView_2 наследуются от mytreeview
Здесь все норм у меня

Далее идет класс mytreeview

Код:
#include <mainwindow.h>
#include "mytreeview.h"
#include <QApplication>
extern int flag;
mytreeview::mytreeview(QWidget *parent)
    :QTreeView(parent)
{
}
void mytreeview::mousePressEvent(QMouseEvent *event)    //событие при нажатии мышки
{
    if (event->button() == Qt::RightButton) //в случае нажатия правой кнопки мыши
    {
       emit sg();  //испускаем сигнал который активирует контекнсное меню
    }
    if (event->button()==Qt::LeftButton)     //если зажата левая кнопка мыши
    {
        m_ptDragPos=event->pos();   //определяем позицию указателя (первоначальная позиция указателя)
        emit activation();   //испускаем сигнал который активирует метод определения активации окна
    }
        QTreeView::mousePressEvent(event);   //передаем событию qtreeview
}
void mytreeview::keyPressEvent(QKeyEvent *event)   // событие при нажатии клавиши
{
    if (event->key()==Qt::Key_Control)   //если нажата кнопка контрол
    {
        emit sg2(1,1);   //посылаем сигнал на мультиселекцию
    }
    if (event->key()==Qt::Key_C && event->modifiers()==Qt::ControlModifier)      //при нажатии клавиш ctrl+c
    {
        emit ctrl_c();     //вызываем сигнал   который активирует копирование
    }
    if (event->key()==Qt::Key_Delete)   //в случае нажатия клавиши делет
    {
        emit key_delete();    //запускаем удаления объекта
    }
    if (event->key()==Qt::Key_V && event->modifiers()==Qt::ControlModifier)   //в случае нажатия сочетания клавиш кнтрл+в
    {
        emit ctrl_v();   //запускаем вставку
    }
    if (event->key()==Qt::Key_X && event->modifiers()==Qt::ControlModifier)   // в лучае нажатия клавиш кнтрл+х
    {
        emit ctrl_x();  //активирует сигнал который включает вырезание файла
    }
    if (event->key()==Qt::Key_F2)     //в случае нажатия клавиши F2
    {
        emit F2();
    }
        QTreeView::keyPressEvent(event);
}
void mytreeview::keyReleaseEvent(QKeyEvent *event)    // событие при отпускании клавиши
{
    if (event->key()==Qt::Key_Control)
    {
        emit sg2(2,0); //посылаем сигнал на одиночную селекцию
    }
    if (event->key()==Qt::Key_C && event->modifiers()==Qt::ControlModifier)
    {
        emit sg2(2,0); //посылаем сигнал на одиночную селекцию
    }
    if (event->key()==Qt::Key_V && event->modifiers()==Qt::ControlModifier)
    {
        emit sg2(2,0); //посылаем сигнал на одиночную селекцию
    }
    else
    {
        QTreeView::keyReleaseEvent(event);
    }
}
void mytreeview::startDrag()   //старт метода переноса данных
{
    pMimeData=new QMimeData; //создаем новый объект класса QMimeData
    pMimeData->setText("text/uri-list");   //вводим текст
    pDrag=new QDrag(this);     // создаем новый объект класса QDrag
    pDrag->setMimeData(pMimeData);
    pDrag->exec(Qt::CopyAction);
}
void mytreeview::mouseMoveEvent(QMouseEvent *event)  //событие при зажатой ЛКМ при перетаскивании в сторону
{
    if (event->buttons() && Qt::LeftButton) //если зажата левая кнопка мыши
    {
        int distance=(event->pos()-m_ptDragPos).manhattanLength();    //вычисляем расстояние текущей позиции указателя-первоначальной позиции указателя в которой была нажата ЛКМ
        if (distance> QApplication::startDragDistance())  //если расстояние больше чем возвращаемое расстояние статистического метода
        //startdragdistance(которое равно по умолчанию 4 пикселя) значит активируется операция перетаскивания
            //если меньше пользователя случайно двинул указаетль мыши
        {
            startDrag();
        }
    }
    QTreeView::mouseMoveEvent(event);
}
void mytreeview::dragEnterEvent(QDragEnterEvent *event)   //метод вызывается каждый раз когда объект пересекает границу виджета
{
    if (event->mimeData()->hasFormat("text/plain"))     // если перетаскиваемы объект файл
    {
        event->acceptProposedAction();  // сообщение виджета о готовности принять объект
    }
    QTreeView::dragEnterEvent(event);
}
void mytreeview::dropEvent(QDropEvent *event)
{
    QList<QUrl> urlList=event->mimeData()->urls();
    QString str;
    foreach (QUrl url,urlList)
    {
        str=str+url.toString()+"\n";
        MainWindow fv;
        fv.otobr(str);       
    }
    QTreeView::dropEvent(event);
}

Программа работает,но она как бы переносит только один файл или несколько.
Работает она так:
1)Вы зажали ЛКМ
2)затем начинаете отводить (когда вы отводите драг дроп по прежнему недоступен)
3) Драг дроп активируется только тогда когда вы ОТПУСКАЕТЕ ЛКМ( появляется значок+ в Linux)
А должно быть так соответственно чтобы когда я отвел выделенный элемент на достаточное расстояние активировалось перетаскивание( БЕЗ ОТПУСКАНИЯ ЛКМ)
А у меня почему то активируется только при отпускании ЛКМ.

Соответственно у меня вопросы:
1)Как решить вопрос чтоб драг дроп активировался без отпускания ЛКМ
2) Что нужно сделать (или что переопределить) чтобы программа драг дропала папку или несколько папок?


Название: Re: Drag drop папки или нескольких папок
Отправлено: carrygun от Июнь 24, 2014, 10:26
1) В startDrag() написать pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
2) Писать свою логику, например пихать список папок/файлов в mimeData для QDrag объекта.


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 24, 2014, 11:49
1) В startDrag() написать pDrag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
2) Писать свою логику, например пихать список папок/файлов в mimeData для QDrag объекта.

Вы не могли бы подробнее объяснить по второму пункту если можно....

по первому пункту ничего не изменилось
драг дроп активируется только после отпускания ЛКМ вне зависимости от расстояния


Название: Re: Drag drop папки или нескольких папок
Отправлено: kambala от Июнь 24, 2014, 12:20
2) юрлы там из воздуха не появятся, их надо добавить при создании объекта мимедата. а сейчас ты передаешь одну текстовую строку в мимедата.

Код:
        MainWindow fv;
        fv.otobr(str);   
эту чушь убери вообще. если тебе надо передать строки главному окну, испусти сигнал.

по возможности выложи компилируемый пример.


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 24, 2014, 13:22
2) юрлы там из воздуха не появятся, их надо добавить при создании объекта мимедата. а сейчас ты передаешь одну текстовую строку в мимедата.

чтобы реализовать драг дроп папок я так понял нужно:
Код:
pMimeData->setText();
    // в аргументе setText должен быть список всех файлов и папок которые я выбрал для драга да?
Код:
pMimeData=new QMimeData()
  или здесь их нужно добавить? И юрлы -это полные пути папок и файлов которые я выбрал для драга?



Название: Re: Drag drop папки или нескольких папок
Отправлено: kambala от Июнь 24, 2014, 14:25
документацию что ли не можешь открыть?
void QMimeData::setUrls(const QList<QUrl> & urls)
И юрлы -это полные пути папок и файлов которые я выбрал для драга?
да


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 24, 2014, 14:51
документацию что ли не можешь открыть?
void QMimeData::setUrls(const QList<QUrl> & urls)
И юрлы -это полные пути папок и файлов которые я выбрал для драга?
да
Теперь не понятно откуда мне взять список QList<QUrl>?
каким методом?
потому что у меня есть список только QStringlist


Название: Re: Drag drop папки или нескольких папок
Отправлено: Zerkin от Июнь 24, 2014, 15:08
Твой QStringList это по большому счету QList<QString>.  

Конструктор QUrl

Код
C++ (Qt)
QUrl(const QString & url )

Дальше, думаю, понятно.

Код
C++ (Qt)
QList<QUrl> fromStringList(const QStringList &urls, ParsingMode mode)
{
   QList<QUrl> lst;
   lst.reserve(urls.size());
   foreach (const QString &str, urls) {
       lst.append(QUrl(str, mode));
   }
   return lst;
}

https://qt.gitorious.org/qt/odysseus-qtbase/commit/6b9545a


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 24, 2014, 15:34
Твой QStringList это по большому счету QList<QString>.  

Конструктор QUrl

Код
C++ (Qt)
QUrl(const QString & url )

Дальше, думаю, понятно.

Код
C++ (Qt)
QList<QUrl> fromStringList(const QStringList &urls, ParsingMode mode)
{
   QList<QUrl> lst;
   lst.reserve(urls.size());
   foreach (const QString &str, urls) {
       lst.append(QUrl(str, mode));
   }
   return lst;
}

https://qt.gitorious.org/qt/odysseus-qtbase/commit/6b9545a

я так понял вы написали функцию которая превращает список QStringList в QList<QUrl>


Название: Re: Drag drop папки или нескольких папок
Отправлено: Zerkin от Июнь 24, 2014, 15:43
Правильно поняли  :)


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 25, 2014, 08:32
Правильно поняли  :)

ParsingMode mode--это что за параметр функции?

и еще вопрос по поводу QMimeData::setUrls(const QList<QUrl> & urls)
 если в списке окажется папка он ее дропнет как бы? или нужно для папки что то еще делать?



Название: Re: Drag drop папки или нескольких папок
Отправлено: gil9red от Июнь 25, 2014, 08:47
ParsingMode mode--это что за параметр функции?

QUrl::ParsingMode (http://qt-project.org/doc/qt-4.8/qurl.html#ParsingMode-enum)


Название: Re: Drag drop папки или нескольких папок
Отправлено: kambala от Июнь 25, 2014, 10:19
и еще вопрос по поводу QMimeData::setUrls(const QList<QUrl> & urls)
 если в списке окажется папка он ее дропнет как бы? или нужно для папки что то еще делать?
в view::dropEvent / model::dropMimeData опиши необходимую логику


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 25, 2014, 12:17
и еще вопрос по поводу QMimeData::setUrls(const QList<QUrl> & urls)
 если в списке окажется папка он ее дропнет как бы? или нужно для папки что то еще делать?
в view::dropEvent / model::dropMimeData опиши необходимую логику

view::dropEvent --это я так понял здесь нужно писать void mytreeview::dropEvent(QDropEvent *event)?
я так понял  когда будет происходить дроп
нужно смотреть что дропается?
если дропается файл то ничего не делать...(он как бы и по умлочанию дропается
а если дропается папка то нужно как бы скопировать эту папку в приемник(вместе со всеми поддиректориями и файлами).
Только получается как мне узнать путь куда я дропую программно.
Выделил файл, начал отодвигать, активировался дроп , навел на папку в другом окне( куда я собираюсь дропать ...)

ps: Получается дроп папки сводится грубо говоря к копированию этой папки(вместе с ее поддиректориями и файлами) из источника в приемник?


Название: Re: Drag drop папки или нескольких папок
Отправлено: kambala от Июнь 25, 2014, 20:56
bool QAbstractItemModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) [virtual] — выделенная часть позволит узнать куда совершается дроп
ps: Получается дроп папки сводится грубо говоря к копированию этой папки(вместе с ее поддиректориями и файлами) из источника в приемник?
естественно :)


Название: Re: Drag drop папки или нескольких папок
Отправлено: koldun90 от Июнь 25, 2014, 21:45
bool QAbstractItemModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) [virtual] — выделенная часть позволит узнать куда совершается дроп
ps: Получается дроп папки сводится грубо говоря к копированию этой папки(вместе с ее поддиректориями и файлами) из источника в приемник?
естественно :)
те нужно как я понял наследовать от QAbstractItemModel и переопределить dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent)
parent-это как бы папка?(грубо говоря я зажал ЛКМ начал драгать файл и завис над папкой куда я хочу вставить(но пока еще не вставил))
И вот пока я завис над этой папкой (она еще выделилась прямоугольничком таким в Linux ) это получается и есть const QModelIndex & parent?

Таким образом метод bool QAbstractItemModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) выполняется когда доступен дроп и я завис над папкой куда я хочу вставить файлик?


Название: Re: Drag drop папки или нескольких папок
Отправлено: kambala от Июнь 25, 2014, 22:36
наследоваться от QFileSystemModel. а она точно сама не может ДнД обрабатывать?

только dropMimeData модели надо самому вызывать в dropEvent насколько я помню.