Название: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Июль 10, 2018, 23:42 Добрый вечер.
Во всех примерах по перетаскиванию в Qt, которые я видел, создаётся собственный виджет и в нём перекрывается mousePressEvent. Допустим, у меня есть главное окно (наследник QMainWindow), в нём QTableView и другие виджеты. Я хочу, чтобы у меня работал drag'n'drop из QTableView в другие виджеты. Мне при этом обязательно отказываться от стандартного QTableView, создавать его потомка и там соответственно перекрывать mousePressEvent? Или это можно как-то разрулить в MainWindow? Создавать потомка QTableView не хочется, поскольку окно создано в дизайнере, не хочется руками тащить в .ui нестандартные объекты. Название: Re: Drag'n'drop из дочернего виджета Отправлено: Igors от Июль 11, 2018, 04:31 Я хочу, чтобы у меня работал drag'n'drop из QTableView в другие виджеты. Мне при этом обязательно отказываться от стандартного QTableView, создавать его потомка и там соответственно перекрывать mousePressEvent? Необязательно, можно фильтр навесить (installEventFilter). И если перетаскивание чисто "местное", то лучше на фильтре все и сделать, не используя DnD. Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Июль 11, 2018, 11:08 1Необязательно, можно фильтр навесить (installEventFilter). Спасибо за наводку, копну в эту сторону. Я installEventFilter раньше использовал, но только для обработки событий клавиатуры.Цитировать И если перетаскивание чисто "местное", то лучше на фильтре все и сделать, не используя DnD. Да, местное, с одного QTableView на другой.Название: Re: Drag'n'drop из дочернего виджета Отправлено: GreatSnake от Июль 11, 2018, 11:41 Using Drag and Drop with Item Views (http://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views)
И если перетаскивание чисто "местное", то лучше на фильтре все и сделать, не используя DnD. Вот зачем вы советуете человеку, явно не искушенному в этих вопросах, заниматься сексом?Название: Re: Drag'n'drop из дочернего виджета Отправлено: Igors от Июль 11, 2018, 12:02 Вот зачем вы советуете человеку, явно не искушенному в этих вопросах, заниматься сексом? По-моему так проще чем ковыряться в событиях DbDНазвание: Re: Drag'n'drop из дочернего виджета Отправлено: GreatSnake от Июль 11, 2018, 12:06 Т.е. самому городить мышиные грабы, установку курсора, иконки и чтобы всё было портабельно - это проще?
Название: Re: Drag'n'drop из дочернего виджета Отправлено: zhbr от Июль 12, 2018, 06:56 имхо проще делать стандартными средствами DnD Qt. Не так давно как раз делал это с QTableView - помогли следующие доки: http://doc.qt.io/qt-5/dnd.html и http://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views
правда надо иметь ввиду один баг (https://bugreports.qt.io/browse/QTBUG-67155), присутствующий во всех версиях. если док не достаточно, могу попробовать сделать выжимку Название: Re: Drag'n'drop из дочернего виджета Отправлено: Igors от Июль 13, 2018, 06:57 Т.е. самому городить мышиные грабы, установку курсора, иконки и чтобы всё было портабельно - это проще? Да, и намного. И причем тут портабельность - ну фильтруем 3 события мыши вместо 1, как она может пострадать? Название: Re: Drag'n'drop из дочернего виджета Отправлено: Racheengel от Июль 13, 2018, 10:32 Велосипед... Но зачем?
Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Июль 13, 2018, 11:47 Using Drag and Drop with Item Views (http://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views) Спасибо за наводку, я даже не предположил, что подобные вопросы могут на уровне модели решаться (и вроде как-то это не в духе Model-View вообще...).Буду пробовать. Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Сентябрь 13, 2018, 18:40 GreatSnake: ещё раз спасибо.
Прочитал эту доку, сделал решение через mimeData/dropMimeData. Из одного table view в другой данные внутри одной программы таскаются на ура. Сначала сделал, как и в примерах, через QDataStream. Потом, поскольку формат у меня, в общем-то, текстовый (известен как text/vcard), решил попробовать QTextStream. Тоже заработало. Только в конце записи строк в поток обязательно надо вызвать flush(), иначе итоговый QByteArray получится пустым. Да, я знаю о наличии QMimeData::setText(), но он, к сожалению, даёт записанным данным фиксированный тип text/plain, а это не совсем мой случай. И ещё остался вопрос, что мне делать в случае Qt::MoveAction для удаления записи в источнике. Делать специальный сигнал, который отсылается из dropMimeData, или есть стандартный механизм? Вообще, в доке есть такая фраза: Цитировать Although any combination of values from Qt::DropActions can be given, the model needs to be written to support them. For example, to allow Qt::MoveAction to be used properly with a list model, the model must provide an implementation of QAbstractItemModel::removeRows(), either directly or by inheriting the implementation from its base class. Я правильно понял, что мне надо перекрыть removeRows(), и он при необходимости вызовется? У меня, правда, не list, а table...Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Сентябрь 28, 2018, 15:07 Я правильно понял, что мне надо перекрыть removeRows(), и он при необходимости вызовется? К сожалению, на этом вопросе так и застрял. Вроде бы в кутешном примере puzzle removeRows() вызывается автоматом. У меня - нет.Набросал простейший пример (да, код небрежный) с list model. В главном окне два list view. Класс DraggedModel - наследник QAbstractListModel, выводит строки из списка ss (QStringList). Фрагмент конструктора главного окна: Код
Методы модели: Код Запускаю - removeRows() не вызывается. Чего ему может не хватать? Копирование работает, нареканий нет. Название: Re: Drag'n'drop из дочернего виджета Отправлено: Hellraiser от Сентябрь 28, 2018, 15:28 При переопределении removeRows внутри метода надо вызывать пару beginRemoveRows/endRemoveRows, а не beginResetModel/endResetModel.
Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Октябрь 01, 2018, 01:09 Э... Согласен, здесь погорячился, исправлю.
Но главную проблему это не решает. Сам-то removeRows() не вызывается, и тут уже не так важно, что я внутри него написал... Название: Re: Drag'n'drop из дочернего виджета Отправлено: Авварон от Октябрь 01, 2018, 03:41 http://doc.qt.io/qt-5/qabstractitemview.html#DragDropMode-enum ?
Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Октябрь 01, 2018, 12:18 Авварон, dragDropMode не особо помог. Зато рядышком у view есть свойство dragDropOverwriteMode - так вот, для list view, если его выставить в false, removeRows() начинает отрабатывать! Т.е. для списка работают и Copy, и Move.
Теперь делаю аналогичный пример для table view. Всё отличие в том, что виджеты не QListView, а QTableView, и у модели в дополнение к rowCount() переопределил ещё и columnCount(). Начинаю таскать. CopyAction по-прежнему работает, а с MoveAction проблема та же, что и раньше, т.е. removeRows() не вызывается. Уже начинаю перечитывать доку и придираться к словам: Цитировать For example, to allow Qt::MoveAction to be used properly with a list model, the model must provide an implementation of QAbstractItemModel::removeRows(), either directly or by inheriting the implementation from its base class. Может, этот приём только с list model и работает? А как же тогда с table view разруливать? Руками посылать сигнал в модель виджета-источника, чтобы она сама удаляла нужную строку? Да нет, чепуха какая-то, чем таблицы хуже списков... Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Октябрь 02, 2018, 16:45 Нашёл :)
В дополнение к dragDropOverwriteMode==false, для таблиц должно выполняться одно из двух условий:
В принципе, всё оказалось просто и логично. :) Если мы выделяем отдельные ячейки, тогда непонятно, что удалять. Но пока разбирался, чуть не поседел... Название: Re: Drag'n'drop из дочернего виджета Отправлено: DarkHobbit от Декабрь 22, 2018, 16:30 Впрочем, совет Igors навесить фильтр тоже не пропал втуне. Хотя применять его буквально действительно не стоило.
Дело в том, что кроме "местного" драг-н-дропа строк между табличками в моей программе есть ещё и "внешний" - из файлового менеджера можно перетащить имя на панельку (в моём случае, на QTableView), и программа его открывает. Панелек у меня одна или две. И в предыдущей реализации я перекрыл dropEvent() у главного окна... и долго ломал голову, как правильно определять, на какую именно панельку кинут URL. Сделал через определение координат события и сравнение с координатами дочерних виджетов. Способ очевидно некрасивый, и мог поломаться, если, например, мне захочется вместо горизонтального расположения панелек сделать вертикальное. А после этого обсуждения я переписал код. Установил фильтр на события для обоих QTableView, и в фильтре просто смотрю, кто получатель. Получилось намного изящнее. :) |