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

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

Форум на CrossPlatform.RU _ Qt Система рисования. Печать _ QPaintEvent, installEventFilter, QPainter, Overpainting

Автор: SABROG 26.5.2009, 11:52

Есть желание рисовать на дочерних окошках, причем хочется оставить их оригинальный render и рисовать поверх уже готовой картинки. Ввиду того, что дочерних элементов может быть сколько угодно, я не могу (а скорее не хочу) унаследоваться от каждого из них. Поэтому я использую installEventFilter.

Получился такой код:

bool MainWindow::eventFilter(QObject *o, QEvent *e)
{
    if (e->type() == QEvent::Paint && o->isWidgetType()) {
        QPaintEvent *pe = (QPaintEvent *)e;
        QWidget *w = (QWidget *)o;
        qDebug() << "painting:" << o;

        QObject::eventFilter(o, e); //пытаемся вызвать оригинальный обработчик, чтобы сам себя нарисовал
        QPainter p(w); // пытаемся нарисовать что-то поверх уже нарисованного
        p.setRenderHint(QPainter::Antialiasing,true);
        p.drawLine(QPointF(0,0),QPointF(20,90));
        return true; //говорим системе, что мы перехватили, чтобы не отправлял событие дальше, а следовательно и не перерисовывал
    } else {
        return QObject::eventFilter(o, e);
    }
}


Но не получается. Если убрать первый QObject::eventFilter(o, e);, то виджет рисуется поверх линии, т.е. она остается на заднем плане. Если оставить, то рисуется вообще только одна линия, оригинального изображения виджета нет. paintEvent вызвать напрямую не могу, т.к. он protected, render() и repaint() приводят к рекурсии, естественно.

Автор: kwisp 26.5.2009, 12:01

Цитата(SABROG @ 26.5.2009, 12:52) *
оригинальный render

поясни пожалуйста что это такое?

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

SABROG, первая мысля в слух: Стало быть фильтр вызывается до того, как событие будет доставленно адресату. Тогда надо помозговать исходя из этой ситуации

Несколько мимо темы, такой код:

Цитата(SABROG @ 26.5.2009, 15:52) *
QPaintEvent *pe = (QPaintEvent *)e;
QWidget *w = (QWidget *)o;
стиль приведения не С++ный, а Сишный, и уж точно не принятый в Qt (qobject_cast<>, надобы)

Автор: SABROG 26.5.2009, 12:15

Цитата(kwisp @ 26.5.2009, 13:01) *
поясни пожалуйста что это такое?


Что-то типа QPixmap::grabWidget()
QPixmap pixmap(widget->size());
widget->render(&pixmap);

Оригинальный отрисовщик, который в paintEvent'e.

Цитата(Litkevich Yuriy @ 26.5.2009, 13:06) *
SABROG, первая мысля в слух: Стало быть фильтр вызывается до того, как событие будет доставленно адресату. Тогда надо помозговать исходя из этой ситуации


Давайте обмозгуем. Думаю postEvent тут тоже не поможет, т.к. опять будет рекурсия. Возможно флагами как-то, каждому объекту присвоить флаг (QMap)? Сначала вызвать оригинальный eventFilter, выставить flag в 1, потом как-то сгенерить опять событие, но при этом, чтобы старая картинка не затиралась.

Автор: Litkevich Yuriy 26.5.2009, 12:19

Цитата(SABROG @ 26.5.2009, 16:15) *
Думаю postEvent'ом тут тоже не обойтись, т.к. опять будет рекурсия.
дело даже не в рекурсии, http://www.forum.crossplatform.ru/index.php?showtopic=2812&view=findpost&p=20006, что событие рисования посылать получается, да вот рисовальщик (QPainter) ругается.

Цитата(SABROG @ 26.5.2009, 16:15) *
потом попробовать отрисовать что-то поверх
а как попробовать рисовать мимо события рисования, на виджетах ведь можно рисовать только в их обработчике рисования.

Автор: SABROG 26.5.2009, 12:31

Через флаг не получилось. Второй paintEvent затирает как-то все, что было до этого.

Цитата
а как попробовать рисовать мимо события рисования, на виджетах ведь можно рисовать только в их обработчике рисования.

В момент события QEvent::Paint из любого места, не обязательно внутри paintEvent метода.

Автор: kwisp 26.5.2009, 12:39

Цитата(SABROG @ 26.5.2009, 13:31) *
Второй paintEvent затирает как-то все, что было до этого.

в доке написано что пред вызовом нового обработчика все стирается. чтоб этого избежать используют updete(QRect)

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

