Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt GUI _ Нужны идеи как реализовать поведение собственного виджета

Автор: SABROG 15.4.2010, 8:52

Собственный виджет является контейнером для других виджетов. В собственном виджете нужно ловить все движения мышки, в том числе те, которые происходят над детьми. Если курсор мышки оказывается в определенной клиенсткой позиции, предположим в угле виджета, то нужно "снять" последнее изображение, которое содержит собственный виджет (grabWidget(), render() и т.п.), затем убрать/спрятать все дочерние виджеты, отрисовать в paintEvent'e сохранённое изображение. Когда курсор мышки покинет "зону интересов", то все дочерние виджеты снова показать на экране.

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

Автор: igor_bogomolov 15.4.2010, 9:19

Цитата(SABROG @ 15.4.2010, 9:52) *
нужно "снять" последнее изображение, которое содержит собственный виджет (grabWidget(), render() и т.п.), затем убрать/спрятать все дочерние виджеты, отрисовать в paintEvent'e сохранённое изображение. Когда курсор мышки покинет "зону интересов", то все дочерние виджеты снова показать на экране.
Можно воспользоваться QStacketWidget'ом. Т.е. сграбил виджет, отрисовал его в фоне, после чего переключаешь слой. Когда курсор мышки покинет "зону интересов", переключаешь слой обратно. Главное чтобы не было заметно разницы м/у реальным отображением и сграбленным.

Дальше ничего не понял. Не смог визуально представить, что ты хочешь получить. Можешь попроще как то разъяснить задачу, какова цель?

Автор: SABROG 15.4.2010, 9:27

Ок, попробую объяснить на примере QStackedWidget. Отводим курсор к правой стороне QStackedWidget'a, под ним рисуется стрелочка типа "Next page", нажимаем на стрелочку, происходит, предположим, эффект растворения одной страницы QStackedWidget'a в другой странице (на ту, куда переключаемся). То есть при определенных условиях нужно применять эффекты или анимацию к текущему изображению страницы (виджета), при этом эффект зависит от расположения мышки и от того где она кликает. Или другой эффект, через перетаскивание. Зажал мышку с правой стороны виджета и перетащил всё изображение справа налево таким образом, чтобы изображение "ехало" (scroll) и за ним появлялось изображение следующего виджета (страницы). То есть как в iphon'e.

Автор: igor_bogomolov 15.4.2010, 11:03

Не могу сказать чего то конкретного. Не делал пока таких вещей. Тут нужно пробовать, экспериментировать. Можно попробовать это реализовать на графической сцене, это упростит работу с анимацией и графическими эффектами.

Есть интересное http://www.youtube.com/watch?v=jjkUEipm4eA, найти бы исходнички

Автор: SABROG 15.4.2010, 11:11

Цитата(igor_bogomolov @ 15.4.2010, 12:03) *
Есть интересное видео, найти бы исходнички


Это же ролик из недавнего поста в блоге, там ссылка есть: http://gitorious.org/qt-components

Но я бы не хотел прибегать к графической сцене или к QML. Наследование от QGraphicsEffect упростило бы мне задачу, но он http://bugreports.qt.nokia.com/browse/QTBUG-9826.

Автор: Litkevich Yuriy 15.4.2010, 11:39

SABROG, а что если просто наложить виджет, который будет анимацией заниматься, поверх имеющегося (т.е. просто по нужным координатам и без компоновщика)?

Автор: SABROG 15.4.2010, 12:10

Цитата(Litkevich Yuriy @ 15.4.2010, 12:39) *
SABROG, а что если просто наложить виджет, который будет анимацией заниматься, поверх имеющегося (т.е. просто по нужным координатам и без компоновщика)?

Я думал об этом. По идее это должен быть "сестринский" (sibling) виджет для детей, но которому придется делать постоянно QWidget::rise()/lower(). По сути это тоже самое, что добавить дополнительный - "особый" виджет в QStackedWidget как страницу и переключаться на него в нужный момент. При этом сделать проверку, если идет попытка переключения страницы на этот "особый" виджет, то делать переключение на самую первую страницу, минуя этот виджет. Предположим я сделаю это, как тогда решить проблемы с отловом событий мыши на дочерних виджетах, которые поместит пользователь. Единственный вариант, который я знаю - в рекурсивном цикле ставить event filter на каждый виджет через installEventFilter. Как-то это не правильно, может есть мысли как это можно сделать иначе?

