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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: (РЕШЕНО) QMouseEvent перестают поступать в QWidget при смене родителя  (Прочитано 7125 раз)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« : Сентябрь 08, 2015, 22:35 »

Есть большой главный QWidget, на котором лежат другие QWidget, для которых большой виджет родитель. У тех, которые лежат, есть обработка события QMouseEvent, по которому эти виджеты перемещаются в координатах родителя. Всё хорошо. Но среди детей, есть такие QWidget, которые сами становятся родителями, если какой-то QWidget въехал в их прямоугольник. Назовем их "рамками". То есть, если виджет перемещался по главному, и въехал в рамку, то рамка становится его родителем. А если перемещался и выехал из неё, то родителем снова становится главный виджет. Соответственно, если в рамке есть другие виджеты, то они перемещаются вместе с рамкой. Это всё работает почти хорошо, кроме одного неприятного эффекта - как только я меняю родителя виджету, в него перестают поступать события QMouseEvent. Кнопка мши при этом не отпущена, то есть, как только виджет въезжает в рамку, он перестаёт двигаться за мшой. Если кнопку отпустить, и снова взять виджет, уже лежащий в рамке и являющийся её потомком, то он начинает получать события мши и двигается. Двигается в рамке, пока он не выйдет за её границы, и у него родитель не сменится на главный большой виджет. Тогда опять события в него перестают поступать и он замирает.

Очевидно, это происходит вот почему:

Цитировать
Note: The widget becomes invisible as part of changing its parent, even if it was previously visible. You must call show() to make the widget visible again.

То есть, так как окно виджета становится не видимо, события мши перестают в него поступать. После смены родителя я разумеется делаю show(), но даже при том, что кнопка мши остаётся нажатой, события оно почему-то не ловит. Хотя, казалось бы, должно. Но дальше ещё смешнее - если кнопку отпустить, то при наведении курсора на виджет, события опять начинают поступать в него (при спрятывании окна виджета триггер приема событий переключился, события запретил, а кнопка мыши осталась нажата, при отпускании кнопки триггер опять переключился, события разрешил, хотя кнопка не нажата). Чего по идее наоборот не должно быть. И чё-то нет пока идеи, как это побороть...
« Последнее редактирование: Сентябрь 09, 2015, 16:53 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #1 : Сентябрь 09, 2015, 06:56 »

Так может не стоит менять родителя в процессе перемещения? А делать это только в момент отпускания кнопки мыши.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Сентябрь 09, 2015, 09:16 »

Менять родителя на ходу - затея неудачная. Если же вот "надо - и все тут" - перекрывайте QApplcation::notify (или вешайте фильтр на QApplication) и там уже принудительно посылайте кому надо событие "мши"  Улыбающийся.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #3 : Сентябрь 09, 2015, 10:51 »

По-хорошему drag'n'drop-ом должен заниматься родительский виджет, т.е. некий менеджер, а не сам drag-объект.
Записан

Qt 5.11/4.8.7 (X11/Win)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #4 : Сентябрь 09, 2015, 15:33 »

По-хорошему drag'n'drop-ом должен заниматься родительский виджет, т.е. некий менеджер, а не сам drag-объект.

Сначала так и было сделано, менеджером был "главный" виджет, по которому это всё ездит. Но получилось гораздо более громоздко и очень не удобно. Фишка в том, что каждый из виджетов, как главный, так и рамки, так и обычные виджеты - это всё плагины. Да ещё и динамически загружаемые... Смеющийся  Реализация оказалась значительно проще, когда сам перетаскиваемый объект находит, кто будет его новый родитель. Фишка-2 еще в том, что тут есть иерархия - "рамки" - это тоже виджеты, и они тоже перетаскиваются (код тот же самый, что и для других виджетов), и тоже могут быть детьми других "рамок" с неограниченным уровнем вложенности. Когда всё делается самим перетаскиваемым виджетом, общее решение получается значительно проще и компактнее - главному виджету вообще нет нужды разбираться в иерархии детей-родителей, он про неё ничего не знает. Он даже не знает, что по нему что-то перетаскивают - ему это не нужно.

Если же вот "надо - и все тут" - перекрывайте QApplcation::notify (или вешайте фильтр на QApplication) и там уже принудительно посылайте кому надо событие "мши"  Улыбающийся.

Не... Так можно было бы, если бы это было монолитное приложение. Но так как все эти получатели QMouseEvent находятся в плагинах, количество и состав которых заранее не известны, реализация была бы муторной. Поэтому:

Так может не стоит менять родителя в процессе перемещения? А делать это только в момент отпускания кнопки мыши.

Похоже, придётся переделать на такой вариант. Были некоторые заморочки, из-за которых менять родителя было удобнее при перетаскивании. От некоторых возможностей придётся, увы, отказаться.
« Последнее редактирование: Сентябрь 09, 2015, 15:38 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #5 : Сентябрь 09, 2015, 16:24 »

Не... не получается по-простому менять родителя при отпускании мыши.

