[Qt-interest] QML Images displayed incorrectly on Linux/X11 with OpenGL viewport + Crash on Windows

Pierre Fillard pierre.fillard at gmail.com
Sat Aug 13 18:22:41 CEST 2011


Hello folks,


Sorry about the title, the two problems are IMO not connected at all. But I
am running into those on the same code snippet and they are puzzling me.
First, my setup:


Qt Desktop SDK 4.7.3
Linux Ubuntu 11.04 x86_64
Windows 7 / Visual Studio 2010 express


*Now the description:*

(I moved all the code samples at the end of the post - anyone should be able
to reproduce what I am describing now with this minimal example. The code
snippet can also be downloaded from here:
https://transfert.inria.fr/fichiers/f0ab563059f84fb4b3ca77e7ddfdf2b1/qml_bug.rar-
it is available for 5 months).


I want to display a *toolbar* on top of a *QGraphicsView* and *animate
it*when the mouse enters the top of the view. The toolbar is designed
using QML
and called from a C++ app.


I wrote a QML element, namely a ToolBar (see ToolBar.qml), composed of
ToolButtons (see ToolButton.qml). Those ToolButtons are made of a MouseArea
and an Image showing the ToolButton icon. Nothing exceptional. Note that
icons are taken from a Qt resource file that I embedd in my binary.


Now, those QML elements are created from my C++ app using customized
QGraphicsScene / QGraphicsView (see myGraphicsView / myGraphicsScene) and
QDeclarativeComponent. *My QGraphicsView sets its viewPort to an openGL
Widget* because I need it for displaying other stuff. My QGraphicsScene is
responsible for creating the QML element and adding it to itself. I also use
some logic using a QStateMachine to make the toolbar appear / disappear
smoothly (using an animation) when the mouse is over the top the view.


In my main app (see main.cpp), *I finally create two of these* (two pairs of
(view , scene) embedded in an horizontal layout).


*Now the problems:*


   1. on Linux, *toolbar icons are totally mixed up or just shown
   incorrectly* (random pixels). I also get tons of X errors about invalid
   pixmap parameters. If I use a regular QWidget as a viewPort for my
   QGraphicsView, everything works fine (but this is not an option). I tried to
   use item providers, clearing the QPixmapCache, nothing worked. This problem
   occurs only on Linux, meanging that the behaviour is correct on Windows and
   Mac.

   2. *on Windows, if compiled in Release mode, the program crashes when
   emitting the signal enterToolbarArea()*. This signal is emitted when the
   mouse passes over a certain region of the view. It is emitted from the
   mouseMoveEvent() of the QGraphicsView. This event is then interpreted by the
   state machine to trigger the display of the toolbar.
   Note that *if I remove any signal declaration in the root Item of the
   ToolBar* (see ToolBar.qml - I added a custom dummy signal which is
   actually never called), *the program runs fine*. If *I remove the
   animation, the program runs fine as well*.
   The bug *only appears when compiling in Release mode with Visual
Studio*(compiling in Debug or on any other system, it works). I tried
with other
   version of visual studio, same effect.


If anyone has an idea about one or the other problem, you'll be my champion.


Cheers,
Pierre.


*Now the code:*

ToolButton.qml:

import Qt 4.7
>
> Rectangle {
>      id: container
>
>      property string text: "Button"
>
>      property string icon
>
>      signal clicked (bool value);
>      signal pressed
>      signal released
>
>      SystemPalette { id: activePalette }
>
>      width:  45
>      height: 45
>      smooth: true
>
>      color: {
>          if (mouseArea.pressed) {
>             return activePalette.highlight;
>          }
>          else {
>             return "gray";
>          }
>      }
>
>      MouseArea {
>          id: mouseArea
>          anchors.fill: parent
>          onClicked: {container.clicked(true);}
>
>          onPressed: container.pressed();
>
>          onReleased: {container.released();}
>      }
>
>      Image {
>          id: myImage
>          smooth: true
>          anchors.centerIn: container
>          source: container.icon
>          sourceSize.width: container.width
>          sourceSize.height: container.height
>      }
>  }
>


ToolBar.qml:

