Results 1 to 13 of 13

Thread: QGraphicsScene with lots of static items

  1. #1
    Join Date
    Feb 2006
    Posts
    8
    Thanks
    2
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default QGraphicsScene with lots of static items

    Hi!

    I'd like to write a browser for nucleotide sequence alignments. You could see "alignments" as huge matrices of coloured tiles, with the background colour of the tile and the letter printed on it indicating the type of nucleotide at that position. The matrix is full and, when displayed, the area is completely covered by the tiles. The content of the matrix doesn't change and we only want to display it. The size of the matrix varies a lot: it can be from 20 (rows) x 500 (columns) up to hundreds or thousands of rows and tens or hundreds of thousands of columns. We can here assume that it is 80 rows times 5000 columns, giving in total 400k tiles. "Browsing the alignment" means that we can move around to see different parts of the matrix and zoom in/out to see either exact details or an overview.

    I have an implementation that seems to work reasonably well but there are details that could be improved (see blow for the code). I followed the 4k Chips example and used objects inheriting QGraphicsItem to show more details (letter) when zoomed in and only the colour when zoomed out. The main problem in my implementation is its slowness when zooming out and showing lots of items simultaneously.

    My idea to get around this bottleneck is to render an image of the matrix when the zoom-out level is such that the exact details won't anyway be shown, and scale that pixmap to zoom further out. When zooming in, the pixmap would be replaced by the individually drawn tiles. This is my idea but I don't know how to do that. I'm quite sure it's doable and possibly someone has already done something similar. Can you give links to existing code or suggestions how you would do it. If you know a much better way to get around this zooming problem, I'd obviously be very happy to hear about that.

    I've attached code that generates dummy data and displays these in a browser window. When you zoom out (Ctrl+mouse wheel) you can see that the scaling isn't smooth and the application becomes unresponsive.

    Thanks a lot for any help!

    Qt Code:
    1. #include <qapplication.h>
    2. #include <qmainwindow.h>
    3. #include <qgraphicsview.h>
    4. #include <qgraphicsscene.h>
    5. #include <qgraphicsitem.h>
    6. #include <QWheelEvent>
    7. #include <QtOpenGL>
    8. #include <qmath.h>
    9. #include <qcolor.h>
    10.  
    11. using namespace std;
    12.  
    13.  
    14. class BaseTile : public QGraphicsItem
    15. {
    16. public:
    17. BaseTile(int i);
    18. QRectF boundingRect() const{ return QRectF(0, 0, 20, 20); }
    19.  
    20. void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
    21. private:
    22. QColor color;
    23. QChar base_char;
    24. };
    25.  
    26.  
    27. class MainWindow : public QMainWindow
    28. {
    29. public:
    30. MainWindow(QWidget *parent = 0);
    31. private:
    32. void wheelEvent(QWheelEvent * event);
    33.  
    34. QGraphicsView *graphicsView;
    35. };
    36.  
    37. /////////////////////
    38.  
    39. BaseTile::BaseTile(int i)
    40. {
    41. QString alpha = "ACGT";
    42. QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
    43.  
    44. base_char = alpha.at(i);
    45. color = tile_colors[i];
    46. }
    47.  
    48. void BaseTile::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    49. {
    50. Q_UNUSED(widget);
    51.  
    52. const qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());
    53. if (lod < 0.5) {
    54. painter->fillRect(QRectF(0, 0, 20, 20), color);
    55. return;
    56. }
    57.  
    58. QBrush b = painter->brush();
    59. painter->fillRect(QRectF(0, 0, 20, 20), color);
    60. painter->setFont(QFont("Times",10));
    61. painter->setPen(QColor("black"));
    62. painter->drawText(0, 0, 20, 20,0x0084, QString(base_char));
    63. }
    64.  
    65. /////////////////////
    66.  
    67. void MainWindow::wheelEvent(QWheelEvent * e)
    68. {
    69. if ( e->modifiers() == Qt::ControlModifier )
    70. {
    71. int numSteps = ( e->delta() / 8 ) / 15;
    72.  
    73. QMatrix mat = graphicsView->matrix();
    74.  
    75. if ( numSteps > 0 )
    76. mat.scale( numSteps * 1.2, numSteps * 1.2 );
    77. else
    78. mat.scale( -1 / ( numSteps * 1.2 ), -1 / ( numSteps * 1.2 ) );
    79.  
    80. graphicsView->setMatrix(mat);
    81. e->accept();
    82. }
    83. }
    84.  
    85. MainWindow::MainWindow(QWidget *parent) :
    86. QMainWindow(parent)
    87. {
    88.  
    89. // generate random data to display
    90. //
    91. vector< vector<int> > data;
    92. int seq_length = 5000;
    93. int num_seq = 80;
    94.  
    95. vector<int> seq0;
    96. for(int j=0;j<seq_length;j++)
    97. {
    98. seq0.push_back( int(rand()/float(RAND_MAX)*4) );
    99. }
    100. data.push_back(seq0);
    101.  
    102. for(int i=1;i<num_seq;i++)
    103. {
    104. vector<int> seq_i;
    105. for(int j=0;j<seq_length;j++)
    106. {
    107. if(rand()/float(RAND_MAX)*20 < 1)
    108. seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
    109. else
    110. seq_i.push_back( data.at(0).at(j) );
    111. }
    112. data.push_back(seq_i);
    113. }
    114.  
    115.  
    116.  
    117. // the browser stuff
    118. //
    119. scene = new QGraphicsScene();
    120.  
    121. int y_pos = 0;
    122. for (int i = 0; i < num_seq; i++)
    123. {
    124. int x_pos = 0;
    125.  
    126. for (int j = 0; j < seq_length; j++)
    127. {
    128. int base = data.at(i).at(j);
    129.  
    130. BaseTile *item = new BaseTile(base);
    131. item->setPos(QPointF(x_pos, y_pos));
    132. scene->addItem(item);
    133.  
    134. x_pos += 20;
    135. }
    136. y_pos += 20;
    137. }
    138.  
    139.  
    140. graphicsView = new QGraphicsView(this);
    141. graphicsView->setRenderHint(QPainter::Antialiasing, false);
    142. graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
    143. graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
    144. graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    145. graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    146. graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
    147. graphicsView->setScene(scene);
    148. graphicsView->setGeometry(QRect(50, 50, 100, 100));
    149. graphicsView->show();
    150.  
    151.  
    152. this->setCentralWidget(graphicsView);
    153.  
    154. }
    155.  
    156. /////////////////////
    157.  
    158. int main(int argc, char *argv[])
    159. {
    160. QApplication a(argc, argv);
    161.  
    162. MainWindow w;
    163. w.show();
    164. return a.exec();
    165. }
    166.  
    167. /////////////////////
    168.  
    169. /*
    170. g++ -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL -I/usr/include/qt4 -L/usr/lib -lQtOpenGL -lQtGui -lQtCore -lGLU -lGL -lpthread test.cpp -o test
    171. */
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Lari!

    Rendering Text is slow. And you have only for different characters / items to draw. Why don't you render 4 textures at programm startup? QImage, QPainter => QGLWidget::bindTexture.

    Then I would use only one QGraphicsItem that draws all visible data by drawing the textures to appropriate positions - QGLWidget::drawTexture

    Should be quite quick to implement and see if the performance is good enough!

    Johannes

  3. #3
    Join Date
    Feb 2006
    Posts
    8
    Thanks
    2
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Johannes!

    That's an interesting idea but unfortunately I have zero experience on QGLWidgets and can't do even a "trivial" thing like that. I understand the idea of making a set of images (I tested a version that draws pre-defined QPixmaps on GraphicsScene instead of GraphicsItem objects) but don't know how to create textures and then draw those on GraphicsScene. Can you give more detailed code for those bits, please.

    Thanks a lot in advance!

    Regards, Lari

  4. #4
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Lari!

    I just looked into the matter with more detail: Qt's OpenGL Painter automatically assigns textures to QPixmaps. So when you repaint the same Pixmap over and over again, this should be blazing fast.

    Due to this http://bugreports.qt.nokia.com/browse/QTBUG-6800 it wont be possible to use the low-level- bindtexture/drawtexture with the painter setup to the view, if I understand that correctly. So you would have to implement zooming and scrolling manually.

    How fast is the version with the pre-defined QPixmaps? If you share the code, i'll have a look at it. Maybe you can optimize the paint method of the big item to only show those items, whose coordinates are within the visible scenerect.

    Joh

  5. #5
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Ok.. I wanted to see how far this could go.. and implemented a low-level GL solution. It's a bit messy.. just wanted to check it out. Prerendering the sequences to big display lists doesn't give a speed boost and introduces problems with empty displaylists, if the gl context runs out of memory (?).

    That's as far as brute force optimization goes, I think. Further optimizations can be achieved by only drawing the visible items or rendering a big pixmap if the detail level drops to a resolution that can be handled. Both together should allow for a smooth user interaction. To see what items are to be drawn you could look into glUnproject.

    Qt Code:
    1. #ifndef MAINGL_H
    2. #define MAINGL_H
    3.  
    4. #include <QtOpenGL>
    5.  
    6. class MainWindow : public QGLWidget
    7. { Q_OBJECT
    8. public:
    9. MainWindow(QWidget *parent = 0,int seq_length = 5000,int num_seq = 80) : QGLWidget(parent)
    10. {
    11. // generate random data to display
    12. data.reserve(num_seq);
    13. QVector<quint8> seq0;
    14. seq0.reserve(seq_length);
    15. for(int j=0;j<seq_length;j++)
    16. {
    17. seq0.push_back( int(rand()/float(RAND_MAX)*4) );
    18. }
    19. data.push_back(seq0);
    20.  
    21. for(int i=1;i<num_seq;i++)
    22. {
    23. QVector<quint8> seq_i;
    24. seq_i.reserve(seq_length);
    25. for(int j=0;j<seq_length;j++)
    26. {
    27. if(rand()/float(RAND_MAX)*20 < 1)
    28. seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
    29. else
    30. seq_i.push_back( data.at(0).at(j) );
    31. }
    32. data.push_back(seq_i);
    33. }
    34. camPos[0] = 0;camPos[1] = num_seq*10;camPos[2] = 2000;
    35. totaldisplaylist = 0;
    36. totaldisplaylistcount = 0;
    37. gldisplist = 0;
    38. }
    39. ~MainWindow()
    40. {
    41. for (quint8 i=0;i < 4;++i) deleteTexture(gltextures[i]);
    42. if (totaldisplaylist) glDeleteLists(totaldisplaylist,totaldisplaylistcount);
    43. if (gldisplist) glDeleteLists(gldisplist,4);
    44. }
    45.  
    46. protected:
    47.  
    48. void initializeGL()
    49. {
    50. // Set up the rendering context, define display lists etc.:
    51. glClearColor(1.0, 1.0, 1.0, 1.0);
    52. glEnable(GL_TEXTURE_2D);
    53. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    54.  
    55. QString alpha = "ACGT";
    56. QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
    57. // Generate 4 consecutive displaylists
    58. gldisplist = glGenLists(4);
    59. // Prepare 4 textures
    60. for (quint8 i=0;i < 4;++i)
    61. {
    62. QChar base_char = alpha.at(i);
    63. QColor color = tile_colors[i];
    64. QPixmap* pmap = new QPixmap(20,20);
    65. textures[i] = pmap;
    66. QPainter painter(pmap);
    67. painter.fillRect(QRectF(0, 0, 20, 20), color);
    68. painter.setFont(QFont("Times",10));
    69. painter.setPen(QColor("black"));
    70. painter.drawText(0, 0, 20, 20,0x0084, QString(base_char));
    71. gltextures[i] = bindTexture(*pmap);
    72. qDebug() << gltextures[i];
    73.  
    74. // compile display list
    75. glNewList(gldisplist+i, GL_COMPILE);
    76. {
    77. glBindTexture(GL_TEXTURE_2D, gltextures[i]);
    78.  
    79. glBegin(GL_QUADS);
    80.  
    81. // Upper right corner
    82. glTexCoord2f(0.0, 1.0);
    83. glVertex3f(0.0, 20, 0.0);
    84.  
    85. // Upper right corner
    86. glTexCoord2f(1.0, 1.0);
    87. glVertex3f(20, 20, 0.0);
    88.  
    89. // Lower right corner
    90. glTexCoord2f(1.0, 0.0);
    91. glVertex3f(20, 0.0, 0.0);
    92.  
    93. // Lower left corner
    94. glTexCoord2f(0.0, 0.0);
    95. glVertex3f(0.0, 0.0, 0.0);
    96. glEnd();
    97. }
    98. glEndList();
    99. }
    100. prerender = false;
    101. if (prerender)
    102. renderGL();
    103. }
    104.  
    105. void resizeGL(int w, int h)
    106. {
    107. // setup viewport, projection etc.:
    108. glMatrixMode(GL_PROJECTION);
    109. glLoadIdentity();
    110. glViewport(0, 0, (GLint)w, (GLint)h);
    111. gluPerspective(70.0, (float)w/(float)h, 0.01f, 100000.0f);
    112. //glOrtho(1,w,1,h,-1,10);
    113. }
    114.  
    115. void renderGL()
    116. {
    117. if (totaldisplaylist) glDeleteLists(totaldisplaylist,totaldisplaylistcount);
    118. totaldisplaylistcount = data.size();
    119. totaldisplaylist = glGenLists(totaldisplaylistcount);
    120. float x_inc = 20;
    121. float y_inc = 20;
    122. for (int i = 0; i < data.size(); i++)
    123. {
    124. glNewList(totaldisplaylist+i, GL_COMPILE);
    125. {
    126. QVector<quint8> seq = data.at(i);
    127. for (int j = 0; j < seq.size(); j++)
    128. {
    129. glCallList(gldisplist+seq.at(j));
    130. glTranslatef(20,0,0);
    131. }
    132. glTranslatef(-x_inc*seq.size(),y_inc,0);
    133. }
    134. glEndList();
    135. }
    136. }
    137.  
    138. void paintGL()
    139. {
    140. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    141. glMatrixMode(GL_MODELVIEW);
    142. glLoadIdentity();
    143. // Setup camera ..
    144. gluLookAt(camPos[0],camPos[1],camPos[2],camPos[0],camPos[1],camPos[2]-500,0,1,0);
    145. if (prerender) {
    146. // draw the scene:
    147. for (int i = 0; i < data.size(); i++)
    148. {
    149. glCallList(totaldisplaylist+i);
    150. }
    151. } else {
    152. float x_inc = 20;
    153. float y_inc = 20;
    154. for (int i = 0; i < data.size(); i++)
    155. {
    156. QVector<quint8> seq = data.at(i);
    157. for (int j = 0; j < seq.size(); j++)
    158. {
    159. glCallList(gldisplist+seq.at(j));
    160. glTranslatef(20,0,0);
    161. }
    162. glTranslatef(-x_inc*seq.size(),y_inc,0);
    163. }
    164. }
    165. }
    166.  
    167. void keyPressEvent(QKeyEvent *event)
    168. {
    169. // CAMERA
    170. if ((event->modifiers() == Qt::NoModifier) || (event->modifiers() == Qt::ShiftModifier))
    171. {
    172. qreal delta = 50;
    173. if (event->modifiers() == Qt::ShiftModifier) delta *= 10;
    174. switch (event->key()) {
    175. case Qt::Key_Left : {camPos[0] -= delta;}; break;
    176. case Qt::Key_A : {camPos[0] -= delta;}; break;
    177. case Qt::Key_Right : {camPos[0] += delta;}; break;
    178. case Qt::Key_D : {camPos[0] += delta;}; break;
    179. case Qt::Key_Down : {camPos[1] += delta;}; break;
    180. case Qt::Key_W : {camPos[1] += delta;}; break;
    181. case Qt::Key_Up : {camPos[1] -= delta;}; break;
    182. case Qt::Key_S : {camPos[1] -= delta;}; break;
    183. case Qt::Key_Q : {camPos[2] -= delta;}; break;
    184. case Qt::Key_E : {camPos[2] += delta;}; break;
    185. }
    186. update();
    187. }
    188. }
    189. private:
    190. // The 4 characters
    191. QPixmap* textures[4];
    192. GLuint gltextures[4];
    193. GLuint gldisplist;
    194. // Each sequence as a displaylist
    195. GLuint totaldisplaylist;
    196. int totaldisplaylistcount;
    197. float camPos[3];
    198. bool prerender;
    199. QVector< QVector<quint8> > data;
    200. };
    201.  
    202. #endif // MAINGL_H
    203.  
    204. -------------------------------
    205.  
    206. #include <QtCore>
    207. #include <QtGui>
    208.  
    209. #include "maingl.h"
    210.  
    211. int main(int argc, char *argv[])
    212. {
    213. QApplication a(argc, argv);
    214.  
    215. MainWindow w;
    216. w.show();
    217. return a.exec();
    218. }
    To copy to clipboard, switch view to plain text mode 
    Hope it helps!

    Johannes

  6. #6
    Join Date
    Feb 2006
    Posts
    8
    Thanks
    2
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Johannes!

    Thanks a lot for your effort! I need time digest all the new stuff (and any serious attempt has to wait after the grant application deadline) but your example makes eager to learn more about GL.

    I got your code compiling on my Ubuntu system but its performance isn't what I expected. I had to reduce the matrix size to something like 30x100 to make it reasonably fast and even then it sometimes used quite a lot of CPU. I suppose that my hardware acceleration works: glxgears gives some 4500 frames in 5 sec and, with my earlier appraoch, adding "graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));" massively improved the performance.

    I wonder if I'm missing something very obvious. This is my project file:

    Qt Code:
    1. QT += opengl
    2. TARGET = qab
    3. TEMPLATE = app
    4. CONFIG += release
    5. HEADERS += maingl.h
    6. SOURCES += main.cpp
    To copy to clipboard, switch view to plain text mode 

    Should I have something more there?

    Thanks!

    Lari

  7. #7
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Lari!

    No, your project file looks good. I was too tired yesterday night. There is a big speed improvement with prerendering. Just set the bool in the code to true. I don't know how I could miss that :-> But it works correctly only up to a seq_lenght of ~1800.

    And if compared to a QGraphicsView solution it doesn't gain much, if anything. I'm puzzled. My graphicsview solution crashes (only in release mode) if I try to increase the seq_length to 1900. Don't know whats wrong. That seems to be the same limit, my low-level solution has, before it starts to mess up. So my guess is, that the graphicsview also prerenders the whole item into a displaylist.. hence its excellent performance!

    BTW: I'm using Qt4.6 on Win7 with an ATI3850,AMD X2 6000+.

    Qt Code:
    1. #ifndef MAIN_H
    2. #define MAIN_H
    3.  
    4. #include <qapplication.h>
    5. #include <qmainwindow.h>
    6. #include <qgraphicsview.h>
    7. #include <qgraphicsscene.h>
    8. #include <qgraphicsitem.h>
    9. #include <QWheelEvent>
    10. #include <QtOpenGL>
    11. #include <qmath.h>
    12. #include <qcolor.h>
    13.  
    14. using namespace std;
    15.  
    16.  
    17. class SeqMap : public QGraphicsItem
    18. {
    19. public:
    20. SeqMap(int seq_length = 1500,int num_seq = 80);
    21. QRectF boundingRect() const{ return QRectF(0, 0, data.at(0).size()*20, data.size()*20); }
    22.  
    23. void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
    24. private:
    25. QPixmap* textures[4];
    26. QVector< QVector<quint8> > data;
    27. };
    28.  
    29.  
    30. class MainWindow : public QMainWindow
    31. {
    32. public:
    33. MainWindow(QWidget *parent = 0);
    34. private:
    35. void wheelEvent(QWheelEvent * event);
    36.  
    37. QGraphicsView *graphicsView;
    38. };
    39.  
    40. /////////////////////
    41.  
    42. SeqMap::SeqMap(int seq_length,int num_seq)
    43. {
    44. // generate random data to display
    45. data.reserve(num_seq);
    46. QVector<quint8> seq0;
    47. seq0.reserve(seq_length);
    48. for(int j=0;j<seq_length;j++)
    49. {
    50. seq0.push_back( int(rand()/float(RAND_MAX)*4) );
    51. }
    52. data.push_back(seq0);
    53.  
    54. for(int i=1;i<num_seq;i++)
    55. {
    56. QVector<quint8> seq_i;
    57. seq_i.reserve(seq_length);
    58. for(int j=0;j<seq_length;j++)
    59. {
    60. if(rand()/float(RAND_MAX)*20 < 1)
    61. seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
    62. else
    63. seq_i.push_back( data.at(0).at(j) );
    64. }
    65. data.push_back(seq_i);
    66. }
    67.  
    68. QString alpha = "ACGT";
    69. QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
    70. // Prepare 4 textures
    71. for (quint8 i=0;i < 4;++i)
    72. {
    73. QChar base_char = alpha.at(i);
    74. QColor color = tile_colors[i];
    75. QPixmap* pmap = new QPixmap(20,20);
    76. textures[i] = pmap;
    77. QPainter painter(pmap);
    78. QBrush b = painter.brush();
    79. painter.fillRect(QRectF(0, 0, 20, 20), color);
    80. painter.setFont(QFont("Times",10));
    81. painter.setPen(QColor("black"));
    82. painter.drawText(0, 0, 20, 20,0x0084, QString(base_char));
    83. }
    84. }
    85.  
    86. void SeqMap::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    87. {
    88. Q_UNUSED(widget);
    89.  
    90. int y_pos = 0;
    91. for (int i = 0; i < data.size(); i++)
    92. {
    93. int x_pos = 0;
    94.  
    95. for (int j = 0; j < data.at(i).size(); j++)
    96. {
    97. int base = data.at(i).at(j);
    98. painter->drawPixmap(x_pos,y_pos,*textures[base]);
    99. x_pos += 20;
    100. }
    101. y_pos += 20;
    102. }
    103. }
    104.  
    105. /////////////////////
    106.  
    107. void MainWindow::wheelEvent(QWheelEvent * e)
    108. {
    109. if ( e->modifiers() == Qt::ControlModifier )
    110. {
    111. int numSteps = ( e->delta() / 8 ) / 15;
    112.  
    113. QMatrix mat = graphicsView->matrix();
    114.  
    115. if ( numSteps > 0 )
    116. mat.scale( numSteps * 1.2, numSteps * 1.2 );
    117. else
    118. mat.scale( -1 / ( numSteps * 1.2 ), -1 / ( numSteps * 1.2 ) );
    119.  
    120. graphicsView->setMatrix(mat);
    121. e->accept();
    122. }
    123. }
    124.  
    125. MainWindow::MainWindow(QWidget *parent) :
    126. QMainWindow(parent)
    127. {
    128.  
    129. // the browser stuff
    130. scene = new QGraphicsScene();
    131. scene->addItem(new SeqMap());
    132.  
    133. graphicsView = new QGraphicsView(this);
    134. graphicsView->setRenderHint(QPainter::Antialiasing, false);
    135. graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
    136. graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
    137. graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    138. graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    139. graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
    140. graphicsView->setScene(scene);
    141. graphicsView->setGeometry(QRect(50, 50, 100, 100));
    142. graphicsView->show();
    143.  
    144. this->setCentralWidget(graphicsView);
    145.  
    146. }
    147.  
    148. #endif // MAIN_H
    149.  
    150. ---------------------------------
    151.  
    152. #include <QtCore>
    153. #include <QtGui>
    154.  
    155. #include "main.h"
    156.  
    157. int main(int argc, char *argv[])
    158. {
    159. QApplication a(argc, argv);
    160.  
    161. MainWindow w;
    162. w.show();
    163. return a.exec();
    164. }
    To copy to clipboard, switch view to plain text mode 
    I'll have to leave this to you. Gotta do my stuff now :->

    Good luck,

    Johannes

  8. #8
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Couldn't leave it :->

    I implemented the two optimizations I mentioned before:

    Qt Code:
    1. #ifndef MAIN_H
    2. #define MAIN_H
    3.  
    4. #include <qapplication.h>
    5. #include <qmainwindow.h>
    6. #include <qgraphicsview.h>
    7. #include <qgraphicsscene.h>
    8. #include <qgraphicsitem.h>
    9. #include <QWheelEvent>
    10. #include <QtOpenGL>
    11. #include <qmath.h>
    12. #include <qcolor.h>
    13.  
    14. using namespace std;
    15.  
    16.  
    17. class SeqMap : public QGraphicsItem
    18. {
    19. public:
    20. SeqMap(int seq_length = 20000,int num_seq = 80);
    21. QRectF boundingRect() const{ return QRectF(0, 0, data.at(0).size()*20, data.size()*20); }
    22.  
    23. int seq_length() {return data.at(0).size();}
    24. int num_seq() {return data.size();}
    25.  
    26. void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
    27. private:
    28. QPixmap* textures[4];
    29. QVector< QVector<quint8> > data;
    30. };
    31.  
    32.  
    33. class MainWindow : public QMainWindow
    34. {
    35. public:
    36. MainWindow(QWidget *parent = 0);
    37. private:
    38. void wheelEvent(QWheelEvent * event);
    39.  
    40. double scale;
    41. SeqMap* seqmap;
    42. QGraphicsView *graphicsView;
    43. };
    44.  
    45. /////////////////////
    46.  
    47. SeqMap::SeqMap(int seq_length,int num_seq)
    48. {
    49. // Need this for exposedRect to be initialized!
    50. setFlag(QGraphicsItem::ItemUsesExtendedStyleOption,true);
    51. // generate random data to display
    52. data.reserve(num_seq);
    53. QVector<quint8> seq0;
    54. seq0.reserve(seq_length);
    55. for(int j=0;j<seq_length;j++)
    56. {
    57. seq0.push_back( int(rand()/float(RAND_MAX)*4) );
    58. }
    59. data.push_back(seq0);
    60.  
    61. for(int i=1;i<num_seq;i++)
    62. {
    63. QVector<quint8> seq_i;
    64. seq_i.reserve(seq_length);
    65. for(int j=0;j<seq_length;j++)
    66. {
    67. if(rand()/float(RAND_MAX)*20 < 1)
    68. seq_i.push_back( int(rand()/float(RAND_MAX)*4) );
    69. else
    70. seq_i.push_back( data.at(0).at(j) );
    71. }
    72. data.push_back(seq_i);
    73. }
    74.  
    75. QString alpha = "ACGT";
    76. QColor tile_colors[] = { QColor("blue"), QColor("green"), QColor("yellow"), QColor("red") };
    77. // Prepare 4 textures
    78. for (quint8 i=0;i < 4;++i)
    79. {
    80. QChar base_char = alpha.at(i);
    81. QColor color = tile_colors[i];
    82. QPixmap* pmap = new QPixmap(20,20);
    83. textures[i] = pmap;
    84. QPainter painter(pmap);
    85. QBrush b = painter.brush();
    86. painter.fillRect(QRectF(0, 0, 20, 20), color);
    87. painter.setFont(QFont("Times",10));
    88. painter.setPen(QColor("black"));
    89. painter.drawText(0, 0, 20, 20,0x0084, QString(base_char));
    90. }
    91. }
    92.  
    93. void SeqMap::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    94. {
    95. Q_UNUSED(widget);
    96. // Use the exposedRect
    97. int start_x = max(0,(int)option->exposedRect.left()/20-1);
    98. int end_x = min(data.at(0).size(),(int)option->exposedRect.right()/20+1);
    99. int start_y = max(0,(int)option->exposedRect.top()/20-1);
    100. int end_y = min(data.size(),(int)option->exposedRect.bottom()/20+1);
    101.  
    102. int y_pos = 0;
    103. for (int i = start_y; i < end_y; i++)
    104. {
    105. int x_pos = start_x*20;
    106.  
    107. for (int j = start_x; j < end_x; j++)
    108. {
    109. quint8 base = qMin((quint8)3,data.at(i).at(j));
    110. painter->drawPixmap(x_pos,y_pos,*textures[base]);
    111. x_pos += 20;
    112. }
    113. y_pos += 20;
    114. }
    115. }
    116.  
    117. /////////////////////
    118.  
    119. void MainWindow::wheelEvent(QWheelEvent * e)
    120. {
    121. if ( e->modifiers() == Qt::ControlModifier )
    122. {
    123. int numSteps = ( e->delta() / 8 ) / 15;
    124.  
    125. double tempscale = 1;
    126. if ( numSteps > 0 )
    127. tempscale *= numSteps*1.2;
    128. else
    129. tempscale *= -1/(numSteps*1.2);
    130. scale *= tempscale;
    131.  
    132. QMatrix mat = graphicsView->matrix();
    133. mat.scale(tempscale,tempscale);
    134. graphicsView->setMatrix(mat);
    135. e->accept();
    136. }
    137. if (scale < 0.10)
    138. seqmap->setCacheMode(QGraphicsItem::ItemCoordinateCache,QSize(min(seqmap->seq_length(),8000),min(seqmap->num_seq(),2000)));
    139. else
    140. seqmap->setCacheMode(QGraphicsItem::NoCache);
    141. }
    142.  
    143. MainWindow::MainWindow(QWidget *parent) :
    144. QMainWindow(parent)
    145. {
    146. QPixmapCache::setCacheLimit(100000);
    147. scale = 1.0;
    148. // the browser stuff
    149. scene = new QGraphicsScene();
    150. seqmap = new SeqMap();
    151. scene->addItem(seqmap);
    152.  
    153. graphicsView = new QGraphicsView(this);
    154. graphicsView->setRenderHint(QPainter::Antialiasing, false);
    155. graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
    156. graphicsView->setOptimizationFlags(QGraphicsView::DontSavePainterState);
    157. graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    158. graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    159. graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
    160. graphicsView->setScene(scene);
    161. graphicsView->setGeometry(QRect(50, 50, 100, 100));
    162. graphicsView->show();
    163.  
    164. this->setCentralWidget(graphicsView);
    165.  
    166. }
    167.  
    168. #endif // MAIN_H
    To copy to clipboard, switch view to plain text mode 

    Good luck!

    Johannes
    Last edited by JohannesMunk; 20th April 2010 at 13:07.

  9. The following user says thank you to JohannesMunk for this useful post:

    lari (21st April 2010)

  10. #9
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    AAAH! Origin to both bugs is your random data.. there is of course sometimes a 4 inside!!

    int(rand()/float(RAND_MAX)*4).

    As the random generator is deterministic without initialization.. this always occured at the same value..

    quick fix: quint8 base = qMin((quint8)3,data.at(i).at(j)); in the paint method

    So now everything works.. and blazing fast :->

    Good luck for your project!

    Johannes

  11. #10
    Join Date
    Feb 2006
    Posts
    8
    Thanks
    2
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Thanks a lot! This is a good start for me start experimenting!

  12. #11
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    I updated the code above once more. It supports bigger cache pixmaps now. You got to adapt this to your needs though!

    Johannes

    BTW: If you don't mind, you could use the forums thank button :->

  13. The following user says thank you to JohannesMunk for this useful post:

    lari (21st April 2010)

  14. #12
    Join Date
    Feb 2006
    Posts
    8
    Thanks
    2
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Johannes,

    You are righth, it is blazing fast for moving around and zooming in/out on moderate zoom levels. However, my old hardware (ATI Radeon Mobility X1400), or the Linux drivers for it, may not be good enough to zoom out to see the whole matrix.

    This is a great piece of code but also so advanced (to me at least) that I need to do some studying to be able to continue from this. I hope that this leads to a real application one day: I've dreamed of a project where I could learn some nice Qt programming but I also feel that the project has to be related to my research work to be justified. This is exactly that!

    Lari

    P.S. Sorry about the bug! Wasn't first time that I got rand() limits wrong...

  15. #13
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Thanks
    17
    Thanked 90 Times in 88 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QGraphicsScene with lots of static items

    Hi Lari!

    If your hardware is too slow, just reduce the maximum resolution of the cached item in line 39. The last parameter is the size of the cache for that item. But if you set it below the sequence lenght, you won't see every 'step' any more, though! You can also vary the threshold value in line 38, to change when the two display modes are switched.

    What is more advanced here, than in your code? If you have any questions about it, you are welcome to ask!

    Don't worry about the bug - happens to everyone. Funny was, what wrong explanation I found for the misbehaviour :->

    Let me know how your project advances. I am interested in were you go with it.

    Happy coding,

    Johannes

Similar Threads

  1. Position of Items in QGraphicsScene/QGraphicsView
    By StefanK2 in forum Qt Programming
    Replies: 11
    Last Post: 7th July 2009, 14:04
  2. Custom items selection in qgraphicsscene
    By yonnak in forum Qt Programming
    Replies: 7
    Last Post: 28th March 2009, 11:32
  3. How could I save Items on a QGraphicsScene?
    By pinkfrog in forum Qt Programming
    Replies: 2
    Last Post: 9th January 2009, 05:03
  4. Adding QGraphicsProxyWidget items into QGraphicsScene
    By yagabey in forum Qt Programming
    Replies: 3
    Last Post: 21st November 2008, 06:33
  5. speed of setdata - lots of items in treeview
    By Big Duck in forum Qt Programming
    Replies: 4
    Last Post: 6th July 2006, 12:53

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.