I have problems in PySide while trying to determine which mouse button is pressed in event function. I need it in particular for ignoring mouse move event, because it's doing job on both mouse buttons, left and right.
I want to ignore mouse move event if the right button on scene is pressed. Any help?
All of mouse events have two methods (button and buttons) to determine which of buttons are pressed. But for only move event the documentation says:
Note that the returned value is always Qt::NoButton for mouse move events.
for mouseMoveEvent you should use buttons method.
void mouseMoveEvent(QMouseEvent *e)
{
if(e->buttons() == Qt::RightButton)
qDebug() << "Only right button";
}
In order to ignore move events you need to do this work in eventFilter of course.
QApplication::mouseButtons() will return the status of mouseButton,
so, you can get the status of mouse in KeyPressEvent.
you can check, which mouse button is pressed via Qt::RightButton. Sorry for c++ code, but i hope, you would understand idea anyway:
void mousePressEvent(QMouseEvent *event)
{
if (event->button()==Qt::RightButton){
qDebug() << "right button is pressed
}
}
You could use a boolean:
void mousePressEvent(QMouseEvent *event)
{
if (event->button()==Qt::RightButton){
qDebug() << "right button is pressed
pressed=true; //<-----
}
}
and on mouseMoveEvent
void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
float dx = event->x() - lastPos.x(); // where lastpos is a QPoint member
float dy = event->y() - lastPos.y();
if (dx<0) dx=-dx;
if (dy<0) dy=-dy;
if (event->buttons() & Qt::LeftButton) { //if you have MOVEd
...do something
}
if (event->buttons() & Qt::RightButton) {
if (pressed==true) return;
else{
...do
}
}
}
On mouserelease you have to set pressed=false; ( "pressed" must be a member of the class)
Hope it helps,let me know
Related
I am trying to implement mouse wheel zoom in/out. It works BUT when I zoom in/out, the image is getting smaller AND scrolls up/down at the same time with zoom function. Look like events exist at the same time and work together.
I cannot find how to disable scrolling with mouse wheel. May be there is a way to make possible scrolling only with mouse cursor (by clicking on scrollbar).
I was overriding the main method of mouse wheel but it was causing the effect I wrote above
void MainWindow::wheelEvent( QWheelEvent* event )
Solved by using event filter. The code below provides zoom in/out with holding ctrl button.
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneWheel)
{
ui->GV_image->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
double scaleFactor = 1.15;
bool ok = QApplication::keyboardModifiers() & Qt::ControlModifier;
if (ok)
{
QGraphicsSceneWheelEvent *scrollevent = static_cast<QGraphicsSceneWheelEvent *>(event);
if (scrollevent->delta() > 0)
{
ui->GV_image->scale(scaleFactor, scaleFactor);
}
else
{
ui->GV_image->scale(1/scaleFactor, 1/scaleFactor);
}
}
event->accept();
return true;
}
return false;
}
Put this line into your constructor or other your init function
QGraphicsView *GV_image;
...
ui->GV_image->scene()->installEventFilter(this);
I have to make a virtual keyboard.
So I created few QPushButtons, but if I click on one, and move to release on another, then the other button doesn't receive any mouse event.
I to override enterEvent(QEvent *) and leaveEvent(QEvent *), but without success when I have clicked on another button.
Anyone got an idea?
In QAbstractButton code:
void QAbstractButton::mousePressEvent(QMouseEvent *e)
{
Q_D(QAbstractButton);
if (e->button() != Qt::LeftButton) {
e->ignore();
return;
}
if (hitButton(e->pos())) {
setDown(true);
d->pressed = true;
repaint(); //flush paint event before invoking potentially expensive operation
QApplication::flush();
d->emitPressed();
e->accept();
} else {
e->ignore();
}
}
When mousePressEvent triggers, QAbstractButton calls setDown(true) and QAbstractButtonPrivate ( Q_D(QAbstractButton) ) calls d->emitPressed(). After that, others buttons will not receive any events, they are already handled in the active button.
You can see in mouseReleaseEvent
void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QAbstractButton);
d->pressed = false;
if (e->button() != Qt::LeftButton) {
e->ignore();
return;
}
if (!d->down) {
// refresh is required by QMacStyle to resume the default button animation
d->refresh();
e->ignore();
return;
}
if (hitButton(e->pos())) {
d->repeatTimer.stop();
d->click();
e->accept();
} else {
setDown(false);
e->ignore();
}
}
It also checks state d->down. And if mouse hits that button, it will call d->click(); emit click event. If mouse does not hit button, it call setDown(false); to reset state.
I suggest to inherit virtual button from QWidget for easier handle mouse events.
I have a subclass of QGraphicsView that should accept two kinds of mouse events: drag and drop for scrolling and simple clicks for item selection/highlight.
So I use
setDragMode(QGraphicsView::ScrollHandDrag);
to enable scrolling the view with the "Hand". And I have a function like this:
void GraphView::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::LeftButton)
emit leftClicked(mapToScene(e->pos()));
else
emit rightClicked(mapToScene(e->pos()));
QGraphicsView::mouseReleaseEvent(e);
}
which creates signal whenever the user clicks on the scene.
However, the problem is: when I stop dragging and release the mouse button, the mouseReleaseEvent function is called, and if the cursor happens to be over some element of the scene, it will get highlighted.
How can I changed the mouseReleaseEvent function so that the signals are created only if there was no previous drag of the mouse?
If you use mousePress and mouseMove in combination with mouseRelease, then you can determine what mouse action the user just performed.
If you have mousePress then mouseRelease, then it must be a simple click.
If you have mousePress, mouseMove, and then mouseRelease, then it must be a drag.
The Qt documentation contains an example of interpreting combinations of mouse events in action in a scribbling program.
http://doc.qt.io/qt-4.8/qt-widgets-scribble-example.html
You can extend the principle to something like this:
private bool MyWidget::dragging = false;
private bool MyWidget::pressed = false;
void MyWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
pressed=true;
}
QGraphicsView::mousePressEvent(event)
}
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && pressed)
{
dragging=true;
}
QGraphicsView::mouseMoveEvent(event)
}
void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && pressed) {
pressed = false;
if (dragging)
{
dragging = false;
}
else
{
// plain mouse click
// do something here
}
}
QGraphicsView::mouseReleaseEvent(event)
}
Note that this does not address edge cases where a user's mouse action is performed only partially inside the widget. I must also admit that I am relatively new to Qt and have not yet used ScrollHandDrag, but this is how one would go about identifying a certain combination of mouse events.
Right now I'm able to detect when only one button is clicked. But I want to detect when both are pressed together. The purpose is to select some items from a QTableView. I'm trying to select them in such a way that when left button is clicked on an item while right button is already kept pressed then the item will be among the selected.
The following code only shows the message that the right button is clicked, but it doesn't show that both the buttons are clicked. How can I manage to detect when both of them are clicked?
bool MainWindow::eventFilter(QObject* obj, QEvent *ev)
{
if(obj = ui->listOfImages->viewport())
{
QMouseEvent * mouseEv = static_cast<QMouseEvent*>(ev);
if(mouseEv->buttons() == Qt::RightButton)
{
qDebug()<<"Right Button clicked!";
if(mouseEv->buttons() == Qt::LeftButton)
{
qDebug()<<"Both button clicked!";
return QObject::eventFilter(obj,ev);
}
}
}
return QObject::eventFilter(obj,ev);
}
Thanks.
Try
if( (mouseEv->buttons() & Qt::RightButton) &&
(mouseEv->buttons() & Qt::LeftButton) )
{
...
}
Hint:
When you just checked buttons() is equal to Qt::RightButton, how could it be equal to Qt::LeftButton?
The QMouseEvent::buttons() function returns a combination of OR'd states of the mouse buttons.
Therefore, to test the left button is pressed, you should be doing this: -
if(mouseEv->buttons() & Qt::LeftButton)
and for the right button: -
if(mouseEv->buttons() & Qt::RightButton)
As the Qt docs state: -
For mouse press and double click events this includes the button that caused the event. For mouse release events this excludes the button that caused the event.
So you can keep track of when buttons are held down and released.
QGraphicsview has a method setDragMode(ScrollHandDrag) to enable panning with the left mouse click. But I wanted to enable panning when the mouse wheel is clicked(the middle button) and created the following custom implementation to pan:
//Within a custom derived class of QGraphicsView
//pan is true when wheel is clicked and false when released
//last Pos is defined somewhere else in the class
void GridView::mouseMoveEvent(QMouseEvent *event){
if(pan){
QPointF currentPos = event->pos();
QPointF relPos = currentPos - lastPos;
lastPos = currentPos;
//this is what creates the panning effect
translate(relPos.x(), relPos.y());
}
QGraphicsView::mouseMoveEvent(event);
}
This works fine for the most part. But for example, if I scale the identity matrix by 1,000,000 this method fails and stops panning (as if the view got stuck). This problem doesn't arise when I use setDragMode()
What would be the proper custom implementation of setDragMode() so it is enabled by the wheel click?
This works for me... it tricks Qt into thinking the user is pressing the left mouse button when he's really pressing the middle one.
void GridView :: mousePressEvent(QMouseEvent * e)
{
if (e->button() == MidButton)
{
QMouseEvent fake(e->type(), e->pos(), LeftButton, LeftButton, e->modifiers());
QGraphicsView::mousePressEvent(&fake);
}
else QGraphicsView::mousePressEvent(e);
}
void GridView :: mouseReleaseEvent(QMouseEvent * e)
{
if (e->button() == MidButton)
{
QMouseEvent fake(e->type(), e->pos(), LeftButton, LeftButton, e->modifiers());
QGraphicsView::mouseReleaseEvent(&fake);
}
else QGraphicsView::mouseReleaseEvent(e);
}