1
votes

I've a QGridLayout where each cell contains my custom widget QFrameExtended defined as follow:

In .h:

#ifndef QFRAMEEXTENDED_H
#define QFRAMEEXTENDED_H

#include <QObject>
#include <QFrame>

class QFrameExtended : public QFrame
{
    Q_OBJECT

private:

public:
    int id;
    explicit QFrameExtended(QWidget *parent = 0);

signals:
    void mousePressEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
    void pressed(QFrameExtended *);
    void released(QFrameExtended *);

public slots:
    void on_mouse_press();
    void on_mouse_release();
};

#endif // QFRAMEEXTENDED_H

In .cpp:

#include "qframe_extended.h"

QFrameExtended::QFrameExtended(QWidget *parent) : QFrame(parent)
{
    this->id = /* Imagine here there is a function to generate an id */ ;
    connect( this, SIGNAL( mousePressEvent(QMouseEvent*) ), this, SLOT( on_mouse_press() ) );
    connect( this, SIGNAL( mouseReleaseEvent(QMouseEvent*) ), this, SLOT( on_mouse_release() ) );
}

void QFrameExtended::on_mouse_press() {
    emit pressed(this);
}

void QFrameExtended::on_mouse_release() {
    emit released(this);
}

My form creates the QGridLayout with the QFrameExtended widgets and for each of them defines an event handler:

/* ... */
/* This snippet of code is inside a loop that is creating frame objects */
connect(frame, &QFrameExtended::pressed, this, &MyForm::on_mouse_press);
connect(frame, &QFrameExtended::released, this, &MyForm::on_mouse_release);
/* ... */

and finally these are the event handlers:

void MyForm::on_mouse_press(QFrameExtended *frame) {
    qDebug() << "Pressed here: " << frame->id << endl;
}

void MyForm::on_mouse_release(QFrameExtended *frame) {
    qDebug() << "Released here: " << frame->id << endl;
}

When I click on a cell (i.e. a QFrameExtended widget) without release the button, I would see printed on the console the id of the cell. After I moved the mouse over another cell, when I release the button I would see printed the second id.

An example is an output like this:

Pressed here: 1

Released here: 3

but the reality is that when I press the mouse button over a QFrameExtended, he starting to grab all mouse events until I release the button. This is the expected behaviour:

Qt automatically grabs the mouse when a mouse button is pressed inside a widget; the widget will continue to receive mouse events until the last mouse button is released.

From: http://doc.qt.io/qt-4.8/qmouseevent.html

How can I change this behaviour? I'll really appreciate if you can give me also an example

1
Invert the logic: don't accept the mouse event in the sub-widgets, let it propagate up to the container of those widgets, and in there figure out which sub-widget the mouse cursor is on (childAt).peppe

1 Answers

0
votes

Ok, I resolved following the tip of peppe. I tried to extend the QGridLayout but layouts don't support mouse events, because don't inherit from QWidget. So, I extended the QWidget that contains the layout.

In .h:

#ifndef QWIDGETEXTENDED_H
#define QWIDGETEXTENDED_H

#include <QWidget>
#include <QString>
#include <QMouseEvent>
#include "qframe_extended.h"

class QWidgetExtended : public QWidget
{
    Q_OBJECT
public:
    explicit QWidgetExtended(QWidget *parent = 0);

protected:
    virtual void mousePressEvent(QMouseEvent *);
    virtual void mouseReleaseEvent(QMouseEvent *);

signals:
    void pressed(QFrameExtended *);
    void released(QFrameExtended *);

};

#endif

In .cpp:

#include "qwidget_extended.h"
#include "qframe_extended.h"

QWidgetExtended::QWidgetExtended(QWidget *parent) : QWidget(parent)
{

}

void QWidgetExtended::mousePressEvent(QMouseEvent *event) {
    QFrameExtended frame;
    QWidget *widget = this->childAt(event->pos());
    if (widget != NULL) {
        QString widgetClassName(widget->metaObject()->className());
        //I don't use explicitly the string because if one day someone changes the name of the class, the compiler will output an error
        QString className(frame.metaObject()->className());
        if (widgetClassName == className) {
            emit pressed(dynamic_cast<QFrameExtended*> (widget));
        }
    }
}

void QWidgetExtended::mouseReleaseEvent(QMouseEvent *event) {
    QFrameExtended frame;
    QWidget *widget = this->childAt(event->pos());
    if (widget != NULL) {
        QString widgetClassName(widget->metaObject()->className());
        //I don't use explicitly the string because if one day someone changes the name of the class, the compiler will output an error
        QString className(frame.metaObject()->className());
        if (widgetClassName == className) {
            emit released(dynamic_cast<QFrameExtended*> (widget));
        }
    }
}