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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QTreeWidget - как отследить завершение Event'а?  (Прочитано 11918 раз)
Jokerochek
Гость
« : Декабрь 15, 2008, 14:15 »

Добрый день.
Qt занимаюсь недавно, поэтому многого ещё не понимаю.
Возник такой вопрос. У себя в программе использую стандартный QTreeWidget. Понадобилось настроить перетаскивание, но переписывать QTreeWidget не хочется.
При помощи eventFilter() я могу перехватить управление непосредственно перед тем, как произойдет QDrop. Но тогда я не могу получить информацию о том, куда собственно данные будут сброшены (ну кроме как плясок с бубном вокруг QDropEvent::pos() и QTreeWidget::itemAt(), опять же dropIndicatorPosition() в QtreeWidget является protected).
Можно ли каким-нибудь образом перехватить управление программой после завершения обработки QDropEvent?
И второй вопрос - можно ли как-нибудь получить доступ к dropIndicatorPosition() не переписывая стандартный класс?
Заранее, спасибо.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #1 : Декабрь 15, 2008, 14:18 »

Цитировать
Понадобилось настроить перетаскивание

А откуда куда будет происходить перетаскивание?
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Jokerochek
Гость
« Ответ #2 : Декабрь 15, 2008, 14:22 »

Сорри. Перетаскивание происходит в пределах виджета (фактически обычная работа с деревом - просто нужно изменения в дереве переносить на собственную структуру данных).
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #3 : Декабрь 15, 2008, 14:29 »

В таком случание ненужно ничего изобретать. Это уже все реализовано. Установите setAcceptDrops(true), setDragEnabled(true) для QTreeWidget
« Последнее редактирование: Декабрь 15, 2008, 14:31 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Jokerochek
Гость
« Ответ #4 : Декабрь 15, 2008, 14:33 »

Уточню. В самом QTreeWidget перетаскивание работает прекрасно. Но мой объект тоже хранит структуру этого дерева, и чтобы ее оперативно изменять мне нужно знать, что поменялось в QTreeWidget'е. подходящих сигналов, которые бы сообщали о изменении структуры дерева я не нашел. Фактически мне надо после завершения перетаскивания знать какой QTreeWidgetItem поменял своего родителя, и кто теперь его новый папа.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #5 : Декабрь 15, 2008, 14:48 »

Ясненько. Это можно всетяки седлать через эвент фильтр. Это будет выглядеть примерно так:

Код
C++ (Qt)
bool SomeClass::eventFilter(QObject *obj, QEvent *event)
{
   if (event->type() == QEvent::Drop && obj == treeWidget) {
       QDropEvent *dropEvent = static_cast<QDropEvent*>(event);
 
       QTreeWidgetItem *draggedItem = treeWidget->currentItem();
       QTreeWidgetItem *droppedOnItem = treeWidget->itemAt(dropEvent->pos());
 
       Q_ASSERT(draggedItem);
       Q_ASSERT(droppedOnItem);
 
       if (!droppedOnItem || !draggedItem)
               return false;
 
       if (draggedItem == droppedOnItem)
               return false;
 
       int draggedItemIdx = treeWidget->indexOfTopLevelItem(draggedItem);
       int droppedOnItemIdx = treeWidget->indexOfTopLevelItem(droppedOnItem);
 
       Q_ASSERT(draggedItemIdx >= 0);
       Q_ASSERT(droppedOnItemIdx >= 0);
 
       <do_something with indexes or items>
 
 
       return false; //event should be handled in QTreeWidget
   }
 
   return BaseClass::eventFilter(obj, event);
}
 
 
« Последнее редактирование: Декабрь 15, 2008, 14:50 от pastor » Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
SABROG
Гость
« Ответ #6 : Декабрь 15, 2008, 14:51 »

Или можно законнектить сигнал к своему слоту от модели, если он приходит конечно после drop'a

Цитировать
void QAbstractItemModel::dataChanged ( const QModelIndex & topLeft, const QModelIndex & bottomRight )   [signal]
This signal is emitted whenever the data in an existing item changes. The affected items are those between topLeft and bottomRight inclusive (of the same parent).
Note that this signal must be emitted explicitly when reimplementing the setData() function.

В итоге получишь диапозон элементов, которые были изменены.
« Последнее редактирование: Декабрь 15, 2008, 14:53 от SABROG » Записан
Jokerochek
Гость
« Ответ #7 : Декабрь 15, 2008, 15:18 »

