Распространите пользовательский QEvent для порождения виджета в Qt/PyQt

Кулак, извинения за длину вопроса.

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

Спокойные документы предполагают, что каждое событие отправило с postEvent() это имеет accept() и ignore() методы могут быть распространены (значение каждого QEvent подкласс).

Я попытался переопределить customEvents метод вместо events но напрасно.

Python

Я попробовал это в Python с помощью PyQt4 (Спокойная версия 4.6).

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class Foo(QWidget):
    def doEvent(self):
        QApplication.postEvent(self, QEvent(12345))

    def event(self, event):
        event.ignore()
        return False

class Bar(QWidget):
    def __init__(self, *args, **kwargs):
        super(Bar, self).__init__(*args, **kwargs)
        self.foo = Foo(self)
        layout = QHBoxLayout()
        layout.addWidget(self.foo)
        self.setLayout(layout)

    def event(self, event):
        if event.type() == 12345:
            self.someEventHandler()
        return True

    def someEventHandler(self):
        print 'Handler in {0}'.format(self.__class__.__name__)

if __name__=='__main__':
    app = QApplication([''])
    bar = Bar()
    bar.show()
    bar.foo.doEvent()
    app.exec_()

В этом примере Bar.someEventHandler() только инициировал бы, если бы событие было отправлено с self.parent() как первый аргумент как так:

def doEvent(self):
    QApplication.postEvent(self.parent(), QEvent(12345))

Который понятен, так как событие передается непосредственно принимающему объекту.

C++

Подобный пример в C++:

foobar.h

#ifndef FOOBAR_H
#define FOOBAR_H

#include <QtGui>

class Foo : public QWidget
{
    Q_OBJECT

public:
    Foo(QWidget *parent = 0);
    void doEvent();
    bool event(QEvent *);
};


class Bar : public QWidget
{
    Q_OBJECT

public:
    Bar(QWidget *parent = 0);
    Foo *foo;
    bool event(QEvent *);
};

#endif // FOOBAR_H

foobar.cpp

#include "foobar.h"

Foo::Foo(QWidget *parent)
     : QWidget(parent) {}

void Foo::doEvent() {
    QEvent *event = new QEvent(QEvent::User);
    QApplication::postEvent(this, event);
}

bool Foo::event(QEvent *event)
{
    event->ignore();
    return QWidget::event(event);
}

Bar::Bar(QWidget *parent)
     : QWidget(parent)
 {
    foo = new Foo(this);
}

bool Bar::event(QEvent *event)
{
    if (event->type() == QEvent::User) {
        qDebug() << "Handler triggered";
        return true;
    }
    return QWidget::event(event);
}

main.cpp

#include <QtGui>
#include "foobar.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Bar bar(0);
    bar.show();
    bar.foo->doEvent();
    return app.exec();
}

То же как в Python, это только работает, если событие передается непосредственно объекту.

void Foo::doEvent() {
    QEvent *event = new QEvent(QEvent::User);
    QApplication::postEvent(this->parentWidget(), event);
}

Возможно, я упустил суть, действительно ли возможно, что только Ключевые события и События от нажатия мыши распространены вверх?

11
задан Davor Lucic 5 July 2010 в 18:22
поделиться

2 ответа

Я потратил некоторое время, просматривая исходный код Qt, чтобы ответить на ваш вопрос, и в итоге пришел к следующему: распространение событий на родительские виджеты выполняется с помощью QApplication :: notify , в основном длинный оператор switch со всеми видами событий. Например, вот как это делается для QEvent :: WhatsThisClicked :

...
case QEvent::WhatsThisClicked:
        {
            QWidget *w = static_cast<QWidget *>(receiver);
            while (w) {
                res = d->notify_helper(w, e);
                if ((res && e->isAccepted()) || w->isWindow())
                    break;
                w = w->parentWidget();
            }
        }
...

Теперь важный момент: это , а не выполняется для пользовательских событий (и многих других явно обрабатываемых стандартных Qt событий), поскольку предложение default :

 default:
        res = d->notify_helper(receiver, e);
        break;

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

Надеюсь, это поможет.

18
ответ дан 3 December 2019 в 04:31
поделиться

Re- реализация QApplication.notify в Python, которая будет распространять пользовательские события.

В Qt notfy_helper обеспечивает вызов фильтров событий (как QApplications, так и приемников), но я пропустил это, так как они мне не нужны, а notfy_helper является закрытым членом.

from PyQt4.QtCore import QEvent
from PyQt4.QtGui import QApplication

class MyApp(QApplication):
    def notify(self, receiver, event):
        if event.type() > QEvent.User:
            w = receiver
            while(w):
                # Note that this calls `event` method directly thus bypassing
                # calling qApplications and receivers event filters
                res = w.event(event);
                if res and event.isAccepted():
                    return res
                w = w.parent()
        return super(MyApp, self).notify(receiver, event)

И вместо использования экземпляра QApplication мы используем экземпляр нашего подкласса.

import sys
if __name__=='__main__':
    app = MyApp(sys.argv)
5
ответ дан 3 December 2019 в 04:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: