Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: QPaintEvent, installEventFilter, QPainter, Overpainting
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Система рисования. Печать
Страницы: 1, 2, 3
SABROG
Есть желание рисовать на дочерних окошках, причем хочется оставить их оригинальный 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
Цитата(SABROG @ 26.5.2009, 12:52) *
оригинальный render

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

Несколько мимо темы, такой код:
Цитата(SABROG @ 26.5.2009, 15:52) *
QPaintEvent *pe = (QPaintEvent *)e;
QWidget *w = (QWidget *)o;
стиль приведения не С++ный, а Сишный, и уж точно не принятый в Qt (qobject_cast<>, надобы)
SABROG
Цитата(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
Цитата(SABROG @ 26.5.2009, 16:15) *
Думаю postEvent'ом тут тоже не обойтись, т.к. опять будет рекурсия.
дело даже не в рекурсии, обсуждалось недавно, что событие рисования посылать получается, да вот рисовальщик (QPainter) ругается.

Цитата(SABROG @ 26.5.2009, 16:15) *
потом попробовать отрисовать что-то поверх
а как попробовать рисовать мимо события рисования, на виджетах ведь можно рисовать только в их обработчике рисования.
SABROG
Через флаг не получилось. Второй paintEvent затирает как-то все, что было до этого.

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

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

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

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

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

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

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

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

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

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

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

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

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

и ещё

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

if (object == m_widget && m_enabled)
kwisp
Цитата(Litkevich Yuriy @ 26.5.2009, 17:00) *
m_widget

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



Как я понял sendEvent вызывает цикл eventFilter еще раз и таким образом заставляет нарисоваться виджетам. А нулевой m_widget (в моем случае обычный flag типа bool) нужен, чтобы прервать бесконечный цикл. Значит я все-таки рыл в правильную сторону.
Litkevich Yuriy
Цитата(SABROG @ 26.5.2009, 20:35) *
Похоже получается.
т.е. эти чёрные линии ты нарисовал поверх виджета в фильтре событий?
SABROG
Цитата(Litkevich Yuriy @ 26.5.2009, 17:42) *
Цитата(SABROG @ 26.5.2009, 20:35) *
Похоже получается.
т.е. эти чёрные линии ты нарисовал поверх виджета в фильтре событий?


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

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

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

DmP
SABROG, сорри за офтоп, но чем делаются такие картинки?
SABROG
Цитата(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
Может я что то делаю не так, но нарисовать что то приемлемое у меня не получается. Не подскажешь как координаты привести к единым. Т.е. как провести прямую линию через несколько виджетов, и она при этом не ломалась.


Раскрывающийся текст
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
Я об этом думал и хотел попробовать завтра такую штуку (исходники на работе остались):

- даем знать в eventFilter какое окно у нас главное и вместо flag используем указатель на главное окно (QObject/QWidget)
- делаем repaint для главного окна
- если QEvent::Paint приходит для главного окна, то сбрасываем переменную-флаг где содержится указатель на главное окно в 0 таким образом, чтобы следующая проверка вызывала оригинальный обработчик (QObject::eventFilter(o, e);
- вызываем QApplication::sendEvent()
- т.к. у нас переменная 0, то должна произойти отрисовка всех дочерних окон
- после возврата из sendEvent рисуем на главном окне
igor_bogomolov
Цитата(SABROG @ 26.5.2009, 23:28) *
- после возврата из sendEvent рисуем на главном окне
Так ведь ничего не нарисуется. Точнее, линия так и останется под другими виджетами. Иначе в своем коде, который я привел чуть выше, я бы уже получил нормальную прямую линию.
Или я чего то не допонял???
kwisp
igor_bogomolov,
на каждом виджете в отдельности получилось нарисавать, почему бы просто не рассчитать где должна находится линия на каждом виджете чтоб при совмещении получилась одна прямая.. хотя может криво получится:)
SABROG
Цитата(igor_bogomolov @ 26.5.2009, 23:40) *
Так ведь ничего не нарисуется. Точнее, линия так и останется под другими виджетами. Иначе в своем коде, который я привел чуть выше, я бы уже получил нормальную прямую линию.
Или я чего то не допонял???


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

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

Но как я сказал это пока предположение, проверить я смогу на работе.
igor_bogomolov
Цитата(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
Цитата(igor_bogomolov @ 27.5.2009, 9:52) *
линии практически совпадают
Цитата(igor_bogomolov @ 27.5.2009, 9:52) *
возвращает неправильные координаты и размеры.

так и не понял получается или нет.
igor_bogomolov
Цитата(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 почему то возвращает неправильные координыты? Как с этим бороться?
kwisp
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
kwisp, все правильно. Сам только что до этого додумался. Дело в том что viewport возвращем координаты относительно QTextEdit.

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

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

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

Так я что-то и не понял, что тебя не устраивает??? Задачу решили, на мой взглян, хорошо. Работает и рисует как надо.
SABROG
Цитата(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
У меня на сегодня уже перенагрузка мозга пошла. Вообще перестал что либо понимать. Так что не ругайте если что.

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

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

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

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

Помоему предложенный вариант тоже неплох. Свою задачу он выполняет. :)
SABROG
Цитата(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
SABROG, я к тому, что вроде была для этого отдельная тема
igor_bogomolov
Я думаю, другого способа мы не найдем. Дело в том, что после обработки события рисования родительского виджета, всегда генерируются события рисования для чайлдов. Поэтому, даже если найдется способ, в событии рисования родителя, методом sendEvetn, отрисовать все его чайлды, при выходе они сгенерируются снова, и затрут, то что мы нарисовали. Проигнорировать эти события не получается, т.е.
            event->ignore();
            return true;
положительного результата не даст. Фон все равно отрисуется.
Так что думаю, придется смириться с двойной перерисовкой каждого виджета. По моему, не так уж это накладно для современных компьютеров. Меня такой вот финт ушами, вполне устраивает. Вы как считаете???


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

В рекурсии поставил setUpdates(false) каждому чайлду, в итоге это привело к тому, что дети просто очистились, ну и окно естественно тоже на котором я пытаюсь что-то нарисовать. Это надо еще как-то отключать auto erase для виджетов.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.