---------------
нет оказывается затруднительно рисовать на дочерних элементах даже если они на хозяине :(

Автор: SABROG 26.5.2009, 12:51

Цитата(kwisp @ 26.5.2009, 13:39) *
вообще как я понимаю. если дочерние элементы находятся на хозяине то рисовать на них нет труда в обраьботчике хозяина рисуй и всё.

А ты попробуй, ничего не получится. Как ни изгаляйся, а рисование на родителе всегда будет позади детей.

Цитата(kwisp @ 26.5.2009, 13:39) *
Может попробовать рисовать то что хочется на картинке а потом картинку лепить на дочернее окошко.

Если ты добавляешь детей в окно, то они отображаются. Если ты их скрываешь через setVisible(false)/hide(), то они естественно не будут вести себя как нормальные видимые дети, события обрабатываться не будут, анимация и обновление происходить не будут. Заставить их прорисоваться через QWidget::render можно, но вот как от них избавиться, чтобы реально их на экране не было - вопрос. На ум приходит что-то типа послать по далеким далеким координатам, за пределы виджета, но тут сразу возникает вопрос с корректировкой координат и событий клавиатуры и мыши. Опять же наверняка будут проблемы. Есть еще вариант с дополнительным виджетом-прослойкой. Эта тема как-раз создана для того, чтобы избежать такого решения, т.к. виджет-прослойка это не рисование, а по сути хак. Я вообще троллей не понимаю в связи с этим, вроде всё можно, вроде рисовать можно как хочешь, а вот поверх всего только в примере overpainting QGlWidget'a. Бред...

Автор: kwisp 26.5.2009, 12:53

Цитата(SABROG @ 26.5.2009, 13:31) *
В момент события QEvent::Paint из любого места, не обязательно внутри paintEvent метода.

гдеж еще если в eventFilter не получилось?

Автор: SABROG 26.5.2009, 12:56

Цитата(kwisp @ 26.5.2009, 13:53) *
Цитата(SABROG @ 26.5.2009, 13:31) *
В момент события QEvent::Paint из любого места, не обязательно внутри paintEvent метода.

гдеж еще если в eventFilter не получилось?

В другом методе например, вызываемым внутри eventFilter'a.

Автор: Litkevich Yuriy 26.5.2009, 13:11

Цитата(SABROG @ 26.5.2009, 16:56) *
В другом методе например, вызываемым внутри eventFilter'a.
ну это и будет в фильтре событий.

Автор: SABROG 26.5.2009, 13:23

Цитата(Litkevich Yuriy @ 26.5.2009, 14:11) *
Цитата(SABROG @ 26.5.2009, 16:56) *
В другом методе например, вызываемым внутри eventFilter'a.
ну это и будет в фильтре событий.

Всё, что я хочу сказать, это то, что на методе paintEvent свет не сошелся при отрисовке, главное создать правильные условия/событие.

Но мы отклонились от темы, рисовать не вопрос. void QWidget::update ( const QRect & rect ) - не знаю как его можно прикрутить к фильтру событий, это надо его как-то вызвать на ребенке, чтобы он и линию не затер и себя смог отрисовать, врятли это возможно.

Автор: Litkevich Yuriy 26.5.2009, 16:00

SABROG, для случая не окна, глянь-ка http://www.forum.crossplatform.ru/index.php?showtopic=2077&view=findpost&p=13877

и http://www.prog.org.ru/index.php?topic=3518.msg14821;topicseen#msg14821

вот как делают троли:

bool HoverPoints::eventFilter(QObject *object, QEvent *event)
{
    if (object == m_widget && m_enabled) {
        switch (event->type()) {
        
        case QEvent::Paint:
        {
            QWidget *that_widget = m_widget;        // <---
            m_widget = 0;                            // <---
            QApplication::sendEvent(object, event);    // <---
            m_widget = that_widget;                    // <---
            paintPoints();
#ifdef QT_OPENGL_SUPPORT
            ArthurFrame *af = qobject_cast<ArthurFrame *>(that_widget);
            if (af && af->usesOpenGL())
                af->glWidget()->swapBuffers();
#endif
            return true;
        }
        default:
            break;
        }
    }

    return false;
}
интересные места выделены в коментариях

Автор: SABROG 26.5.2009, 16:24

До этих мест я добрался уже давно, но никак не могу понять в чем разница. Если ключ в QApplication::sendEvent(object, event);, то почему у меня это приводит к рекурсии и как следствие к крашу...
---
Тэкс похоже этот m_widget что-то типа моего флага:

if (object == m_widget && m_enabled)

Автор: kwisp 26.5.2009, 16:24

Цитата(Litkevich Yuriy @ 26.5.2009, 17:00) *
m_widget

что это за виджет ? полагаю член класса(принадлежит HoverPoints).
зачем его на время посылки события устанавливать в 0 а потом тут же возвращать прежнее значение?
странно....

Автор: SABROG 26.5.2009, 16:35

Похоже получается.



Как я понял sendEvent вызывает цикл eventFilter еще раз и таким образом заставляет нарисоваться виджетам. А нулевой m_widget (в моем случае обычный flag типа bool) нужен, чтобы прервать бесконечный цикл. Значит я все-таки рыл в правильную сторону.

Автор: Litkevich Yuriy 26.5.2009, 16:42

Цитата(SABROG @ 26.5.2009, 20:35) *
Похоже получается.
т.е. эти чёрные линии ты нарисовал поверх виджета в фильтре событий?

Автор: SABROG 26.5.2009, 16:46

Цитата(Litkevich Yuriy @ 26.5.2009, 17:42) *
Цитата(SABROG @ 26.5.2009, 20:35) *
Похоже получается.
т.е. эти чёрные линии ты нарисовал поверх виджета в фильтре событий?


Первая линия рисуется для centralWidget(), вторая для его чайлдов, в данном случае это только QGroupBox, т.к. надо еще писать функцию рекурсии, чтобы пройтись по всему дереву, а у меня пока руки не дошли.

Автор: Litkevich Yuriy 26.5.2009, 16:48

а можешь тестовый примерчик вылочить, с минимумом виджетов. Найду время тоже побалуюсь.

Автор: SABROG 26.5.2009, 16:50

Цитата(Litkevich Yuriy @ 26.5.2009, 17:48) *
а можешь тестовый примерчик вылочить, с минимумом виджетов. Найду время тоже побалуюсь.

Попробую. Можно будет потом в faq добавить, а то даже на QtCentre все уверенны, что это невозможно :)

Автор: SABROG 26.5.2009, 18:25

Накатал простенький пример. Правда не самый удачный, т.к. не показывает преимущества технологии. Отличить от обычного paintEvent'a не получится, но тем не менее шрифт, который обычно рисуется на фоне - рисуется поверх вводимого текста.



 ChildOverpainting.zip ( 1.78 килобайт ) : 213
 

Автор: SABROG 26.5.2009, 19:22

Господа, поздравьте меня. Наконец-то я это сделал:


Автор: DmP 26.5.2009, 19:47

SABROG, сорри за офтоп, но чем делаются такие картинки?

Автор: SABROG 26.5.2009, 20:34

Цитата(DmP @ 26.5.2009, 20:47) *
SABROG, сорри за офтоп, но чем делаются такие картинки?

Camtasia Studio.

Цитата(Litkevich Yuriy @ 26.5.2009, 13:14) *
Несколько мимо темы, такой код:
Цитата(SABROG @ 26.5.2009, 15:52) *
QPaintEvent *pe = (QPaintEvent *)e;
QWidget *w = (QWidget *)o;
стиль приведения не С++ный, а Сишный, и уж точно не принятый в Qt (qobject_cast<>, надобы)


Грешу понемногу, хочется как обычно сделать быстро, а вспоминать является ли QEvent - QObject'ом влом :) (и кстати, не является, т.ч. static_cast, но я в этих cast'ах плаваю, т.ч. это мне бы еще пришлось блог Алёны открывать ;) ).

Автор: igor_bogomolov 26.5.2009, 22:09

Может я что то делаю не так, но нарисовать что то приемлемое у меня не получается. Не подскажешь как координаты привести к единым. Т.е. как провести прямую линию через несколько виджетов, и она при этом не ломалась.


Раскрывающийся текст
form::form(QWidget *parent) : QMainWindow(parent)
{
    setMinimumSize(200, 180);
    centralwidget = new QWidget(this);
    setCentralWidget(centralwidget);

    QTextEdit *textedit = new QTextEdit(centralwidget);
    QPushButton *btn = new QPushButton("text", textedit);

    QVBoxLayout *vl = new QVBoxLayout(centralwidget);
    vl->addWidget(textedit);
    vl->addWidget(btn);

    centralwidget->setLayout(vl);

    centralwidget->installEventFilter(this);
    textedit->viewport()->installEventFilter(this);
    btn->installEventFilter(this);
}


bool form::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type() == QEvent::Paint) {
        obj->removeEventFilter(this);
        QApplication::sendEvent(obj, event);
        obj->installEventFilter(this);

        QPainter p(qobject_cast<QWidget*>(obj));
        p.setPen(Qt::red);
        p.setViewport(rect());
        p.drawLine(rect().topLeft(), rect().bottomRight());
        return true;
    }
    return false;
}

