Mouse events blocked because of QGL View

866 views Asked by At

I created a simple project to show the problem I have in a bigger application.
So, I create a mainwindow with 2 buttons. I create a class which inherit from QWidget with 2 buttons and a QGL view.
The problem is that, apparently and for some reason I don't find, the creation of this QGL view blocks some events of the views, particularly mouse events. In the code below, the mouse hover events on the buttons and the main widget of class 1 are not detected (the cursor has to change from Arrow to hand and wait respectively) whereas the mouse cursor changes well on the mainwindow buttons (but in my real application, it's more serious than a simple hover event).
I precise that this problem appears only on Mac 10.6 and superior, and not on Windows. I use Qt 5.1.

Here is the code :

mainwindow.h :

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class Class1;
class PanoramaGLView;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    Class1 *c1;
    PanoramaGLView *gl;
};

#endif // MAINWINDOW_H

mainwindoww.cpp :

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <iostream>
using namespace std;

#include "class1.h"
#include "panoramaglview.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    c1=new Class1(0);
    ui->centralLayout->addWidget(c1);

    //if created here, no problem with mouse cursor on mainwindow buttons but not what I want
    //gl=new PanoramaGLView(0);
    //ui->centralLayout->addWidget(gl);
}

MainWindow::~MainWindow()
{
    delete ui;
}

myglview.h :

#ifndef MYGLVIEW_H
#define MYGLVIEW_H

#include <QGraphicsView>
#include <QtOpenGL/QGLWidget>

class MyGLView : public QGraphicsView
{
    Q_OBJECT

public:
    MyGLView(QWidget* pParent = 0);
    virtual ~MyGLView();

protected:
    QGLWidget* m_pGLWidget;
};

#endif // MYGLVIEW_H

myglview.cpp :

#include "myglview.h"

MyGLView::MyGLView(QWidget* pParent)
: QGraphicsView(pParent)
{
    m_pGLWidget = new QGLWidget(QGLFormat(QGL::SampleBuffers | QGL::AlphaChannel));
    m_pGLWidget->makeCurrent();
    setViewport(m_pGLWidget);

    setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
}

MyGLView::~MyGLView()
{
    delete m_pGLWidget;
}

class1.h :

#ifndef CLASS1_H
#define CLASS1_H

#include <QWidget>

class MyGLView;

namespace Ui {
class Class1;
}

class Class1 : public QWidget
{
    Q_OBJECT

public:
    explicit Class1(QWidget *parent = 0);
    ~Class1();

private:
    Ui::Class1 *ui;

public slots:
    void click1();
};

#endif // CLASS1_H

class1.cpp :

#include "class1.h"
#include "ui_class1.h"

#include "myglview.h"
#include <iostream>
using namespace std;

Class1::Class1(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Class1)
{
    ui->setupUi(this);

    MyGLView *glv=new MyGLView(0);
    ui->verticalLayout->addWidget(glv);

    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(click1()));
}

Class1::~Class1()
{
    delete ui;
}

void Class1::click1(){
    cout<<"Class1::click1()"<<endl;
}

mainwindow.ui :

    <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QVBoxLayout" name="centralLayout">
    <item>
     <widget class="QWidget" name="widget" native="true">
      <property name="styleSheet">
       <string notr="true">background-color: rgb(255, 54, 76);</string>
      </property>
      <layout class="QHBoxLayout" name="horizontalLayout">
       <item>
        <widget class="QPushButton" name="pushButton">
         <property name="cursor">
          <cursorShape>PointingHandCursor</cursorShape>
         </property>
         <property name="text">
          <string>PushButton</string>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

class1.ui :

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Class1</class>
 <widget class="QWidget" name="Class1">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="cursor">
   <cursorShape>WaitCursor</cursorShape>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <property name="styleSheet">
   <string notr="true"/>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout">
   <item>
    <widget class="QPushButton" name="pushButton">
     <property name="cursor">
      <cursorShape>PointingHandCursor</cursorShape>
     </property>
     <property name="text">
      <string>1</string>
     </property>
    </widget>
   </item>
   <item>
    <widget class="QPushButton" name="pushButton_2">
     <property name="cursor">
      <cursorShape>PointingHandCursor</cursorShape>
     </property>
     <property name="text">
      <string>2</string>
     </property>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

If I don't create the GL view, there is no problem of course. And if I create the myGLView instance directly in MainWindow, without class1, it works too. But I need to create différents views and not all in mainwindow (which is usually how ui are created).
In my opinion, it's a problem with the way I create the view, its parent or something like that, as event are passed from parent to child, so I think the problem has a link with that. If it works well, the mouse cursor has to change when the mouse passes over the buttons 1 and 2 (hand cursor) and just hover class1 main widget (waiting cursor).

Any ideas?

1

There are 1 answers

1
Kuba hasn't forgotten Monica On BEST ANSWER

I can confirm that this is a regression. Tested on OS X 10.8.4. It works under Qt 4.8.5, doesn't work under Qt 5.1.0. You should report it as a bug. Below is a sane single-file test case that you will know to produce the next time you post to stackoverflow :)

//main.cpp
#include <QApplication>
#include <QPushButton>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <QGraphicsView>
#include <QGLWidget>

class TestView : public QGraphicsView
{
public:
    explicit TestView(QWidget* parent = 0) : QGraphicsView(parent) {
        setViewport(new QGLWidget());
        setScene(new QGraphicsScene(this));
        scene()->addEllipse(-50, -50, 100, 100, QPen(Qt::red), QBrush(Qt::lightGray));
    }
};

class Pane : public QWidget
{
public:
    explicit Pane(bool hasView, const QCursor & cur, QWidget *parent = 0) :
        QWidget(parent)
    {
        QVBoxLayout * l = new QVBoxLayout(this);
        QPushButton * btn = new QPushButton("[Pane]");
        btn->setCursor(cur);
        l->addWidget(btn);
        if (hasView) l->addWidget(new TestView()); else l->addStretch();
    }
};

class MainWindow : public QWidget
{
    Q_OBJECT
    QStackedWidget *sw;
public:
    explicit MainWindow(QWidget *parent = 0) : QWidget(parent) {
        QVBoxLayout *l = new QVBoxLayout(this);
        QPushButton *btn = new QPushButton("[Main Window] Flip Pages");
        btn->setCursor(Qt::PointingHandCursor);
        connect(btn, SIGNAL(clicked()), SLOT(nextPage()));
        sw = new QStackedWidget();
        l->addWidget(btn);
        l->addWidget(sw);
        sw->addWidget(new Pane(true, Qt::OpenHandCursor));
        sw->addWidget(new Pane(false, Qt::ClosedHandCursor));
    }
    Q_SLOT void nextPage() { sw->setCurrentIndex((sw->currentIndex() + 1) % sw->count()); }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

#include "main.moc"