如何在Qt中将点击事件传递给下面的兄弟?

Posted

技术标签:

【中文标题】如何在Qt中将点击事件传递给下面的兄弟?【英文标题】:How to pass click event to sibling underneath in Qt? 【发布时间】:2011-04-06 09:02:07 【问题描述】:

我在窗口子 A 和子 B 中有两个重叠的小部件。子 A 在 B 上方并获取鼠标事件,但有时点击应该通过并最终击中子 B。

理想的解决方案是使用event->ignore(),但这会将事件传递给父窗口小部件,而不是兄弟窗口。

“全部通过”解决方案setAttribute(Qt::WA_TransparentForMouseEvents); 也不起作用,因为子 A 需要捕获一些事件。

我如何告诉 Qt“我不想处理这个事件,就像我不在那里一样”?

【问题讨论】:

您能否设置“全部传递”选项并从鼠标事件处理程序重新发送鼠标事件?事件完成后,再次将其设置为 false。可能会导致无限递归.. 也许您应该在主窗口中为子 A 安装一个事件过滤器,尝试 A 是否管理事件,如果没有,检查它是否在子 B 的区域中,如果是,将其传递给它?这应该可行,但可能有点麻烦。否则,我会看到 A 应该知道 B 并能够将事件传递给它的可能性。 通过查看 Qt 的源代码,QWidgetPrivate::childAtRecursiveHelper 找到了一个匹配的孩子(过滤带有WA_TransparentForMouseEvents 的孩子,然后它调用孩子的事件处理程序,但是这个调用发生在孩子查找方法之外,所以唯一的解决方案似乎是从父级手动管理点击操作... 【参考方案1】:

更简单的解决方案(如果适用)是根据您的点击条件设置WA_TransparentForMouseEvents

例如,如果要点击 Child-A 的某些区域,可以使用其mouseMoveEvent() 来检查是否需要设置或取消设置WA_TransparentForMouseEvents。然后点击事件自动通过。

如果您无法确定是否应在实际触发点击事件之前接受它,您可以执行以下操作:

void ChildA::mousePressEvent(QMouseEvent* event) 
    const bool accepted = ...; //insert custom logic here
    if (accepted) 
        ... //handle event here
     else 
        //not accepting event -> resend a copy of this event...
        QMouseEvent* eventCopy = new QMouseEvent(*event);
        QApplication::instance()->postEvent(eventCopy);
        //...but this time, ignore it
        setAttribute(Qt::WA_TransparentForMouseEvents, true);
        QTimer::singleSlot(1, this, SLOT(resetClickTransparency()));
        //don't propagate original event any further
        event->accept();
    


void ChildA::resetClickTransparency()  //slot
    setAttribute(Qt::WA_TransparentForMouseEvents, false);

免责声明:在一年不做 Qt 之后,所有这些都记在心里,所以请纠正我的名称或类型错误。

【讨论】:

我知道这是旧的,但你知道,一旦我激活它,我就无法将它设置为 false。 投了反对票,因为这是相当的 hack,并且可能通常适用于不会太快进入的点击事件,但如果应用程序挂起一小会儿并且多次点击进入,那么有些会可能触发错误。此处介绍的其他解决方案需要实施者进行更多工作,但更强大 imo。【参考方案2】:

您也可以从另一面处理问题。您可以让其他小部件使用事件过滤器侦听第一个小部件的事件,而不是将事件转发到“其他”小部件。我不确定这是否适合您的用例,这取决于什么/谁确定什么事件将由哪个对象处理。

【讨论】:

【参考方案3】:

如果事件必须被 Child-A 忽略,则发出一个信号并与其父级捕获它,然后父级发出一个新信号以由 Child-B 捕获

子 A -> 父 -> 子 B (信号)->(插槽)(信号)->(插槽)

【讨论】:

【参考方案4】:

这是一个可能的选择:

    将子 B 指针指向子 A 对象。 重新定义 bool QObjet::event(QEvent *event) 以在需要时将事件转发给子 B。

例如:

bool WidgetA::event(QEvent *event)
 
    QWidget::event( event);
    QEvent::Type type = event->type();
    if ( (type != QEvent::KeyPress) &&
         (type != QEvent::Wheel) &&
         (type != QEvent::MouseButtonDblClick) &&
         (type != QEvent::MouseMove) &&
         (type != QEvent::MouseButtonPress) )
        return true;
    //forward the event
    if ( m_pChildB )
         m_pChildB->event( event);
    return true;

 

希望这会有所帮助。

【讨论】:

以上是关于如何在Qt中将点击事件传递给下面的兄弟?的主要内容,如果未能解决你的问题,请参考以下文章

在没有点击事件的情况下使用 $emit

QT Designer 菜单栏事件响应问题。

如何在 PyQt4 中将事件监听器添加到动态 QTableWidgetItem?

QT如何获取窗口外的鼠标点击事件,或者鼠标坐标

如何在 Swift 中将触摸事件发送到 nextResponder

QT:如何在点击事件上展开/折叠文本(qtextbrowser,qwebview,...)