Qt QAbstractButton setDown interferes with grabMouse
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;
}
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
.
精彩评论