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

问题描述 投票:0回答:5

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

理想的解决方案是使用

event->ignore()
但这会将事件传递给父部件,而不是兄弟部件。

“全部通过”解决方案

setAttribute(Qt::WA_TransparentForMouseEvents);
也不起作用,因为孩子 A 需要捕获一些事件。

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

qt qt4
5个回答
5
投票

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

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 后,所有这些都记在心里,所以请纠正我的名称或类型错误。


4
投票

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


2
投票

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

Child-A -> Parent -> Child-B
(信号)->(时隙)(信号)->(时隙)


1
投票

这是一个可能的选择:

  1. 给孩子 B 指向孩子 A objet.
  2. 重新定义 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;

 }

希望这有帮助。


0
投票

对于当前的 Qt5(当然这也适用于 Qt6;我不知道它是否适用于 Qt4)如果你想将几个半透明的小部件堆叠在一起(例如自定义在媒体查看器上方绘制画布或 QMdiArea 等)。

一般的假设是从事件处理的意义上来看待QObject的父子关系(如果孩子不能处理一个事件,父母会处理它)。

在我的例子中,这看起来类似于以下内容:

class MyCentralWidget(QWidget):

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    # helper class - initializes a layout suitable for widget stacking
    class _Layout(QGridLayout):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.setContentsMargins(0, 0, 0, 0)

    # set layout for this widget
    layout = _Layout(self)

    # initialize layer widgets
    layer0 = ...  # bottom most layer
    layer1 = ...
    layer2 = ...
    layer3 = ...  # top layer

    # Stack entities on top of another
    layout.addWidget(layer0, 0, 0)  # this is shielded by layer1 and will never receive mouse events
    layout.addWidget(layer1, 0, 0)  # this will receive all mouse events not handled by layers above

    # Parenting-based stacking using QGridLayout
    # to enable proper event propagation (events flow in
    # child->parent direction if unused by child)
    _Layout(layer1).addWidget(layer2, 0, 0)
    _Layout(layer2).addWidget(layer3, 0, 0)

    # Resulting mouse event propagation: layer3 -> layer2 -> layer1

    # possibly add some other floating widget for floating menus...
    toolbox = MyToolbox(parent=self)

现在为了将事件传播到较低的小部件(例如从第 3 层到第 2 层),您必须确保小部件不使用事件。通常,当一个小部件对事件不感兴趣时,它只是通过在其基础上调用 event() 将其传递给其父级(例如,QMdiArea 在没有点击 QMdiSubWindow 或按钮时执行此操作):

# example implementation of event() method
def event(self, e) -> bool:
    if self.consumeEvent(e):
        # return if event was consumed
        return True
    # event was not consumed - send to parent via super call
    return super().event(e)
© www.soinside.com 2019 - 2024. All rights reserved.