import Qt 4.7
>
>  Item {
>      width: 640
>      height: 45
>
>      signal dummySignal // makes app crash on Windows when compiled in
> Release mode
>
>      Rectangle {
>          id:myToolBar
>          objectName:"toolBar"
>
>          anchors.fill: parent
>
>         color: "transparent"
>
>         property int spacing: 5
>
>
>          ToolButton {
>              id: tb1
>              icon: "/icons/designer.png"
>
>              anchors.right: parent.right
>              anchors.verticalCenter: parent.verticalCenter
>          }
>
>          ToolButton {
>              id: tb2
>              icon:  "/icons/go-next.png"
>
>              anchors.right: tb1.left
>              anchors.rightMargin: parent.spacing
>              anchors.verticalCenter: parent.verticalCenter
>         }
>
>          ToolButton {
>              id: tb3
>              icon:  "/icons/qwebview.png"
>
>              anchors.right: tb2.left
>              anchors.rightMargin: parent.spacing
>              anchors.verticalCenter: parent.verticalCenter
>          }
>
>          ToolButton {
>              id: tb4
>              icon:  "/icons/videoplayer.png"
>
>              anchors.right: tb3.left
>              anchors.rightMargin: parent.spacing
>              anchors.verticalCenter: parent.verticalCenter
>          }
>
>          Rectangle {
>              id: spacer
>              anchors {right: tb4.left; rightMargin: 5; verticalCenter:
> parent.verticalCenter}
>              width: parent.width - 4*(tb1.width + 5)
>              height: parent.height
>              color: "white"
>          }
>      }
>  }
>


myGraphicsView.h:

#ifndef MYGRAPHICSVIEW_H
> #define MYGRAPHICSVIEW_H
>
> #include <QtGui>
>
> class myGraphicsScene;
> class myGraphicsViewPrivate;
>
> class myGraphicsView : public QGraphicsView
> {
>     Q_OBJECT
>
> public:
>              myGraphicsView (myGraphicsScene * scene, QWidget * parent =
> 0);
>     virtual ~myGraphicsView (void);
>
> signals:
>     void enterToolbarArea (void);
>     void leaveToolbarArea (void);
>
> protected:
>     void resizeEvent (QResizeEvent * event);
>     void mouseMoveEvent (QMouseEvent *event);
>
> private:
>     myGraphicsViewPrivate *d;
> };
>
> #endif // MYGRAPHICSVIEW_H
>


myGraphicsView.cpp:

#include "myGraphicsView.h"
>
> #include "myGraphicsScene.h"
>
> #include <QGLWidget>
>
> #include <QDeclarativeItem>
>
> class myGraphicsViewPrivate
> {
> public:
>     bool top;
>
>     myGraphicsScene *scene;
>
>     QStateMachine *stateMachine;
>
>     QState *toolbarState;
>     QState *defaultState;
>
>     QPropertyAnimation *toolbarAnimation;
> };
>
> myGraphicsView::myGraphicsView (myGraphicsScene * scene, QWidget * parent)
>     : QGraphicsView (scene, parent), d (new myGraphicsViewPrivate)
> {
>     this->setViewport(new QGLWidget(this) );
>     this->setViewportUpdateMode(
>
>     QGraphicsView::FullViewportUpdate);
>     this->setCacheMode(CacheNone);
>     this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
>     this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
>     this->setMouseTracking(true);
>
>     Q_ASSERT (scene!=NULL);
>
>     d->scene = scene;
>
>     d->top = false;
>
>     d->toolbarAnimation = new QPropertyAnimation (d->scene->toolbar(), "y",
> this);
>     d->toolbarAnimation->setDuration(250);
>     d->toolbarAnimation->setEasingCurve(QEasingCurve::InOutQuad);
>
>     // Build the state machine
>     d->stateMachine = new QStateMachine (this);
>
>     d->toolbarState = new QState (d->stateMachine);
>     d->defaultState = new QState (d->stateMachine);
>
>     d->stateMachine->setInitialState (d->defaultState);
>
>     d->defaultState->addTransition (this, SIGNAL (enterToolbarArea()),
> d->toolbarState)
>         ->addAnimation (d->toolbarAnimation);
>     d->toolbarState->addTransition  (this, SIGNAL (leaveToolbarArea()),
> d->defaultState)
>         ->addAnimation (d->toolbarAnimation);
>
>     QRectF rect = d->scene->toolbar()->boundingRect();
>
>     d->toolbarState->assignProperty  (d->scene->toolbar(), "y", 0);
>     d->defaultState->assignProperty  (d->scene->toolbar(), "y",
> -rect.height());
>
>     d->stateMachine->start();
> }
>
> myGraphicsView::~myGraphicsView (void)
> {
>     delete d;
> }
>
> void myGraphicsView::resizeEvent (QResizeEvent * event)
> {
>     QGraphicsView::resizeEvent (event);
>
>     if (d->scene) {
>         QPointF shownPos  = this->mapToScene (0, 0);
>         QPointF hiddenPos = this->mapToScene (0, -45);
>
>         if (d->stateMachine->configuration().contains (d->toolbarState))
>             d->scene->toolbar()->setPos ( shownPos );
>         else
>             d->scene->toolbar()->setPos ( hiddenPos );
>
>         d->scene->toolbar()->setWidth ( event->size().width() );
>
>         d->toolbarState->assignProperty  (d->scene->toolbar(), "y",
> shownPos.y());
>         d->defaultState->assignProperty  (d->scene->toolbar(), "y",
> hiddenPos.y());
>
>         this->update();
>     }
> }
>
>
> void myGraphicsView::mouseMoveEvent( QMouseEvent * e )
> {
>     if ( e->buttons() == Qt::NoButton ) {
>         if (d->scene->toolbar()->boundingRect().contains ( e->pos() ) ) {
>             if (!d->top) {
>                 d->top = true;
>                 emit enterToolbarArea();
>             }
>         }
>         else {
>             if (d->top) {
>                 d->top = false;
>                 emit leaveToolbarArea();
>             }
>         }
>     }
>     else
>         QGraphicsView::mouseMoveEvent (e);
> }
>