Автор: SABROG 26.5.2009, 22:28

Я об этом думал и хотел попробовать завтра такую штуку (исходники на работе остались):

- даем знать в eventFilter какое окно у нас главное и вместо flag используем указатель на главное окно (QObject/QWidget)
- делаем repaint для главного окна
- если QEvent::Paint приходит для главного окна, то сбрасываем переменную-флаг где содержится указатель на главное окно в 0 таким образом, чтобы следующая проверка вызывала оригинальный обработчик (QObject::eventFilter(o, e);
- вызываем QApplication::sendEvent()
- т.к. у нас переменная 0, то должна произойти отрисовка всех дочерних окон
- после возврата из sendEvent рисуем на главном окне

Автор: igor_bogomolov 26.5.2009, 22:40

Цитата(SABROG @ 26.5.2009, 23:28) *
- после возврата из sendEvent рисуем на главном окне
Так ведь ничего не нарисуется. Точнее, линия так и останется под другими виджетами. Иначе в своем коде, который я привел чуть выше, я бы уже получил нормальную прямую линию.
Или я чего то не допонял???

Автор: kwisp 27.5.2009, 7:23

igor_bogomolov,
на каждом виджете в отдельности получилось нарисавать, почему бы просто не рассчитать где должна находится линия на каждом виджете чтоб при совмещении получилась одна прямая.. хотя может криво получится:)

Автор: SABROG 27.5.2009, 8:51

Цитата(igor_bogomolov @ 26.5.2009, 23:40) *
Так ведь ничего не нарисуется. Точнее, линия так и останется под другими виджетами. Иначе в своем коде, который я привел чуть выше, я бы уже получил нормальную прямую линию.
Или я чего то не допонял???


Пока есть такое предположение. Т.к. ты установил фильтры на каждый компонент, то событий приходит 3-4. В каждом таком событии ты вызываешь оригинальный обработчик для каждого из фильтрованных виджетов. В результате не получается цепочки типа Родитель->Ребенок1->Ребенок2. А получается несколько отдельных вызовов, которые не связаны:
Родитель-Оригинальный обработчик-Свой обработчик
Ребенок1-Оригинальный обработчик-Свой обработчик
Ребенок2-Оригинальный обработчик-Свой обработчик

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

Но как я сказал это пока предположение, проверить я смогу на работе.

Автор: igor_bogomolov 27.5.2009, 8:52

Цитата(kwisp @ 27.5.2009, 8:23) *
на каждом виджете в отдельности получилось нарисавать, почему бы просто не рассчитать где должна находится линия на каждом виджете чтоб при совмещении получилась одна прямая..
Цитата(igor_bogomolov @ 26.5.2009, 23:09) *
Не подскажешь как координаты привести к единым. Т.е. как провести прямую линию через несколько виджетов, и она при этом не ломалась.

Как раз это у меня не получается. Не знаю, как координаты привести. Это единственный выход в нашей ситуации.
Если заменить p.setViewport(rect()) на p.setWindow(qobject_cast<QWidget*>(obj)->geometry()), линии практически совпадают. Тут проблемы возникают с методом geometry, возвращает неправильные координаты и размеры.

Автор: kwisp 27.5.2009, 9:01

Цитата(igor_bogomolov @ 27.5.2009, 9:52) *
линии практически совпадают
Цитата(igor_bogomolov @ 27.5.2009, 9:52) *
возвращает неправильные координаты и размеры.

так и не понял получается или нет.

Автор: igor_bogomolov 27.5.2009, 9:32

Цитата(SABROG @ 27.5.2009, 9:51) *
если установить фильтр только на главное окно
Тогда, в eventFilter(QObject *obj, QEvent *event) obj == главное окно, например QDialog
Далее
Цитата(SABROG @ 27.5.2009, 9:51) *
через sendEvent отправить событие отрисовки
QApplication::sendEvent(obj, event); т.е. ты отрисуешь только сам QDialog. Никаких child-ов здесь отрисовано не будет!!!!!
Цитата(SABROG @ 27.5.2009, 9:51) *
правление вернется обратно в фильтр событий
Здесь мы отрисуюем то что мы хотим, только по QDialog.

Теперь когда мы выйдем из евентфильтра, поверх QDialog нарисуются child-ы, затерев собой то что мы рисовали.

Другимим словами, предложенный тобой способ, позволяет нарисовать оригинальный виджет, для которого установлен фильтр, + что-то поверх него. Если ты попытаешься в обработчике события главного окна, принудительно выздать обработчик события его потомков, в лучшем случае получишь ошибку QPainter-а, иначе просто крашь.



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

kwisp, Если соберешь проект, увидешь, что через кнопку линия рисуется правильно. Для QTextEdit метод geometry почему то возвращает неправильные координыты? Как с этим бороться?

 temporary.zip ( 1.54 килобайт ) : 123
 

Автор: kwisp 27.5.2009, 10:20

igor_bogomolov,
готово
проблема в viewport() он возвращает не совсем точную геометрию текседита.
я так написал криво извини я всетаки на работе думаю понятно

Раскрывающийся текст

#include <QtCore/QEvent>
#include <QtCore/QTimer>
#include <QtGui/QTextEdit>
#include <QtGui/QGridLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPainter>
#include <QtGui/QApplication>
#include <QtGui/QPushButton>
#include <QtDebug>

#include "form.h"

form::form(QWidget *parent) : QMainWindow(parent)
{
    setMinimumSize(200, 180);
    centralwidget = new QWidget(this);
    centralwidget->setObjectName("centralwidget");
    setCentralWidget(centralwidget);

    QTextEdit *textedit = new QTextEdit(centralwidget);
    textedit->setObjectName("textedit");
    QPushButton *btn = new QPushButton("text", this);
    btn->setObjectName("btn");

    QVBoxLayout *vl = new QVBoxLayout(centralwidget);
    vl->addWidget(textedit);
    vl->addWidget(btn);

    centralwidget->setLayout(vl);

    centralwidget->installEventFilter(this);
    textedit->viewport()->installEventFilter(this);
    btn->installEventFilter(this);
}


bool form::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type() == QEvent::Paint) {
        obj->removeEventFilter(this);
        QApplication::sendEvent(obj, event);
        obj->installEventFilter(this);

//        qDebug()<< qobject_cast<QWidget*>(obj)
  //              << qobject_cast<QWidget*>(obj)->geometry()
    //            <<" "
    //            << qobject_cast<QWidget*>(obj)->visibleRegion();

        QPainter p(qobject_cast<QWidget*>(obj));
        p.setPen(Qt::red);
        if(qobject_cast<QWidget*>(obj)->objectName() == "qt_scrollarea_viewport")
            p.setWindow(centralwidget->findChild<QTextEdit*>("textedit")->geometry());
        else
        p.setWindow(qobject_cast<QWidget*>(obj)->geometry());
        p.drawLine(rect().topLeft(), rect().bottomRight());
        return true;
    }
    return false;
}


