QGLWidget within a QAbstractScrollArea
-
Hello.
I've been trying to put a QGLWidget as a viewport in a QAbstractScrollArea subclass.
But for some reason my QGLWidget won't draw.Do I need to inherit any functions or call protected functions to make it work?
-
Can you not just use QScrollArea and QScrollArea::setWidget()? Something like:
@
QScrollArea* scroll = new QScrollArea( this );
QGLWidget* glWidget = new QGLWidget;
scroll->setWidget( glWidget );
@Not tested, but I think it should work. You may need to set a size for your QGLWidget.
Edit: Fixed typo. s/QScrollWidget/QScrollArea/
-
[quote author="ZapB" date="1301599554"]Can you not just use QScrollArea and QScrollArea::setWidget()? Something like:
@
QScrollWidget* scroll = new QScrollWidget( this );
QGLWidget* glWidget = new QGLWidget;
scroll->setWidget( glWidget );
@Not tested, but I think it should work. You may need to set a size for your QGLWidget.[/quote]
What's a QScrollWidget? I don't have it, I'm using Qt 4.7. -
Oopsy sorry, I meant QScrollArea not QScrollWidget. The text was right the code was wrong.
-
I tried doing that.
It still doesn't render.I think I really do need to inherit QAbstractScrollArea.
Any more suggestions?
-
It works for me (tm). Here is an example showing it in action.
Create a new Qt C++ application using qt-creator and choose QMainWindow as the base class for the main window in the wizard.
Then in design mode, add a QScrollArea to the main window and lay it out vertically. I also changed the name of the scroll area to m_scrollArea (as you'll see in the code below).
Now edit the project so that it looks like this:
mainwindow.h : no changes needed.
mainwindow.cpp:
@
#include "mainwindow.h"
#include "ui_mainwindow.h"#include "solarsystem.h"
MainWindow::MainWindow( QWidget* parent )
: QMainWindow( parent ),
ui( new Ui::MainWindow )
{
ui->setupUi( this );
SolarSystem* solar = new SolarSystem;
solar->setMinimumSize( 1024, 768 );
ui->m_scrollArea->setWidget( solar );
}MainWindow::~MainWindow()
{
delete ui;
}
@All I do is create a SolarSystem widget (which is derived from QGLWidget - source below). This just gives us something to look at ;-)
main.cpp:
@
#include <QtGui/QApplication>
#include "mainwindow.h"#include <GL/glut.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
glutInit( &argc, argv );
MainWindow w;
w.show();return a.exec();
}
@For completeness here is my SolarSystem class (ported from one of the examples in the OpenGL superbible book):
solarsystem.h:
@
#ifndef SOLARSYSTEM_H
#define SOLARSYSTEM_H#include <QGLWidget>
class SolarSystem : public QGLWidget
{
Q_OBJECT
public:
SolarSystem( QWidget* parent = 0 );public slots:
void advance();protected:
virtual void initializeGL();
virtual void resizeGL( int w, int h );
virtual void paintGL();virtual void keyPressEvent( QKeyEvent* e );
private:
float m_thetaEarth;
float m_thetaMoon;
};#endif // SOLARSYSTEM_H
@solarsystem.cpp:
@
#include "solarsystem.h"#include <QApplication>
#include <QKeyEvent>
#include <QTimer>
#include <QVector3D>#include <GL/glut.h>
SolarSystem::SolarSystem( QWidget* parent )
: QGLWidget( parent ),
m_thetaEarth( 0.0f ),
m_thetaMoon( 0.0f )
{
QTimer* timer = new QTimer( this );
connect( timer, SIGNAL( timeout() ), SLOT( advance() ) );
timer->start( 1000 / 60 );
}void SolarSystem::advance()
{
m_thetaEarth += 0.25f;
if ( m_thetaEarth > 360.0f )
m_thetaEarth -= 360.0f;m_thetaMoon += 2.0f; if ( m_thetaMoon > 360.0f ) m_thetaMoon -= 360.0f; updateGL();
}
void SolarSystem::initializeGL()
{
// Set the clear color to black
glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );// Enable depth testing glEnable( GL_DEPTH_TEST ); // Enable back face culling glFrontFace( GL_CCW ); // Counter clock-wise polygons face out glEnable( GL_CULL_FACE ); // Enable lighting const float whiteLight[] = { 0.2f, 0.2f, 0.2f, 1.0f }; const float sourceLight[] = { 0.8f, 0.8f, 0.8f, 1.0f }; glEnable(GL_LIGHTING); // Setup and enable light 0 glLightModelfv( GL_LIGHT_MODEL_AMBIENT, whiteLight ); glLightfv( GL_LIGHT0, GL_DIFFUSE, sourceLight ); glEnable( GL_LIGHT0 ); // Enable color tracking glEnable( GL_COLOR_MATERIAL ); // Set Material properties to follow glColor values glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
}
void SolarSystem::resizeGL( int w, int h )
{
// Prevent a divde by zero
if ( h == 0 )
h = 1;// Set the viewport to window dimensions glViewport( 0, 0, w, h ); // reset the coordinate system glMatrixMode( GL_PROJECTION ); glLoadIdentity(); // Establish the clipping volume by setting up an orthographic projection double aspectRatio = double( w ) / double( h ); double verticalViewingAngle = 45.0; gluPerspective( verticalViewingAngle, aspectRatio, 1.0, 425.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity();
}
void SolarSystem::paintGL()
{
// Clear the buffer with the current clearing color
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );// Set the identity modelview transform glMatrixMode( GL_MODELVIEW ); glPushMatrix(); // Translate the whole scene a little glTranslatef( 0.0f, 0.0f, -300.0f ); // Set drawing colour to yellow and draw the Sun glColor3f( 1.0f, 1.0f, 0.0f ); glDisable( GL_LIGHTING ); glutSolidSphere( 15.0f, 30, 17 ); glEnable( GL_LIGHTING ); // Position a light to simulate the Sun as a light source const float lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f }; glLightfv( GL_LIGHT0, GL_POSITION, lightPos ); // Draw the Earth glColor3f( 0.0f, 0.0f, 1.0f ); glRotatef( m_thetaEarth, 0.0f, 1.0f, 0.0f ); glTranslatef( 105.0f, 0.0f, 0.0f ); glutSolidSphere( 15.0f, 30, 17 ); // Rotate from Earth based coords and draw the moon glColor3f( 0.7f, 0.7f, 0.7f ); glRotatef( m_thetaMoon, 0.0f, 1.0f, 0.0f ); glTranslatef( 30.0f, 0.0f, 0.0f ); glutSolidSphere( 6.0f, 15, 15 ); glPopMatrix();
}
void SolarSystem::keyPressEvent( QKeyEvent* e )
{
switch ( e->key() )
{
case Qt::Key_Escape:
QCoreApplication::instance()->quit();
break;default: QGLWidget::keyPressEvent( e ); }
}
@Anyway, the above all runs and works as expected. I see scroll bars when the mainwindow and scroll area are too small to accomodate the minimum size of the SolarSystem widget.
-
Apparently I needed to set the minimum size.
It works and all but I need control over the scrollbars..
So I've to use the QAbstractScrollArea anyway.MapView.h (QAbstractScrollArea class decleration):
@#ifndef MAPVIEW_H
#define MAPVIEW_H#include <QAbstractScrollArea>
class Map;
class MapRenderer;class MapView : public QAbstractScrollArea
{
Q_OBJECT
public:
explicit MapView(QWidget *parent = 0);void setMap(Map *map);
private:
Map* mMap;
MapRenderer *mMapRenderer;
};#endif // MAPVIEW_H
@MapView.cpp (QAbstractScrollArea class implementation):
@#include "mapview.h"
#include "map.h"
#include "maprenderer.h"#include <QScrollBar>
MapView::MapView(QWidget *parent) :
QAbstractScrollArea(parent),
mMap(0),
mMapRenderer(0)
{
setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}void MapView::setMap(Map *map)
{
mMap = map;
mMapRenderer = new MapRenderer(map);setViewport(mMapRenderer);
}
@MapRenderer.cpp (QGLWidget subclass implementation):
@#include "maprenderer.h"MapRenderer::MapRenderer(Map *map, QWidget *parent) :
QGLWidget(parent),
mMap(map)
{
}void MapRenderer::initializeGL()
{
glViewport(0, 0, width(), height());glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, 320.0 / 240.0, 0.001, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 20.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
void MapRenderer::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}void MapRenderer::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
@This is how I use the MapView:
@mMapView = new MapView();
setCentralWidget(mMapView);@ -
Glad that you got it working. Good luck with the rest of your project.
-
[quote author="ZapB" date="1301668583"]Glad that you got it working. Good luck with the rest of your project.[/quote]
It doesn't work.. -
Which aspect? The example I posted worked in that it embedded a QGLWidget into the scroll view. What else is missing?
-
I'm talking about my code. I said I needed help with inheriting QAbstractScrollArea not QScrollArea, that's because I need control over the scrollbars.
[quote author="ZapB" date="1302016156"]Which aspect? The example I posted worked in that it embedded a QGLWidget into the scroll view. What else is missing?[/quote] -
But you have not said how it doesn't work or what you are trying to achieve. Simply saying that you want/need to use QAbstractScrollArea to control the scroll bars is not enough info. What does QScrollArea do with the scroll bars that is wrong in your case?
I am only trying to help but I need more information to do so.
-
[quote author="ZapB" date="1302016490"]But you have not said how it doesn't work or what you are trying to achieve. Simply saying that you want/need to use QAbstractScrollArea to control the scroll bars is not enough info. What does QScrollArea do with the scroll bars that is wrong in your case?
I am only trying to help but I need more information to do so.[/quote]
What doesn't work is that I don't see the graphics produced by the QGLWidget in my QAbstractScrollArea.
QGLWidget is set as its viewport.
I tried setting a breakpoint in the paintGL and it did reach it, so I guess the problem is in the QAbstractScrollArea. -
QAbstractScrollArea by default filters some events for its viewport widget, including the paint event (QPaintEvent / QEvent::Paint). You need to manually forward it from the derived QAbstractScrollArea to your QGLWidget.
One way to do this, is to override viewportEvent() in your MapView, and return false to indicate that the paint event should be propagated to the viewport(), i.e.:
@bool MapView ::viewportEvent(QEvent* e)
{
if (e->type() == QEvent::Paint)
return false;
return QAbstractScrollArea::viewportEvent(e);
}
@