myGraphicsScene.h:

#ifndef MYGRAPHICSSCENE_H
> #define MYGRAPHICSSCENE_H
>
> #include <QtGui>
>
> class QDeclarativeItem;
> class myGraphicsScenePrivate;
>
> class myGraphicsScene : public QGraphicsScene
> {
>     Q_OBJECT
>
> public:
>              myGraphicsScene (QObject * parent = 0);
>     virtual ~myGraphicsScene (void);
>
>     QDeclarativeItem *toolbar (void) const;
>
> private:
>     myGraphicsScenePrivate *d;
>
> };
>
> #endif // myGraphicsScene_H
>


myGraphicsScene.cpp:

#include "myGraphicsScene.h"
>
> #include <QDeclarativeEngine>
> #include <QDeclarativeComponent>
> #include <QDeclarativeItem>
>
> #include <QDebug>
>
> class myGraphicsScenePrivate
> {
> public:
>     QDeclarativeEngine  *engine;
>     QDeclarativeItem    *toolbar;
> };
>
> myGraphicsScene::myGraphicsScene(QObject *parent)
>     : QGraphicsScene (parent), d (new myGraphicsScenePrivate)
> {
>     d->engine  = new QDeclarativeEngine (this);
>
>     QDeclarativeComponent component (d->engine,
> QUrl("qrc:/qml/ToolBar.qml"));
>     d->toolbar = qobject_cast<QDeclarativeItem *>(component.create());
>     if (!d->toolbar) {
>         qDebug() << "cannot create toolbar";
>         qDebug() << component.errorString();
>     }
>     Q_ASSERT (d->toolbar!=NULL);
>
>     d->toolbar->setPos (0, 0);
>     d->toolbar->setHeight (45);
>     d->toolbar->setY(-45);
>
>     this->addItem (d->toolbar);
> }
>
> myGraphicsScene::~myGraphicsScene (void)
> {
>     delete d;
> }
>
> QDeclarativeItem *myGraphicsScene::toolbar (void) const
> {
>     return d->toolbar;
> }
>


main.cpp:

#include <QApplication>
>
> #include <QtGui>
>
> #include "myGraphicsScene.h"
> #include "myGraphicsView.h"
>
> int main (int argc, char *argv[])
> {
>     QApplication application (argc, argv);
>
>     QMainWindow mainWindow;
>
>     QWidget *mainWidget = new QWidget (&mainWindow);
>
>     // create 2 scenes
>     myGraphicsScene *scene1 = new myGraphicsScene (mainWidget);
>     myGraphicsScene *scene2 = new myGraphicsScene (mainWidget);
>
>     // create 2 myGraphicsView instances
>     myGraphicsView *view1 = new myGraphicsView (scene1, mainWidget);
>     myGraphicsView *view2 = new myGraphicsView (scene2, mainWidget);
>
>     // create a default layout
>     QHBoxLayout * layout = new QHBoxLayout (mainWidget);
>     layout->addWidget (view1);
>     layout->addWidget (view2);
>
>     mainWindow.setCentralWidget (mainWidget);
>     mainWindow.resize (640, 480);
>
>     mainWindow.show();
>
>     return application.exec();
> }
>


-- 
Pierre Fillard, Ph.D.,
Research Scientist
INRIA Parietal - Neurospin
Bât 145, Point Courrier 156
91191 Gif/Yvette, France
tel: +33 1 69 08 79 92

INRIA Saclay-Île-de-France,
Parc Orsay Université
4, rue Jacques Monod
91893 Orsay cedex
tel: +33 1 72 92 59 62
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20110813/c7c42a47/attachment.html 


More information about the Qt-interest-old mailing list