Это будет выглядеть примерно так:
Спасибо. Работает, но... Опять похоже упирается в dropIndicatorPosition().
Если я сбрасываю элемент между двумя элементами, то treeWidget->itemAt(dropEvent->pos()) вернет один из этих двух элементов.
Записан
Jokerochek
Гость
« Ответ #8 : Декабрь 15, 2008, 15:19 »

Или можно законнектить сигнал к своему слоту от модели, если он приходит конечно после drop'a
так одна из проблем - как отследить, что сигнал отправлен после того, как отработал QDropEvent.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #9 : Декабрь 15, 2008, 15:33 »

Если я сбрасываю элемент между двумя элементами, то treeWidget->itemAt(dropEvent->pos()) вернет один из этих двух элементов.

Первое решение - это всетаки наследоватся от QTreeWidget
Второе решение - написать аналог dropIndicatorPosition самому. Если заглянуть в исходники, то мы увидем следующе:

Код
C++ (Qt)
QAbstractItemView::DropIndicatorPosition
QAbstractItemViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
{
   QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
   if (!overwrite) {
       const int margin = 2;
       if (pos.y() - rect.top() < margin) {
           r = QAbstractItemView::AboveItem;
       } else if (rect.bottom() - pos.y() < margin) {
           r = QAbstractItemView::BelowItem;
       } else if (rect.contains(pos, true)) {
           r = QAbstractItemView::OnItem;
       }
   } else {
       QRect touchingRect = rect;
       touchingRect.adjust(-1, -1, 1, 1);
       if (touchingRect.contains(pos, false)) {
           r = QAbstractItemView::OnItem;
       }
   }
 
   if (r == QAbstractItemView::OnItem && (!(model->flags(index) & Qt::ItemIsDropEnabled)))
       r = pos.y() < rect.center().y() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
 
   return r;
}

А вызов таков:

Код
C++ (Qt)
dropIndicatorPosition = position(event->pos(), q->visualRect(index), index);

Все данные для создания аналога есть.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
SABROG
Гость
« Ответ #10 : Декабрь 15, 2008, 15:39 »

Или можно законнектить сигнал к своему слоту от модели, если он приходит конечно после drop'a
так одна из проблем - как отследить, что сигнал отправлен после того, как отработал QDropEvent.

Ну MessageBox вставь в свой законнекченный слот и посмотри появится ли после того как отпустил мышку.
Записан
Jokerochek
Гость
« Ответ #11 : Декабрь 15, 2008, 15:42 »

pastor, спасибо. Буду разбираться.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #12 : Декабрь 15, 2008, 15:48 »

Незачто! Собственно говоря, вам нужен вот этот кусок:

Код
C++ (Qt)
const int margin = 2;
if (pos.y() - rect.top() < margin) {
   r = QAbstractItemView::AboveItem;
} else if (rect.bottom() - pos.y() < margin) {
   r = QAbstractItemView::BelowItem;
} else if (rect.contains(pos, true)) {
   r = QAbstractItemView::OnItem;
}

pos у вас есть, rect можно получить при помощи QTreeWidget::visualItemRect
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Guk
Гость
« Ответ #13 : Март 22, 2009, 22:44 »

Здравствуйте

У меня вопрос по Вашему коду:

Ясненько. Это можно всетяки седлать через эвент фильтр. Это будет выглядеть примерно так:

Имеется форма, на форме QTreeWidget.
Добавил в класс формы protected метод eventFilter, как у Вас в коде.
В конструкторе формы дописал
Код
C++ (Qt)
ui.treeWidget->installEventFilter(this);
Фильтрация работает на ура, но ни одного события из нужных:
QEvent::DragEnter
QEvent::DragLeave
QEvent::DragMove
QEvent::Drop
Все остальные события "сыпятся" нормально, а вот по перетаскиванию - ни одного.
Нужные свойства TreeWidget задействованы:
Код
C++ (Qt)
setDragEnabled(true);
setAcceptDrops(true);
setDropIndicatorShown(true);
Визуально элементы перетаскиваются нормально. Возникает такое впечатление, что ивенты Drag&Drop фильтруются кем-то другим до моего фильтра.

Отсюда и вопрос: что-то я делаю не так, не могу понять что...
Заранее, спасибо.
Записан
Jokerochek
Гость
« Ответ #14 : Март 23, 2009, 09:23 »

Здравствуйте

У меня вопрос по Вашему коду:

Добавил в класс формы protected метод eventFilter, как у Вас в коде.
В конструкторе формы дописал
Код
C++ (Qt)
ui.treeWidget->installEventFilter(this);
Попробуйте сделать
Код
C++ (Qt)
ui.treeWidget->viewport()->installEventFilter(this);
 
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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