Как сделать QEvent, который поднимается до родительских объектов QObject?

Мне нужно сделать кнопку GUI, которая сообщает своему родителю (или родителю родителя или даже родителю родителя...), что должен быть показан другой виджет в QStackedLayout. Я создал собственный QEvent:

class SwitchScreenEventWidget : public QEvent {
public:
  SwitchScreenEventWidget(QWidget* w) : SwitchScreenEvent(), widget(w) {
    if(widget==nullptr)
      throw "SwitchScreenEventWidget received null widget.";
  }
  virtual QWidget* getWidget() const {;return widget;}
private:
  QWidget* const widget;
};

Я вызываю его так:

// Through debugger I checked that this is getting called properly
void GraphButton::buttonClicked()
{
  if(qApp!=nullptr && parent()!=nullptr)
    qApp->notify(parent(), new SwitchScreenEventWidget(getGraph()));
}

И обрабатывать это так:

bool ViewStack::eventFilter(QEvent* e)
{
    if(e->type()>=QEvent::User) {
      if(SwitchScreenEvent* event = dynamic_cast<SwitchScreenEvent*>(e)) {
        // Show the given widget
      }
      return true;
    }
    return false;
}

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

Так всплывают все события или нет? Если нет, то какие делают, какие нет и почему? И как правильно сделать всплывающее окно события?


person Tomáš Zato - Reinstate Monica    schedule 18.01.2016    source источник
comment
Попробуйте установить для флага accepted вашего события значение false.   -  person thuga    schedule 18.01.2016
comment
Почему бы вам не использовать для этой цели сигнально-слотовую систему? Вы как-то ограничены?   -  person tro    schedule 18.01.2016
comment
@troyane Я не хочу напрямую обращаться к главному виджету из QPushButton - я хочу, чтобы решение работало независимо от количества родительских узлов, которые есть у кнопки.   -  person Tomáš Zato - Reinstate Monica    schedule 18.01.2016
comment
Вы все еще можете использовать сигнал, просто рекурсивно найдите свой findChildren<GraphButton*> в самом верхнем окне и подключите сигнал.   -  person Sebastian Lange    schedule 18.01.2016
comment
@SebastianLange да, это умно, и я уже делаю это для других целей, но я бы все же предпочел метод событий, потому что эти кнопки можно добавить после инициализации приложения.   -  person Tomáš Zato - Reinstate Monica    schedule 18.01.2016
comment
@TomášZato Другим вариантом было бы иметь приложение MainWindow-Singleton или подкласса Q [Gui] и иметь там соединение сигнал-сигнал, которое затем подключается к вашему верхнему слоту виджета (оба, вероятно, плохой дизайн).   -  person Sebastian Lange    schedule 18.01.2016
comment
Можете ли вы предоставить максимально упрощенный, но работающий пример, чтобы мы могли поиграть с ним.   -  person tro    schedule 18.01.2016
comment
@troyane Хорошо, я попытаюсь создать пример проекта. Но сам вопрос достаточно сложен - код, вероятно, будет слишком большим для SO-вопроса.   -  person Tomáš Zato - Reinstate Monica    schedule 18.01.2016


Ответы (1)


Я думаю, что лучший способ для вас - создать подкласс QApplication, переопределить метод notify и самостоятельно выполнять свои «пузыри». Я почти уверен, что события мыши и клавиатуры "пузырятся" с помощью этого метода, а другие события - нет.

bool QCoreApplication::notify(QObject * получатель, QEvent * событие)

Отправляет событие получателю: Receiver->event(event). Возвращает значение, возвращаемое обработчиком событий получателя. Обратите внимание, что эта функция вызывается для всех событий, отправляемых любому объекту в любом потоке.

Для определенных типов событий (например, событий мыши и клавиш) событие будет передано родительскому объекту получателя и так далее до объекта верхнего уровня, если получатель не заинтересован в событии (т. е. он возвращает false).

Таким образом, вы можете изменить это поведение своим осознанием.

Также о вашем примере кода. Я думаю, что это проверка

if( qApp!=nullptr )

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

person Evgeny    schedule 18.01.2016