Russian Qt Forum
Ноябрь 24, 2024, 14:30 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: DnD в дереве  (Прочитано 12186 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июнь 20, 2017, 17:17 »

Добрый день

Есть QTreeWidget, юзер выбрал неск айтемов и тянет их. Допустим мыша оказалась сейчас между item1 и item2. Как определить можно ли туда вставить выбранное (и значит нарисовать намек - линию разделителя) или нет? Собсно требуется точно такое же поведение как у Xcode когда дропаем файлы в проект

Спасибо
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Июнь 20, 2017, 17:26 »

Код:
QAbstractItemModel::canDropMimeData
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июнь 21, 2017, 12:31 »

Код:
QAbstractItemModel::canDropMimeData
Ага
Цитировать
Лучшие друзья девушек это бриллианты
Улыбающийся
Но и в этом случае его надо писать. Упростим задачу - нет никаких mime, нас интересует только move нодов, драг происходит в одном дереве, selection известен (т.е. строго говоря это не DnD). Если точка вставки известна, то дальше все очевидно (take + insert)   
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #3 : Июнь 21, 2017, 15:16 »

DnD во вью уже реализован и вызывает методы модели. Написать модель много раз проще, чем повторно перекрывать DnD.
Он не так прост, я когда-то курил этот код.
Лучше через модель. Можно даже через StandardItemModel - почти как тривиджет, только модель.
Upd: ну и при реализации DnD руками от MimeData никуда не уйти:)
« Последнее редактирование: Июнь 21, 2017, 15:19 от Авварон » Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Июнь 21, 2017, 15:22 »

Ну в простейшем случае, есть флажки у вьюхи, которые разрешают/запрещают мув айтемов.
Соответственно, никакой логики по запрету (верно я понял, что нужно именно это?) написать не получится.
Если же не требуется никакой логики, то юзайте флажки, мув должен автоматом работать.
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #5 : Июнь 21, 2017, 15:25 »

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

Та модель дерева: .h и .cpp
Записан

Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июнь 21, 2017, 15:59 »

Что касается "оформления" (отслеживания мыши и.т.п.) - с этим проблем нет.  К слову: влезать во все эти mime,  drag/drop event'ы есть смысл если DnD планируется между приложениями (редко) или хотя бы между разными виджетами/окнами одного приложения. Если же, как в данном случае, все в рамках одного дерева - проще самому. Ну в самом деле, чего светить dragImage за пределами виджета если никаких дропов там делать не собирались? Да и имедж тот у них совсем колхозный

Лучше через модель.
Ну так об этом и вопрос,
..мув должен автоматом работать.
Простой пример иерархии
Цитировать
Item0
   Item1 (selected, dragged)
            Item1_1
                           <---- мышь здесь
            Item1_2
Юзер не может вставить Item1 между его чайлдами Item1_1 и Item1_2. Однако это лишь простейший случай, есть и много других - вот о чем я хотел поговорить
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #7 : Июнь 21, 2017, 16:32 »

Что касается "оформления" (отслеживания мыши и.т.п.) - с этим проблем нет.  К слову: влезать во все эти mime,  drag/drop event'ы есть смысл если DnD планируется между приложениями (редко) или хотя бы между разными виджетами/окнами одного приложения. Если же, как в данном случае, все в рамках одного дерева - проще самому. Ну в самом деле, чего светить dragImage за пределами виджета если никаких дропов там делать не собирались? Да и имедж тот у них совсем колхозный

Лучше через модель.
Ну так об этом и вопрос,
..мув должен автоматом работать.
Простой пример иерархии
Цитировать
Item0
   Item1 (selected, dragged)
            Item1_1
                           <---- мышь здесь
            Item1_2
Юзер не может вставить Item1 между его чайлдами Item1_1 и Item1_2. Однако это лишь простейший случай, есть и много других - вот о чем я хотел поговорить

Что значит "проще самому?" У вас в драг эвент приходить MimeData и от неё никуда не деться. Что вы в неё положите (ид айтема или тупо row/column/parent) это ваше дело. По сути, это просто контейнер и вы сейчас звучите "зачем в QMap лезть разбираться, можно же самому, руками"
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июнь 21, 2017, 16:47 »

По сути, это просто контейнер и вы сейчас звучите "зачем в QMap лезть разбираться, можно же самому, руками"
Не надо все понимать слишком буквально. Написать красно-черное дерево руками можно, но это намного сложнее чем прочитать QMap или std::map

Что значит "проще самому?" У вас в драг эвент приходить MimeData и от неё никуда не деться. Что вы в неё положите (ид айтема или тупо row/column/parent) это ваше дело.
А здесь ситуация другая, резонов задействовать Qt DnD нет, можно mouseMove или еще лучше вторичный цикл событий (как я и делаю). Но все это отношения у теме не имеет

- есть выборка (selection) в дереве (неважно как о ней узнали, через мимю или нет)
- есть текущая точка вставки от мыши

Она валидна или нет?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #9 : Июнь 21, 2017, 16:49 »

https://github.com/qt/qtbase/blob/dev/src/widgets/itemviews/qabstractitemview.cpp#L3674
https://github.com/qt/qtbase/blob/dev/src/widgets/itemviews/qabstractitemview.cpp#L2107

Она валидна или нет?


https://github.com/qt/qtbase/blob/dev/src/widgets/itemviews/qabstractitemview.cpp#L2145
https://github.com/qt/qtbase/blob/dev/src/widgets/itemviews/qabstractitemview.cpp#L2193
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Июнь 21, 2017, 17:06 »

Изучение исходников полезно до определенного предела  Улыбающийся Вот та же иерархия что и выше, но мышь сместилась
Цитировать
Item0
   Item1 (selected, dragged)
            Item1_1
            Item1_2
                           <---- мышь здесь
И, как ни странно, Item1 сюда мувить можно Улыбающийся
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #11 : Июнь 21, 2017, 17:09 »

И чо? Я вам привел код, который это обрабатывает, нет?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Июнь 22, 2017, 08:38 »

И чо? Я вам привел код, который это обрабатывает, нет?
К сожалению не обрабатывает. И еще: если Вы заметили то в одно и то же место можно вставить неск способами, в Qt этого ф-ционала нет
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #13 : Июнь 22, 2017, 11:33 »

Ок, покурил ещё, действительно, случай, когда мышь внизу обрабатывается так: вставка идет в рут.
Насчет нескольких способов - можно либо между айтемами воткнуть, либо на сам айтем дропнуть. Или ещё какие способы?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Июнь 22, 2017, 11:41 »

Вроде все получилось. Псевдокод
Код
C++ (Qt)
// mouse is inbetween item1 & item2 (onr can be null)
bool CanInsertHere(  QTreeWidgetItem *& item1, QTreeWidgetItem *& item2 )
{
 while (item2 && item2->isSelected())
   item2 = itemBelow(item2);
 
 if (item2 && item2->HasSelectedParent()) return false;   // can't insert here
 
 while (item1 && (item1->isSelected() || item1->HasSelectedParent()))
   item1 = itemAbove(item1);
 
 return item1 || item2;
}
 
Правда это еще далеко не все  Улыбающийся
« Последнее редактирование: Июнь 22, 2017, 11:43 от Igors » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.077 секунд. Запросов: 23.