Автор: Litkevich Yuriy 15.4.2010, 12:14

Я никак не могу найти пример с которым я развлекался. Это переделка:
examples\dialogs\configdialog
там при переключении страниц, страницы появлялись плавно, но я сделал, чтобы виджет наложенный на страницу был прозрачен для событий мишки. Если найду, то выложу.

Автор: AD 15.4.2010, 12:15

А я на словах все не могу понять, чего хотят добиться. Можно хоть какой-то рисунок что-ли или хотя бы близкий аналог? Просто заинтересовала тема, а врубиться что хотят сделать - не могу!

Автор: SABROG 15.4.2010, 12:38

Цитата(Litkevich Yuriy @ 15.4.2010, 13:14) *
чтобы виджет наложенный на страницу был прозрачен для событий мишки

Я думал про аттрибут Qt::WA_TransparentForMouseEvents. Но, что насчет клавиатуры?

Цитата(AD @ 15.4.2010, 13:15) *
А я на словах все не могу понять, чего хотят добиться. Можно хоть какой-то рисунок что-ли или хотя бы близкий аналог? Просто заинтересовала тема, а врубиться что хотят сделать - не могу!

Предположим, что один цветок это одна страничка, а второй - вторая в QStackedWidget/QStackedLayout/QTabWidget


Тут какбы сдвиг одной страницы в другую заснят на середине перетаскивания мыши.

Автор: BRE 15.4.2010, 13:13

Цитата(SABROG @ 15.4.2010, 13:38) *
Тут какбы сдвиг одной страницы в другую заснят на середине перетаскивания мыши.

Так может это делать через QScrollArea?

Автор: SABROG 15.4.2010, 13:38

Цитата(BRE @ 15.4.2010, 14:13) *
Так может это делать через QScrollArea?

Слишком ограниченное применение. Я хочу добиться некой универсальной прослойки, которая позволит реализовать любой эффект над списком виджетов. Вот igor_bogomolov хотел реализовать http://www.forum.crossplatform.ru/index.php?showtopic=4573 похожий на Compiz. Почему бы и нет, только не средствами графической сцены, а самому заняться отрисовкой всей анимации.

Автор: Litkevich Yuriy 15.4.2010, 14:18

Нашёл код, который был для меня исходным: http://wiki.crossplatform.ru/index.php/Fading_Effects_with_Qt_4.1
А вот свои изменения, я, похоже, не сохранил.

Автор: igor_bogomolov 15.4.2010, 14:27

Цитата(SABROG)
Я хочу добиться некой универсальной прослойки, которая позволит реализовать любой эффект над списком виджетов.
Так графическая сцена и является этой прослойкой. Всё необходимое для этого уже ест: возможность добавлять виджеты на сцену, компоновать их (layout'ы), готовые средства для различных трансформаций, анимация, различные эффекты. Другое дело, что пока есть баги. Исправят, надеюсь в ближайших релизах.

Автор: Litkevich Yuriy 15.4.2010, 14:30

Цитата(Litkevich Yuriy @ 15.4.2010, 18:18) *
Нашёл код, ...
http://labs.trolltech.com/blogs/2007/08/21/fade-effects-a-blast-from-the-past/, автор этого дела писал

Автор: SABROG 15.4.2010, 15:47

Хочу такое http://zrusin.blogspot.com/2007/04/folding.html

только нигде нет исходников. Судя по всему используется QWindowSurface.

Автор: igor_bogomolov 15.4.2010, 16:01

Ух ты. Круть. Теперь я тоже хочу такое :)
Нужно найти способ сделать это без использования приватных классов. Иначе будут проблемы со сборкой под Linux

Тут есть ссылки на svn. К сожалению не могу проверить сейчас. Может это как раз ссылки на исходники
http://labs.trolltech.com/page/Graphics/Examples/Examples2

Автор: SABROG 15.4.2010, 16:14

Цитата(igor_bogomolov @ 15.4.2010, 17:01) *
Может это как раз ссылки на исходники

Насколько я знаю этот svn не работает. Проверить сейчас нет возможности. Когда я там пытался найти давно первый пример для box2d, то его не было.

Автор: Litkevich Yuriy 15.4.2010, 16:15

