Qt QAbstractButton setDown 干扰grabMouse

发布于 2024-10-12 07:27:08 字数 2805 浏览 2 评论 0原文

我在 Qt 中有一些奇怪的行为,看起来像是一个缺陷。我想知道是否有人有好的解决方法。

我有一个弹出窗口小部件,其中包含许多按钮。用户通过按下鼠标按钮激活弹出窗口。弹出窗口小部件在显示时调用grabMouse。它获取所有鼠标事件。当它滚动到按钮上时,它会调用按钮上的 setDown(true) 。然而现在,当释放鼠标按钮时,弹出窗口小部件不会获取转到按钮的mouseReleaseEvent

也就是说,在按钮上调用 setDown(true) 会导致按钮窃取鼠标事件,绕过弹出窗口小部件中的 grabMouse

我查看了 setDown 的源代码,但我看不到任何可以直接执行此操作的内容。然而,我还注意到有时按钮会获得悬停事件,有时则不会。我认为当鼠标被抓住时它永远不会得到这些事件。

//g++ -o grab_lost grab_lost.cpp -lQtCore -lQtGui -I /usr/include/qt4/ -I /usr/include/qt4/QtCore -I /usr/include/qt4/QtGui
/**
    Demonstrates the defect of losing the mouse. Run the program and:

    1. Press mouse anywhere
    2. release in purple block (not on X)
    3. Release message written (GrabLost receives the mouseReleaseEvent)

    For defect:

    1. Pree mouse anywhere
    2. Release inside the X button
    3. button is clicked, no release message (GrabLost does not get the mouseReleaseEvent)
*/
#include <QWidget>
#include <QPushButton>
#include <QApplication>
#include <QMouseEvent>
#include <QPainter>

class GrabLost : public QWidget
{
    QPushButton * btn;
public:
    GrabLost( QWidget * parent = 0)
        : QWidget( parent, Qt::Popup )
    {
        btn = new QPushButton( "X", this );
        setMouseTracking( true );
    }

protected:
    void showEvent( QShowEvent * ev )
    {
        QWidget::showEvent( ev );
        grabMouse();
    }
    void closeEvent( QCloseEvent * ev )
    {
        releaseMouse();
        QWidget::closeEvent( ev );
    }
    void hideEvent( QHideEvent * ev )
    {
        releaseMouse();
        QWidget::hideEvent( ev );
    }

    void mouseReleaseEvent( QMouseEvent * ev )
    {
        qDebug( "mouseRelease" );
        close();
    }

    void mouseMoveEvent( QMouseEvent * ev )
    {
        QWidget * w = childAt( ev->pos() );
        bool ours = dynamic_cast<QPushButton*>( w ) == btn;
        btn->setDown( ours );
    }

    void paintEvent( QPaintEvent * ev )
    {
        //just to show where the widget is
        QPainter pt( this );
        pt.setPen( QColor( 0,0,0 ) );
        pt.setBrush( QColor( 128,0,128) );
        pt.drawRect( 0, 0, size().width(), size().height() );
    }
};

class GrabMe : public QWidget
{
protected:
    void mousePressEvent( QMouseEvent * ev )
    {
        GrabLost * gl = new GrabLost();
        gl->resize( 100, 100 );
        QPoint at( mapToGlobal( ev->pos() ) );
        gl->move( at.x() - 50, at.y() - 50 );
        gl->show();
    }
};

int main( int argc, char** argv )
{
    QApplication app( argc, argv );

    GrabMe * gm = new GrabMe();
    gm->move( 100, 100 );
    gm->resize( 300, 300 );
    gm->show();

    app.exec();
    return 0;
}

I have some weird behaviour in Qt that seems like a defect. I'd like to know if anybody has a good workaround.

I have a popup widget that contains many buttons in it. The user activates the popup by pressing the mouse button down. The popup widget calls grabMouse when shown. It gets all the mouse events. As it rolls over a button it calls setDown(true) on the button. Now however, when the mouse button is released the popup widget does not get the mouseReleaseEvent, that goes to the button.

That is, calling setDown(true) on a button causes the button to steal mouse events, bypassing the grabMouse in the popup widget.

I've looked at the source code for setDown but I can't see anything there that would do it directly. I also notice however that sometimes a button gets a hover event, sometimes not. I would assume it would never get those events when the mouse is grabbed.

//g++ -o grab_lost grab_lost.cpp -lQtCore -lQtGui -I /usr/include/qt4/ -I /usr/include/qt4/QtCore -I /usr/include/qt4/QtGui
/**
    Demonstrates the defect of losing the mouse. Run the program and:

    1. Press mouse anywhere
    2. release in purple block (not on X)
    3. Release message written (GrabLost receives the mouseReleaseEvent)

    For defect:

    1. Pree mouse anywhere
    2. Release inside the X button
    3. button is clicked, no release message (GrabLost does not get the mouseReleaseEvent)
*/
#include <QWidget>
#include <QPushButton>
#include <QApplication>
#include <QMouseEvent>
#include <QPainter>

class GrabLost : public QWidget
{
    QPushButton * btn;
public:
    GrabLost( QWidget * parent = 0)
        : QWidget( parent, Qt::Popup )
    {
        btn = new QPushButton( "X", this );
        setMouseTracking( true );
    }

protected:
    void showEvent( QShowEvent * ev )
    {
        QWidget::showEvent( ev );
        grabMouse();
    }
    void closeEvent( QCloseEvent * ev )
    {
        releaseMouse();
        QWidget::closeEvent( ev );
    }
    void hideEvent( QHideEvent * ev )
    {
        releaseMouse();
        QWidget::hideEvent( ev );
    }

    void mouseReleaseEvent( QMouseEvent * ev )
    {
        qDebug( "mouseRelease" );
        close();
    }

    void mouseMoveEvent( QMouseEvent * ev )
    {
        QWidget * w = childAt( ev->pos() );
        bool ours = dynamic_cast<QPushButton*>( w ) == btn;
        btn->setDown( ours );
    }

    void paintEvent( QPaintEvent * ev )
    {
        //just to show where the widget is
        QPainter pt( this );
        pt.setPen( QColor( 0,0,0 ) );
        pt.setBrush( QColor( 128,0,128) );
        pt.drawRect( 0, 0, size().width(), size().height() );
    }
};

class GrabMe : public QWidget
{
protected:
    void mousePressEvent( QMouseEvent * ev )
    {
        GrabLost * gl = new GrabLost();
        gl->resize( 100, 100 );
        QPoint at( mapToGlobal( ev->pos() ) );
        gl->move( at.x() - 50, at.y() - 50 );
        gl->show();
    }
};

int main( int argc, char** argv )
{
    QApplication app( argc, argv );

    GrabMe * gm = new GrabMe();
    gm->move( 100, 100 );
    gm->resize( 300, 300 );
    gm->show();

    app.exec();
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

朱染 2024-10-19 07:27:08

我已在 Nokia DB 中输入了该缺陷。我认为他们有 95% 的机会将其关闭,因为“按预期工作”。

对于那些需要解决方案的人来说,您必须使用事件过滤器并创建自己的抓取。基本上为每个子窗口小部件安装一个事件过滤器并将鼠标事件传播到父窗口小部件。

请注意,在上面的代码中,即使不调用 setDown,鼠标右键也不起作用。

I've entered the defect at the Nokia DB. I'm giving it about a 95% chance that they close it as "works as intended".

For those of you that need a solution nonetheless you'll have to use event filters and create your own grabbing. Basically install an event filter for every child widget and propagate the mouse events to the parent.

Note in the above code that the right mouse button doesn't work even if you don't call setDown.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文