0
votes

I have a QMainWindow which contains a circular QWidget inside it. In order to have a circular shaped QWidget I am making use of QWidget::setMask. The intended behaviour of the application on mouse press is inside the MainWindow depends on the region on which mouse is pressed.

class MyMainWindow: public QMainWindow
{
public:
    MyMainWindow():QMainWindow()
    {

    }
    void mousePressEvent( QMouseEvent * event )
    {
        qDebug()<<"Clicked on MainWindow";
    }
};

class CircularWidget: public QWidget
{
public:
    CircularWidget( QWidget * parent ):QWidget( parent )
    {

    }
    void paintEvent(QPaintEvent * event)
    {
        QRegion circularMask( QRect( pos(), size() ), QRegion::Ellipse );
        setMask( circularMask );
        setStyleSheet("background-color:black;");
        QWidget::paintEvent( event );
    }
    void mousePressEvent( QMouseEvent * event )
    {
        qDebug()<<"Clicked on Circular Widget";
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QMainWindow w;
    w.resize( 400, 400 );

    CircularWidget circularWidget( &w );
    circularWidget.show();

    w.setCentralWidget( &circularWidget );
    w.show();
    return a.exec();
}

enter image description here

Currently, when I click inside the circular region I get the event in my Widget. But all the mouse press events outside the circle are lost. I saw in the Qt Documentations that: Masked widgets receive mouse events only on their visible portions. Is there any way to transfer the other mouse click events (events on the grey region in the picture) to the parent widget?

2
So the CircularWidget covers whole main window? How do you place this widget in the main window?vahancho
I will have to resize it, But currently it covers the whole mainWindow. I just want all the mouse events that are made outside of the circle to be taken up by the mainwindowsajas

2 Answers

2
votes

The reason why you did not get mouse events in your MyMainWindow class is because in your main() function you create the main window object of class QMainWindow instead. For handling the mouse click events on the circular widget I would use signal/slot mechanism here. I.e. let the circular widget emit a signal each time it is clicked. Any other receiver will handle it as its own. For example:

class MyMainWindow: public QMainWindow
{
    Q_OBJECT
    [..]
public slots:
    void handleMouseClick(const QPoint &) {}
};

class CircularWidget: public QWidget
{
    Q_OBJECT
public:
    [..]
    void mousePressEvent( QMouseEvent * event )
    { emit mouseClicked(event->pos()); }
signals:
    void mouseClicked(const QPoint &);
};

And finally establish connection. With this in MyMainWindow class you will be able to handle mouse click events both from circular widget and main window itself.

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyMainWindow w; // <-------- This should be MyMainWindow instead of QMainWindow

    CircularWidget circularWidget( &w ); 
    w.setCentralWidget( &circularWidget );

    QObject::connect(&circularWidget, SIGNAL(mouseClicked(const QPoint &)),
                     &w, SLOT(handleMouseClick(const QPoint &));

    return a.exec();
}
2
votes

Proper solution is reject mouse press event if pointer is outside of region so more or less it should look like this:

void mousePressEvent( QMouseEvent * event )
{
    QRegion circularMask( QRect( pos(), size() ), QRegion::Ellipse ); // it would be nice to make it a class field

    if (!circularMask.contains(event->pos()) {
        event->ignore();
    }
}

See documentation:

A mouse event contains a special accept flag that indicates whether the receiver wants the event. You should call ignore() if the mouse event is not handled by your widget. A mouse event is propagated up the parent widget chain until a widget accepts it with accept(), or an event filter consumes it.