Автор: igor_bogomolov 27.5.2009, 10:32

kwisp, все правильно. Сам только что до этого додумался. Дело в том что viewport возвращем координаты относительно QTextEdit.

Блин, как все усложняется, относительно составных виджетов. Через QCalendarWidget, вообще непонятно как линию провести.
Но уже почти. Немного осталось додумать.

Нужен универсальный способ получить координаты любого виджета, относительно главного окна.

Автор: Kagami 27.5.2009, 10:47

Можно подумать в эту сторону

Раскрывающийся текст
Цитата
QPoint QWidget::mapTo ( QWidget * parent, const QPoint & pos ) const

Translates the widget coordinate pos to the coordinate system of parent. The parent must not be 0 and must be a parent of the calling widget.

See also mapFrom(), mapToParent(), mapToGlobal(), and underMouse().

QPoint QWidget::mapToGlobal ( const QPoint & pos ) const

Translates the widget coordinate pos to global screen coordinates. For example, mapToGlobal(QPoint(0,0)) would give the global coordinates of the top-left pixel of the widget.

See also mapFromGlobal(), mapTo(), and mapToParent().

QPoint QWidget::mapToParent ( const QPoint & pos ) const

Translates the widget coordinate pos to a coordinate in the parent widget.

Same as mapToGlobal() if the widget has no parent.

See also mapFromParent(), mapTo(), mapToGlobal(), and underMouse().

Автор: igor_bogomolov 27.5.2009, 11:06

Цитата(Kagami @ 27.5.2009, 11:47) *
Можно подумать в эту сторону
Надо посмотреть.


Пока решил так. Работает на ура.
Раскрывающийся текст
bool form::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type() == QEvent::Paint) {
        obj->removeEventFilter(this);
        QApplication::sendEvent(obj, event);
        obj->installEventFilter(this);

        QWidget *widget = qobject_cast<QWidget*>(obj);
        QPoint point = widget->pos();
        while(widget && (widget->parentWidget() != this)) {
            widget = widget->parentWidget();
            point += widget->pos();
        }

        QRect r = qobject_cast<QWidget*>(obj)->rect().translated(point);

        QPainter p(qobject_cast<QWidget*>(obj));
        p.setPen(Qt::red);
        p.setWindow(r);

        p.drawLine(rect().topLeft(), rect().bottomRight());
        return true;
    }
    return false;
}
:yahoo:

Автор: igor_bogomolov 27.5.2009, 11:54


Автор: SABROG 27.5.2009, 12:30

В общем затык на отрисовке чайлдов. Как я понял схема такая repaint()->repaint_sys()->QWidgetPrivate::drawWidget(и тут рекурсия этого drawWidget на всех чайлдах). Но похоже я что-то упускаю, как-то надо QPainter инициализировать чтоль, но это уже похоже надо лезть в трусы к QWidgetPrivate членам.

Насчет всех чайлдов. Я такую функцию написал:

static void childsRecursive(QObject *object, QWidget *watcher, bool install)
{
    if (object->isWidgetType()) {
        if (install) object->installEventFilter(watcher);
        else object->removeEventFilter(watcher);
    }
    QObjectList children = object->children();
    foreach(QObject *child, children) {
        childsRecursive(child, watcher, install);
    }
}


Юзать так:
childsRecursive(this, this, true); //устанавливаем обработчик на все чайлды и само окно
childsRecursive(this, this, false); //снимаем обработчик со всех чайлдов и окна


P.S.: теперь вариант с прозрачным QWidget'ом поверх всех окон мне кажется не таким уж и плохим вариантом. Но я еще не сдался :)

Автор: igor_bogomolov 27.5.2009, 12:59

Цитата(SABROG @ 27.5.2009, 13:30) *
В общем затык на отрисовке чайлдов. Как я понял схема такая repaint()->repaint_sys()->QWidgetPrivate::drawWidget(и тут рекурсия этого drawWidget на всех чайлдах). Но похоже я что-то упускаю, как-то надо QPainter инициализировать чтоль, но это уже похоже надо лезть в трусы к QWidgetPrivate членам.
Ничего не понял, если честно. Но с трусами и членами силно завернул.

childsRecursive заюзал. Все работает. Удобно.

Так я что-то и не понял, что тебя не устраивает??? Задачу решили, на мой взглян, хорошо. Работает и рисует как надо.

Автор: SABROG 27.5.2009, 13:19

Цитата(igor_bogomolov @ 27.5.2009, 13:59) *
Цитата(SABROG @ 27.5.2009, 13:30) *
В общем затык на отрисовке чайлдов. Как я понял схема такая repaint()->repaint_sys()->QWidgetPrivate::drawWidget(и тут рекурсия этого drawWidget на всех чайлдах). Но похоже я что-то упускаю, как-то надо QPainter инициализировать чтоль, но это уже похоже надо лезть в трусы к QWidgetPrivate членам.
Ничего не понял, если честно. Но с трусами и членами силно завернул.

childsRecursive заюзал. Все работает. Удобно.

Так я что-то и не понял, что тебя не устраивает??? Задачу решили, на мой взглян, хорошо. Работает и рисует как надо.

Оверхед сплошной :) Тут такая ситуация вырисовывается: в порядке рекурсии испускаются QPaintEvent'ы начиная от родителя до последнего самого глубокого ребенка (это если они вообще видимы, конечно). Мне надо как-то сделать так, чтобы обойти стандартный механизм рекурсии и отрисовать только одно окно не вызывая при этом перерисовку (генерацию эвентов перерисовки) для дочерних окон. Наткнулся на любопытный код:

    QPaintEvent *pe = new QPaintEvent(ui->groupBox->rect());
    QPixmap pix(ui->groupBox->size());
    pix.fill(Qt::white);
    QPainter::setRedirected(ui->groupBox, &pix);
    QApplication::sendEvent(ui->groupBox, pe);
    QPainter::restoreRedirected(ui->groupBox);
    pix.save("file.jpg");


По сути тоже самое, что и grabWidget(). Но тут отличие в том, что сгенеренный эвент срабатывает и окно (без детей) рисуется в файл. Если вместо &pix редиректнуть на другой виджет, то уже не пашет.

Автор: igor_bogomolov 27.5.2009, 13:50

У меня на сегодня уже перенагрузка мозга пошла. Вообще перестал что либо понимать. Так что не ругайте если что.

Цитата(SABROG @ 27.5.2009, 14:19) *
отрисовать только одно окно не вызывая при этом перерисовку (генерацию эвентов перерисовки) для дочерних окон

О каких окнах речь идет? И причем здесь вообще окна? Задача, как я изначально понял, бала - найти возможность рисовать поверх виджетов.

Если у тебя два окна, у них раззные циклы обработки событий. Или ты хочешь сказать, что если я имею два диалоговых окна, изменю размер одного, для второго придет событие на перерисовку?

Автор: SABROG 27.5.2009, 14:05

Виджет.

Автор: Litkevich Yuriy 27.5.2009, 14:41

Цитата(SABROG @ 26.5.2009, 23:22) *
Господа, поздравьте меня. Наконец-то я это сделал:
Я что-то непонял, причём здесь покрашеное в чёрный цвет окно?

Автор: SABROG 27.5.2009, 14:56

Цитата(Litkevich Yuriy @ 27.5.2009, 15:41) *
Цитата(SABROG @ 26.5.2009, 23:22) *
Господа, поздравьте меня. Наконец-то я это сделал:
Я что-то непонял, причём здесь покрашеное в чёрный цвет окно?

:) это альфа-канал, который ставится каждому чайлду. Но из-за того, что прозрачные бэкграунды наслаиваются друг на друга местами альфа-канал суммируется и происходит лажа.

Автор: igor_bogomolov 27.5.2009, 15:00

Тебя смущает двойной вызов обработчика события рисования для каждого виджета? Я правильно понимаю?
Но вызов

    if(event->type() == QEvent::Paint && obj == Родитель) {
        QApplication::sendEvent(ребёнок, event);
        ...
    }
ни к чему не приведет. Событие вызовится, но QPainter.begin() вернет false. Мы это уже недавно обсуждали, где то в теме есть ссылочка.
Тагда приходим к тому же самому. Нужно разбираться как работает метод update(). У меня разобраться не получилось. Может ты сможешь.

Помоему предложенный вариант тоже неплох. Свою задачу он выполняет. :)

Автор: SABROG 27.5.2009, 15:12

Цитата(igor_bogomolov @ 27.5.2009, 16:00) *
У меня разобраться не получилось


Да вот у меня тоже не получается. Слишком уж много там проверок всяческих. Например в момент отрисовки виджету ставится спец.аттрибут:

widget->setAttribute(Qt::WA_WState_InPaintEvent)'
//paint
widget->setAttribute(Qt::WA_WState_InPaintEvent, false):


и походу именно таким образом он определяет, что QPainter пытается рисовать в paintEvent'e. Пытался симулировать, не получилось. Сейчас затык видимо в paintEngine.

Автор: Litkevich Yuriy 27.5.2009, 15:28

SABROG, я к тому, что вроде была для этого отдельная тема

Автор: igor_bogomolov 27.5.2009, 16:33

Я думаю, другого способа мы не найдем. Дело в том, что после обработки события рисования родительского виджета, всегда генерируются события рисования для чайлдов. Поэтому, даже если найдется способ, в событии рисования родителя, методом sendEvetn, отрисовать все его чайлды, при выходе они сгенерируются снова, и затрут, то что мы нарисовали. Проигнорировать эти события не получается, т.е.

            event->ignore();
            return true;
положительного результата не даст. Фон все равно отрисуется.
Так что думаю, придется смириться с двойной перерисовкой каждого виджета. По моему, не так уж это накладно для современных компьютеров. Меня такой вот финт ушами, вполне устраивает. Вы как считаете???


Тем более двойной перерисовки здесь нет. :) Просто обработчик события рисования вызывается дважды.

Автор: Litkevich Yuriy 27.5.2009, 17:01

а что если после собственного рисования, запрещать виджету обновлятся?
setUpdateEnable(false)

Автор: SABROG 27.5.2009, 17:32

Цитата(Litkevich Yuriy @ 27.5.2009, 18:01) *
а что если после собственного рисования, запрещать виджету обновлятся?
setUpdateEnable(false)

В рекурсии поставил setUpdates(false) каждому чайлду, в итоге это привело к тому, что дети просто очистились, ну и окно естественно тоже на котором я пытаюсь что-то нарисовать. Это надо еще как-то отключать auto erase для виджетов.

Автор: Litkevich Yuriy 27.5.2009, 17:49

а есть ещё такая штука как двойная буферизация, её можно запрещать.

Автор: igor_bogomolov 27.5.2009, 17:57

Цитата(Litkevich Yuriy @ 27.5.2009, 18:49) *
а есть ещё такая штука как двойная буферизация, её можно запрещать.
Лучше этого не делать. Я уже пробовал. Во первых нам это ничем не помогает, во вторых при ресайзе предыдущее отображение на затирается

Автор: SABROG 27.5.2009, 17:58

Цитата(Litkevich Yuriy @ 27.5.2009, 18:49) *
а есть ещё такая штука как двойная буферизация, её можно запрещать.

Установка флагов Qt::WA_PaintOnScreen или Qt::WA_PaintOnScreen для детей приводит к крашу, также как и w->setAutoFillBackground(false);
---
Пардон, это я забыл одно место раскомментировать. В общем всё равно флаги ничем не помогли, autoFillBackground(false) сделал у QListWidget'a фон списка не белым, а как у основного окна.

Автор: igor_bogomolov 27.5.2009, 18:02

SABROG, да объясни же, чем не устраивает полученное http://www.forum.crossplatform.ru/index.php?s=&showtopic=2839&view=findpost&p=20165

Автор: SABROG 27.5.2009, 18:11

Цитата(igor_bogomolov @ 27.5.2009, 19:02) *
SABROG, да объясни же, чем не устраивает полученное http://www.forum.crossplatform.ru/index.php?s=&showtopic=2839&view=findpost&p=20165

Ну вот если рисовать QPixmap, он же по идее будет рисоваться медленней с ростом количества окон, да и на скрине почему-то в некоторых местах у тебя синяя рамка перекрывает красные линии. К тому же как я уже говорил тут возникает проблема с прозрачностью. Прозрачный фон у виджетов накладывается друг на друга и в итоге я получаю совсем другой цвет. Да и сама по себе проблема до конца не решена.

Автор: igor_bogomolov 27.5.2009, 18:24

Цитата(SABROG @ 27.5.2009, 19:11) *
на скрине почему-то в некоторых местах у тебя синяя рамка перекрывает красные линии
В моем примере фильтр устоновлен для textedit->viewport(), для самого textedit - не установлен. Если восползоваться твоей функцией childsRecursive, все будет рисоваться нормально.
Цитата(SABROG @ 27.5.2009, 19:11) *
проблема с прозрачностью
Эт я не проверял. Надо будет посмотреть.
Цитата(SABROG @ 27.5.2009, 19:11) *
Да и сама по себе проблема до конца не решена.
Поподробнее. Что не решено.