Фишка в том, что виджет надо не только затаскивать внутрь рамки, но и вытаскивать из неё. А если родителем является рамка, то виджет перестает отображаться, когда выезжает из рамки. Чтобы этого не было, надо при начале перетаскивания менять родителя снова с рамки на главный виджет. Но при этом... виджет закрывается и перестаёт получать события. Замкнутый круг.

Не знаю, зачем это сделано, что виджет закрывается при смене родителя - но имхо это полный маразм. И еще баг потери связи с кнопкой мыши.

Записан

2^7-1 == 127, задумайтесь...
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Сентябрь 09, 2015, 16:34 »

Чтобы избежать всех этих заморочек задействуй QDrag.
Записан

Qt 5.11/4.8.7 (X11/Win)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #7 : Сентябрь 09, 2015, 16:50 »

Чтобы избежать всех этих заморочек задействуй QDrag.

Не, это ещё более громоздко и совершенно не нужно. Там маймить надо, размаймливать, с иконками возиться... В виджетах-рамках придётся делать ловушку, на главном виджете придётся делать ловушку. Куча не нужного кода. QDrag имеет смысл, когда надо тащить драг куда-то наружу, а тут перетаскивание только в границах главного виджета. Даже ограничитель сделан, чтобы за границы нельзя было вытащить

Решение очень близко - экспериментирую с grabMouse(), один раз получилось, но это было какое-то совпадение сигналов, повторить пока не удаётся.
« Последнее редактирование: Сентябрь 09, 2015, 17:34 от Гурман » Записан

2^7-1 == 127, задумайтесь...
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #8 : Сентябрь 09, 2015, 16:55 »

А вообще-то с grabMouse() после show() при смене родителя работает, надо только releaseMouse() делать в обработчике mouseReleaseEvent(QMouseEvent *event). Правда иногда почему-то при grabMouse() перепрыгивает фокус на другие приложения. Не могу уловить закономерность, это довольно редко. Возможно это дырка виндозы.
Записан

2^7-1 == 127, задумайтесь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Сентябрь 10, 2015, 08:36 »

Не...
Не...
Неконструктивный подход, Вы немедленно начинаете искать изъяны в предложенном решении. А поскольку Вы под впечатлением своих мыслей - найти очень легко. Поэтому дело кончается упрямым "не" Улыбающийся Попробуйте найти какое-то рациональное зерно. Ну например

Не... Так можно было бы, если бы это было монолитное приложение. Но так как все эти получатели QMouseEvent находятся в плагинах, количество и состав которых заранее не известны, реализация была бы муторной. Поэтому:
А Вас интересует только виджет захвативший "мшу" Улыбающийся

Да, и если Вы все еще на Qt4, то не факт что Ваша проблема воспроизведется в пятерке. Где кстати возможен удобный перехватчик на уровне окна
Записан
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #10 : Сентябрь 10, 2015, 12:28 »

Вы немедленно начинаете искать изъяны в предложенном решении.

А вы нет? Тогда я бы вас на работу не взял... Это обязательное действие, как часть конструктивного подхода. В системном программировании вообще второй обязательный шаг - поиск изъянов в предполагаемом решении, не важно, откуда оно взялось, извне заимствовано или самостоятельно придумано. Лучше найти их раньше, чем биться головой и переделывать потом. Это не всегда получается сделать, но это делать всегда надо. Я и от подчинённых всегда этого требую.

А Вас интересует только виджет захвативший "мшу" Улыбающийся

По отношению к обработке мши - да. Если имелась в виду групповая операция над несколькими виджетами, то к обработке событий мши она никакого отношения не имеет, сделана совершенно отдельно и отлично работает. С поддержкой undo и redo.

если Вы все еще на Qt4, то не факт что Ваша проблема воспроизведется в пятерке

Не факт, но в данном конкретном случае это совершенно не важно. Окно виджета также точно будет терять ввод, поскольку и в Qt 5.5 виджет также становится невидим при вызове setParent() - это описано в документации. Возможно только, что после show() виджет станет получать события мши без необходимости вызова grabMouse(). Но grabMouse() просто ничего не изменит (в Qt 5.5 он тоже есть). Или если изменит, его можно будет удалить. Но скорее всего, всё это будет работать точно также, как в 4.х.

А вообще вопрос исчерпан - всё уже работает, как требуется.
« Последнее редактирование: Сентябрь 10, 2015, 12:37 от Гурман » Записан

2^7-1 == 127, задумайтесь...
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #11 : Сентябрь 10, 2015, 12:32 »

А вообще вопрос исчерпан - всё уже работает, как требуется.
Ну да, до тех пор пока qt-ишники не вспомнят, что забыли вызвать releaseMouse() в hide()  Смеющийся
Записан

Qt 5.11/4.8.7 (X11/Win)
Гурман
Гуру общения
******
Offline Offline

Сообщений: 1442

Qt 2.2, 3.3, 4.5, 4,7, 4.8, 5.3, 5.6, 5.9, 5.12


Просмотр профиля
« Ответ #12 : Сентябрь 10, 2015, 12:39 »

А вообще вопрос исчерпан - всё уже работает, как требуется.
Ну да, до тех пор пока qt-ишники не вспомнят, что забыли вызвать releaseMouse() в hide()  Смеющийся

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

2^7-1 == 127, задумайтесь...
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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