SVN-хранилище у них не работает больше, переехали в Git, но в git'е нет таких каталогов
:(

Автор: igor_bogomolov 15.4.2010, 16:22

Цитата
SVN-хранилище у них не работает больше, переехали в Git, но в git'е нет таких каталогов
Может где то в ихнем блоге поинтересоваться где можно исходнички взять?

Автор: SABROG 15.4.2010, 16:29

Цитата(igor_bogomolov @ 15.4.2010, 17:22) *
Может где то в ихнем блоге поинтересоваться где можно исходнички взять?

В комментах блога Zack'a просили, он чего-то молчит с 26 марта этого года.

Автор: Litkevich Yuriy 15.4.2010, 16:40

Цитата(igor_bogomolov @ 15.4.2010, 20:22) *
Может где то в ихнем блоге поинтересоваться где можно исходнички взять?
http://labs.trolltech.com/forums/topic/2000?replies=1, голосуйте/поддерживайте

Автор: Litkevich Yuriy 23.4.2010, 21:42

Хе-хе-хе. А я оказывается ещё тот куркуль. :blum1:

У меня есть рабочая копия их хранилища, в состоянии 902 версии. ftp://crossplatform.ru/misc/TrLabsFromSVN.7z

Автор: SABROG 23.4.2010, 23:28

Опяньки, гуляем мужики :lol:



void Folder::updateCache()
{
    //A lot faster than grabWidget because it doesn't actually
    // paint the widget, just grabs its backing store
    QPaintDevice *back = windowSurface()->paintDevice();
    QPixmap *px = dynamic_cast<QPixmap*>(back);
    if (px) {
        m_foldCache = *px;
    }
}


Угумс.

    QWidget *w1 = new QWidget;
    Ui_AppearanceConfigWidget *form1 = new Ui_AppearanceConfigWidget;
    form1->setupUi(w1);

    QWidget *w2 = new QWidget;
    Ui_EditConfigWidget *form2 = new Ui_EditConfigWidget;
    form2->setupUi(w2);

    m_first->setWrapper(w1);
    m_second->setWrapper(w2);


Врапперы, хмм.

Короче принцип у них такой.

- QWindowSurface используется, чтобы быстро сграбить окно. accept
- нужно точно прицеливаться в уголок, чтобы курсор мышки не попадал на пользовательский виджет. Для этого сделаны отступы. fail
- пользовательский виджет скрывается, чтобы освободить место для рисования на background'e под ними (на wrapper'e). fail

Откуда растут "ноги" у двух последних решений и почему fail:

В Qt нет стандартной возможности перехватывать события дочерних виджетов (даже если они намеренно блокируют их, нужен перехват). Отсюда отступ, который дает возможность пользователю кликнуть на виджет под пользовательским виджетом в маленьком пространстве в углу.

В Qt нет стандартной возможности рисовать родительскому виджету поверх всех своих детей. Отсюда уловка с сокрытием пользовательского виджета. Они конечно могли обойти это, но код бы серьезно вырос. У меня была надежда на бажный QGraphicsEffect о котором я запостил багрепорт и только через 10 дней тролли попросили меня предоставить компилируемый проект с демонстрацией проблемы. Затем они перевели багрепорт с "Paint system" на "Graphics view", что меня еще больше расстроило. Если они зарубят на корню возможность использовать QGraphicsEffect без графической сцены, то это меня сильно расстроит.

Собственно никакой магии в демке не оказалось. Без того же QWindowSurface в ней вполне реально обойтись. По крайней мере я теперь хоть знаю, что мыслил правильно и все мои догадки подтвердились.

Автор: Litkevich Yuriy 24.4.2010, 0:25

Цитата(SABROG @ 24.4.2010, 3:28) *
- нужно точно прицеливаться в уголок, чтобы курсор мышки не попадал на пользовательский виджет. Для этого сделаны отступы. fail
можно положить в угол прозрачный виджет, навёл на него мыша, "уголок бумаги" отогнулся, как сделано в некоторых типах веб рекламы

Цитата(SABROG @ 24.4.2010, 3:28) *
- пользовательский виджет скрывается, чтобы освободить место для рисования на background'e под ними (на wrapper'e). fail
опять же можно рисовать на наложеном поверх {полу}прозрачном виджете

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)