Для чего понадобилось рисовать поверх виджетов? Только для http://www.forum.crossplatform.ru/index.php?s=&showtopic=2839&view=findpost&p=20145

Автор: SABROG 27.5.2009, 19:48

Много чего придумать можно. Тот же эффект падающего снега. Разные спец.эффекты.

Похоже уже есть смысл копать в сторону backingstore и paintEngine.

Автор: igor_bogomolov 27.5.2009, 21:05

Цитата(SABROG @ 27.5.2009, 15:56) *
это альфа-канал, который ставится каждому чайлду. Но из-за того, что прозрачные бэкграунды наслаиваются друг на друга местами альфа-канал суммируется и происходит лажа.
Назнач для кождого такого виджета, с которым лажа происходит, свойство setAutoFillBackground(true). Лажа пропадет :)

Автор: SABROG 27.5.2009, 21:12

Ладно, чтобы завершить тему, можешь выложить пример, где бы поверх чайлдов рисовалась картинка с альфа-каналом?

А то я уже устал, если честно.

Автор: igor_bogomolov 27.5.2009, 21:40

Цитата(SABROG @ 27.5.2009, 22:12) *
Ладно, чтобы завершить тему, можешь выложить пример, где бы поверх чайлдов рисовалась картинка с альфа-каналом?
Могу конечно. Подчищу проек немного от экспериментов, выложу.


Цитата(SABROG @ 27.5.2009, 22:12) *
А то я уже устал, если честно.
Это твоя тема, тебе решать. Я лишь помочь пытался, в силу своих возможностей.

http://crossplatform.ru/?q=node/286

Автор: SABROG 27.5.2009, 22:05

Меня не столько исходники интересуют, сколько скриншот с результатом :)

Автор: igor_bogomolov 28.5.2009, 1:17

Цитата(SABROG @ 27.5.2009, 23:05) *
Меня не столько исходники интересуют, сколько скриншот с результатом
??? Какой от него толк, от скриншота?

Исходники прилагаю, скриншот есть. Картинку сам поменяешь, если что. У меня их просто нет.


 Overpainting.zip ( 7.54 килобайт ) : 171
 

Автор: Litkevich Yuriy 28.5.2009, 4:18

Вот для эфекта затемнения я бы просто палитру окошка менял перед паказом диалога. И альфа канал бы не использовал, за ненадобностью. Т.к. само окошко все равно не прозрачное.

Автор: SABROG 28.5.2009, 8:23

Цитата(Litkevich Yuriy @ 28.5.2009, 5:18) *
Вот для эфекта затемнения я бы просто палитру окошка менял перед паказом диалога. И альфа канал бы не использовал, за ненадобностью. Т.к. само окошко все равно не прозрачное.


Я думал над этим, но это не решение, а обход реальной задачи.

igor_bogomolov, думаю я теперь созрел, чтобы принять этот вариант как окончательный на данный момент. Можно начать писать статью в wiki. Осталось лишь подумать еще над возможностью добавить прозрачную анимацию.

Автор: igor_bogomolov 28.5.2009, 8:40

Цитата(SABROG @ 28.5.2009, 9:23) *
Осталось лишь подумать еще над возможностью добавить прозрачную анимацию.
Я вчера ночью, перед тем как выложить пример, немного поэксперементировал. Как раз таки хотел сделать сюрприз и выложить демку с эфектом падающего снега. Сделал 5 прозрачных пнг-шег с хаотично расположенными снижинками. По таймеру - перерисовывал эти картинки, вызывая update() для окна. Оказалось, что таким образом перерисовываются только те виджеты у которых свойство setAutoFillBackground(false). Виджеты с установленным свойством в true, почему то перерисовку игнорируют.
Так что у меня вопрос - чем отличаются события перерисовки через update() и от тех событий которые происходят при ресайзе?

Автор: Litkevich Yuriy 28.5.2009, 8:58

Цитата(igor_bogomolov @ 28.5.2009, 12:40) *
чем отличаются события перерисовки через update() и от тех событий которые происходят при ресайзе?
на память: update() - групирует события поэтому его рекомендуют использовать для повышения производительности. Т.е. пачка из нескольких событий рисования будет превращена в одно.

Цитата
void QWidget::update () [slot]
...
This function does not cause an immediate repaint; instead it schedules a paint event for processing when Qt returns to the main event loop. This permits Qt to optimize for more speed and less flicker than a call to repaint() does.

Calling update() several times normally results in just one paintEvent() call.
http://doc.crossplatform.ru/qt/4.4.3/qwidget.html#update
Цитата
void QWidget::repaint () [slot]

Repaints the widget directly by calling paintEvent() immediately, unless updates are disabled or the widget is hidden.

We suggest only using repaint() if you need an immediate repaint, for example during animation. In almost all circumstances update() is better, as it permits Qt to optimize for speed and minimize flicker.

Warning: If you call repaint() in a function which may itself be called from paintEvent(), you may get infinite recursion. The update() function never causes recursion.
http://doc.crossplatform.ru/qt/4.4.3/qwidget.html#repaint

на память немного промазал, групируются не события, а вызовы update()

Автор: igor_bogomolov 28.5.2009, 11:02

Все поправил. Теперь и анимация работает нормально.
Прилагаю изменёный проектик. В нем по таймеру перерисовываются звездочки. Получается как анимация. При нажатии на кнопку рисуется затемненный прозрачный фон.

SABROG
, у меня на работе нет возможности сделать гифку, если нетрудно, скомпилируй проектик, засними, и размести здесь. Что бы вроде как итог подвести. Ну и теперь на самом деле можешь писать статью :rolleyes:

 temporary.zip ( 31.93 килобайт ) : 598
 

Автор: SABROG 28.5.2009, 11:20



Написал в http://wiki.crossplatform.ru/index.php/%D0%A0%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D1%80%D1%85_%D0%B4%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%85_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D0%BE%D0%B2 как смог, если есть желающие добавить или поправить - милости прошу.

Автор: SABROG 28.5.2009, 12:52

wasyota мне дал любопытную ссылочку http://www.qtcentre.org/forum/f-qt-programming-2/t-request-for-comment-post-event-filter-12287.html

Автор: igor_bogomolov 28.5.2009, 13:04

Цитата(SABROG @ 28.5.2009, 13:52) *
wasyota мне дал любопытную ссылочку http://www.qtcentre.org/forum/f-qt-program...lter-12287.html
Я еще с утра это посмотрел. Что толку. В Qt PostEventFilter пока нет. Но реализацию было бы все равно интересно посмотреть. Приатач сюда posteventfilter.h, а то неохото региться там только из-за этого

Автор: SABROG 28.5.2009, 13:08

#ifndef __POSTEVENTFILTER_H
#define __POSTEVENTFILTER_H

#include <QList>
#include <QEvent>

