Кулак, извинения за длину вопроса.
Я пытаюсь распространить пользовательское событие Qt от дочерних виджетов до главного родительского виджета для инициирования некоторого действия на основе типа события вместо того, чтобы связать сигналы.
Спокойные документы предполагают, что каждое событие отправило с postEvent()
это имеет accept()
и ignore()
методы могут быть распространены (значение каждого QEvent
подкласс).
Я попытался переопределить customEvents
метод вместо events
но напрасно.
Я попробовал это в 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++:
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);
}
Возможно, я упустил суть, действительно ли возможно, что только Ключевые события и События от нажатия мыши распространены вверх?
Я потратил некоторое время, просматривая исходный код 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
(это виртуальный публичный член) и добавить событие распространение для вашего события (-ий)).
Надеюсь, это поможет.
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)