#define WW_POSTEVENTFILTER(superclass) \
public: \
void installPostEventFilter(QObject *monitor){ \
  postFilters.push_front(monitor); \
} \
void removePostEventFilter(QObject *monitor){ \
  postFilters.removeAll(monitor); \
} \
private: \
QList<QObject*> postFilters; \
protected: \
  bool event(QEvent *e){ \
    bool ret = superclass::event(e); \
    if(!ret) \
      return false; \
    foreach(QObject *o, postFilters){ \
    bool r; \
    QMetaObject::invokeMethod(o, "postEventFilter", Qt::DirectConnection, Q_RETURN_ARG(bool, r), Q_ARG(QObject*, this), Q_ARG(QEvent*, e)); \
    if(r) return true; \
    } \
    return true; \
  }

#endif

Автор: igor_bogomolov 28.5.2009, 13:29

Цитата(SABROG @ 28.5.2009, 12:20) *
Написал в wiki как смог, если есть желающие добавить или поправить - милости прошу.
Хорошая статья получилась. Не зря мучились почти три дня.

Еще бы ссылочку на эту дему добавить, если вдруг кто то захочет задать вопросс.

Автор: Litkevich Yuriy 28.5.2009, 13:51

SABROG, а что если теперь запустить ссылкой в qt-apps?
(http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&u=http%3A%2F%2Fwiki.crossplatform.ru%2Findex.php%2F%D0%A0%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D1%80%D1%85_%D0%B4%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%85_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D0%BE%D0%B2&sl=ru&tl=en&history_state0=&swap=1)

Автор: SABROG 28.5.2009, 13:57

Цитата(Litkevich Yuriy @ 28.5.2009, 14:51) *
SABROG, а что если теперь запустить ссылкой в qt-apps?
(http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&u=http%3A%2F%2Fwiki.crossplatform.ru%2Findex.php%2F%D0%A0%D0%B8%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D1%80%D1%85_%D0%B4%D0%BE%D1%87%D0%B5%D1%80%D0%BD%D0%B8%D1%85_%D0%B2%D0%B8%D0%B4%D0%B6%D0%B5%D1%82%D0%BE%D0%B2&sl=ru&tl=en&history_state0=&swap=1)

Поподробней отсюда, я ничего не понял :)

Автор: Litkevich Yuriy 28.5.2009, 14:21

ну на qt-apps, кто-то утверждал, что задачка не для Qt. Если я ничего не перепутал.
Дак вот дать им ссылку на нашу вики, типа вот как всё это можно сделать.
Дать ссылку на оригинал и на гугловский перевод, чтоб по аглицки могли почитать.

Автор: igor_bogomolov 28.5.2009, 14:24

http://www.qtcentre.org/forum/f-qt-programming-2/t-how-to-sendevent-qpaintevent--21313.html

Автор: SABROG 28.5.2009, 14:38

Цитата(igor_bogomolov @ 28.5.2009, 15:24) *
http://www.qtcentre.org/forum/f-qt-programming-2/t-how-to-sendevent-qpaintevent--21313.html


:) не совсем эта тема, она просто стала продолжением этой: http://www.qtcentre.org/forum/f-qt-programming-2/t-paint-over-childs-21153.html

Щас обновлю все-таки последнюю тему, добавлю туда ссылочку.

Автор: Litkevich Yuriy 28.5.2009, 14:39

Ах, да qtcentre.org, конечно, а не qt-apps

Автор: SABROG 28.5.2009, 16:44

Вопрос. А ведь QRubberBand тоже рисуется поверх виджетов?
---
Вопрос отпал, это тот самый прослойчатый виджет:

    setAttribute(Qt::WA_TransparentForMouseEvents);
#ifndef Q_WS_WIN
    setAttribute(Qt::WA_NoSystemBackground);
#endif //Q_WS_WIN
    setAttribute(Qt::WA_WState_ExplicitShowHide);

---
Отличие PostEventFilter'а от нашего метода в том, что там переопределяется метод event() вместо installEventFilter'a, ну и соответственно вызывается сначала оригинальный обработчик, а после него вызывается метод postEventFilter. Хуже он тем, что работает только на одном виджете и соответственно каждый такой виджет надо наследовать.

Автор: igor_bogomolov 28.5.2009, 18:17

Цитата(SABROG @ 28.5.2009, 17:44) *
Хуже он тем, что работает только на одном виджете и соответственно каждый такой виджет надо наследовать.
Такой метод нам явно не подходит. Наш метод однозначно лучше. Твою статью можно смело в QQ размещать :D


--------------------------------------------------------------------------------
Наконец то научился работать с гиф анимацией через Qt, не воспроизводя ее в QLabel.

Автор: Litkevich Yuriy 28.5.2009, 19:19

igor_bogomolov, Прикольно получилось

Автор: ViGOur 28.5.2009, 20:06

Цитата(igor_bogomolov @ 28.5.2009, 19:17) *
Твою статью можно смело в QQ размещать
Угу, только думаю нужно грамотно перевести на английский и заслать им. :)

Автор: Kagami 28.5.2009, 20:55

igor_bogomolov, выложи, пожалуйста, исходники с мужиком :)

Автор: igor_bogomolov 28.5.2009, 21:15

Цитата(Kagami)
igor_bogomolov, выложи, пожалуйста, исходники с мужиком

Выкладываю. Правда координаты где мужика рисую я жестко задавал. Цель была разобраться как работать с гиф анимацией, т.е. считывать кадр из гифки.

 muzhik.zip ( 24.15 килобайт ) : 657
 

Автор: ViGOur 29.5.2009, 7:56

igor_bogomolov, выложил твоего мужика на сайт: http://www.crossplatform.ru/node/887. Скорее всего не только Kagami будет интересно посмотреть.

Как зайдешь на сайт, смогу тебе сделать автором данного исходника, чтобы мог поправить или добавить описание. Просто как я понял ты туда ниразу не заходил, по крайней мере залогиненым на форуме. :)

Автор: igor_bogomolov 29.5.2009, 9:13

Цитата(ViGOur @ 29.5.2009, 8:56) *
Просто как я понял ты туда ниразу не заходил, по крайней мере залогиненым на форуме.
Так это же главная страница сайта. Всегда на форум захожу через неё. А регистрация по всему ресурсу автоматическая. Сегодня при входе был приятно удивлён, увидев там знакомого мужика.

"Работа с гиф анимацией" - на данный момент звучит очень громко. Там десяти строк не наберется. За все отвечает класс QImageReader, с которым я до конца так и не разобрамся. По данному вопросу я новую тему создам чуть позже.

Предлогаю переименовать "Работа с гиф анимацией". Там всетаки вся прелесть не в работе с гиф, а в самом методе рисования. SABROG использовал термин overpainting. Может стоит его придерживаться?

Автор: Litkevich Yuriy 29.5.2009, 9:18

Цитата(igor_bogomolov @ 29.5.2009, 13:13) *
SABROG использовал термин overpainting. Может стоит его придерживаться?
может мы его по-русски запишим? Подберём подходящий вариант.

Автор: ViGOur 29.5.2009, 9:23

Это я сам дурак, ограничение в запросе стояло, потому тебя и не нашел.

Сделал тебя автором статьи-исходника, так что можешь поправить как хочешь. :)

Автор: ViGOur 29.5.2009, 19:49

Блин, вот думаю исходник SUBROG'a выкладывать на сайте или нет? В принципе есть статья в вики.
Просто он также интересен и полезен! :)

Автор: igor_bogomolov 29.5.2009, 22:31

Цитата(ViGOur @ 29.5.2009, 8:56) *
igor_bogomolov, выложил твоего мужика на сайт
Цитата(ViGOur @ 29.5.2009, 20:49) *
Блин, вот думаю исходник SUBROG'a выкладывать на сайте или нет?
Это один и тот же код :) Анимация только разная. В первом звездочки, во втором "мужик". Поэтому я и предлогал переименовать.
Цитата(igor_bogomolov)
Там всетаки вся прелесть не в работе с гиф, а в самом методе рисования.

Автор: ViGOur 29.5.2009, 23:31

Цитата(igor_bogomolov @ 29.5.2009, 23:31) *
Поэтому я и предлогал переименовать.
Вроде как ты автор того исходника, так что дерзай, если есть идеи. :)

Автор: Litkevich Yuriy 30.5.2009, 11:32

Цитата(kwisp @ 30.5.2009, 14:42) *
может вообще не стоит русский аналог искать а писать просто по русски оверрисование.
стОит. Надо подумать, http://www.forum.crossplatform.ru/index.php?showtopic=1081

Автор: SABROG 28.10.2009, 23:36

Не должно muzhik'у быть одному, поэтому я склепал ему бабу.



Решил попробовать схожий метод перехвата эвентов, но уже в глобальном виде - через переопределение QApplication::notify(). Принцип почти такой же за исключением того, что здесь не нужно использовать installEventFilter и рекурсию по детям.

bool MyApplication::notify(QObject *receiver, QEvent *event)
{
    if (QEvent::Paint == event->type() && m_overWidget) {
        bool ret = QApplication::notify(receiver, event);
        QWidget *widget = qobject_cast<QWidget *>(receiver);
        if (!m_overWidget->isAncestorOf(widget))
            return ret;
        QPainter painter(widget);

        QWidget *parent = widget;

        while(parent && parent->parentWidget() && (parent->parentWidget() != m_overWidget))
            parent = parent->parentWidget();

        if (parent != m_overWidget) {
            QPoint point = widget->mapTo(parent, parent->pos());
            QRect rect = widget->rect().translated(point);

            painter.setWindow(rect);
        }

        painter.drawPixmap(m_pix.rect(), m_pix);
        return ret;
    }
    return QApplication::notify(receiver, event);
}


В примере используется .mng анимация с классом QMovie. Есть баги, требующие доработки.

http://filebeam.com/6ed6c9e1fb5b4f89ee1174775315d87b

Автор: SABROG 30.10.2009, 23:31

Это тролли так шутят или они действительно планируют все-таки реализовать подобный функционал в Qt 5.0.0?

http://bugreports.qt.nokia.com/browse/QTBUG-1615

Автор: Litkevich Yuriy 30.10.2009, 23:36

Ну, а почему бы в 5-ке этому не появится (пострисованию)

Автор: SABROG 30.10.2009, 23:46

Цитата(Litkevich Yuriy @ 31.10.2009, 0:36) *
Ну, а почему бы в 5-ке этому не появится (пострисованию)


Ну если Qt 4.3.0 вышла в 2007 году, то 5.0.0 выйдет наверно, когда мы будем уже дедушками.

Автор: BRE 30.10.2009, 23:50

Цитата(SABROG @ 30.10.2009, 23:46) *
Ну если Qt 4.3.0 вышла в 2007 году, то 5.0.0 выйдет наверно, когда мы будем уже дедушками.

IMHO, сейчас релизы чаще выходят. Думаю год два.... :)

Автор: Litkevich Yuriy 31.10.2009, 1:23

Цитата(BRE @ 31.10.2009, 2:50) *
Думаю год два....
да быстрее и не надо, а то там каки будут.
Да и судя по http://bugreports.qt.nokia.com/secure/BrowseProject.jspa в разделе версии целая куча всего, что отложено на "после 5-ки"
Цитата
4.5.2 1
4.5.3 11
4.5.4 (Next Patch Release) 44
4.6.0 (Next Minor Release) 424
4.6.1 (Next Patch Release) 1
4.6.x 67
4.7.x 10
5.0.0 (Next Major Release) 80
Some future release

Стало быть 5-ки слишком долго ждать не прийдётся. Одно интересно ВинХП похоронят в 5-ке или нет

Автор: Litkevich Yuriy 31.10.2009, 13:49

Тему разделил: http://www.forum.crossplatform.ru/index.php?showtopic=3694

Автор: Litkevich Yuriy 6.11.2009, 4:43

Может будет интересно: http://www.prog.org.ru/index.php?topic=11184.msg68349#msg68349

Автор: SABROG 6.11.2009, 11:59

Цитата(Litkevich Yuriy @ 6.11.2009, 4:43) *
Может будет интересно: http://www.prog.org.ru/index.php?topic=11184.msg68349#msg68349


Не понятно зачем человек полез в кишки Qt, когда достаточно просто создать верхний слой из QWidget'a, если требуется для рабочего проекта. Сама по себе задача отрисовки в этой теме носит академический характер, поэтому мне интересно получив доступ к QWidgetBackingStore что меняется? Действительно ли тот код дает возможность рисовать поверх виджетов, в чем логика?

Автор: SABROG 5.1.2010, 20:08

Перезалил исходники с бабой, прошлый архив битым оказался.

http://filebeam.com/d2ac908250649a41651d20bd332079b0

Автор: Rocky 6.2.2010, 12:49

Я попробовал на основе примера с бабой сделать подобное рисование в реальной программе. Ну, в винде вроде как работает терпимо. А кто-нибудь в линуксе пробовал это запускать? Мне просто интересно, может это у меня что-то не так... Скомпили релиз, запустил:

//USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

[12:41:29 rocky@HM-2 ~]$ ps aux | grep baba
rocky     2626 34.2  1.2 250164 37768 pts/7    S+   12:40   0:29 ./babad
[12:41:34 rocky@HM-2 ~]$
[12:41:42 rocky@HM-2 ~]$
[12:41:42 rocky@HM-2 ~]$
[12:41:42 rocky@HM-2 ~]$


Т.е. тестовый пример грузит систему на 34%... Видимо, SABROG прав насчет академического характера =)

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