Results 1 to 8 of 8

Thread: Using QAbstractItemDelegate to display a TGA from a database

  1. #1
    Join Date
    Aug 2009
    Posts
    56
    Thanks
    14
    Thanked 1 Time in 1 Post

    Default Using QAbstractItemDelegate to display a TGA from a database

    I have the following code that should display any column that is a byte array as a 320x200 tga image. But the cells in the QTTableView are grey rather than the image. Also they don't size to 320x200, as the sizeHint() function is never called.

    Any idea what I'm doing wrong?

    Qt Code:
    1. #ifndef __IMAGE_DELEGATE_H_
    2. #define __IMAGE_DELEGATE_H_
    3.  
    4. #include <QItemDelegate>
    5.  
    6. class SQLQueryItemDelegate : public QItemDelegate
    7. {
    8. Q_OBJECT
    9. public:
    10. SQLQueryItemDelegate(QWidget *parent = 0) : QItemDelegate(parent) {}
    11.  
    12. virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
    13. const QModelIndex &index) const;
    14.  
    15. virtual QSize sizeHint(const QStyleOptionViewItem &option,
    16. const QModelIndex &index) const;
    17. };
    18.  
    19. #endif
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "SQLQueryItemDelegate.h"
    2. #include <QPainter>
    3.  
    4. void SQLQueryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
    5. const QModelIndex &index) const
    6. {
    7. const QVariant &v = index.data();
    8. if (v.type()==QVariant::ByteArray)
    9. {
    10. const QByteArray ba = v.toByteArray();
    11. QImage siImage(320,200,QImage::Format_ARGB32);
    12. siImage.fromData((const uchar*) ba.data(), ba.size());
    13. QPixmap siPixmap;
    14. siPixmap = QPixmap(320,200);
    15. siPixmap.fromImage(siImage,Qt::AutoColor);
    16. painter->drawPixmap(option.rect, siPixmap);
    17.  
    18. }
    19. else
    20. {
    21. QItemDelegate::paint(painter,option,index);
    22. }
    23. }
    24.  
    25. QSize SQLQueryItemDelegate::sizeHint(const QStyleOptionViewItem &option,
    26. const QModelIndex &index) const
    27. {
    28. const QVariant &v = index.data();
    29. if (v.type()==QVariant::ByteArray)
    30. {
    31. return QSize(320,200);
    32. }
    33. else
    34. {
    35. return QItemDelegate::sizeHint(option,index);
    36. }
    37. }
    To copy to clipboard, switch view to plain text mode 

    Thanks, everyone is very helpful here.

  2. #2
    Join Date
    Aug 2009
    Posts
    56
    Thanks
    14
    Thanked 1 Time in 1 Post

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    I figured it out. Maybe not all these steps are needed, but it works

    Qt Code:
    1. QByteArray ba = v.toByteArray();
    2. QBuffer buffer;
    3. buffer.setBuffer(&ba);
    4. buffer.open(QIODevice.ReadOnly);
    5. qir.setDevice(&buffer);
    6. QImage image;
    7. qir.read(&image);
    8. QPixmap pixmap = QPixmap::fromImage(image);
    9. painter->drawPixmap(option.rect, pixmap);
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Aug 2009
    Posts
    56
    Thanks
    14
    Thanked 1 Time in 1 Post

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    I found that it can't load the images fast enough in some cases. I drag the scrollbar to view through the rows, but the scrollbar lags behind the mouse cursor. Is there a way to defer paint events for say 100 milliseconds, so if you're just skipping by that row it doesn't need to draw?

  4. #4
    Join Date
    Feb 2008
    Posts
    98
    Thanks
    2
    Thanked 24 Times in 24 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    You may paint to cell blank when you don't have the data, then store the index in an array and use a timer with setSingleShot(true) and the interval you want. Connect the timeout() signal to a slot where you call view->update(index) for all the indexes that need to be repainted.

    Qt Code:
    1. class SQLQueryItemDelegate : public QStyledItemDelegate
    2. {
    3. ...
    4. signals:
    5. void paintingDeferred(const QModelIndex& index);
    6. ...
    7. };
    8.  
    9. class SQLQueryDeferredPainter : public QObject
    10. {
    11. Q_OBJECT
    12.  
    13. public:
    14. SQLQueryDeferredPainter(QAbstractItemView *view, SQLQueryItemDelegate *delegate, QObject *parent);
    15.  
    16. protected slots:
    17. void paintLater(const QModelIndex& index);
    18. void paintPendingIndexes();
    19.  
    20. protected:
    21. QModelIndexList m_indexes;
    22. QTimer m_timer;
    23. };
    24.  
    25. SQLQueryDeferredPainter::SQLQueryDeferredPainter(QAbstractItemView *view, SQLQueryItemDelegate *delegate, QObject *parent)
    26. : QObject(parent)
    27. {
    28. m_view = view;
    29.  
    30. connect(delegate, SIGNAL(paintingDeferred(const QModelIndex&)),
    31. this, SLOT(paintLater(const QModelIndex&)));
    32.  
    33. m_timer.setSingleShot(true);
    34. m_timer.setInterval(100);
    35. connect(&m_timer, SIGNAL(timeout()),
    36. this, SLOT(paintPendingIndexes()));
    37. }
    38.  
    39. void SQLQueryDeferredPainter::paintLater(const QModelIndex& index)
    40. {
    41. m_indexes.append(index);
    42. m_timer.start();
    43. }
    44.  
    45. void SQLQueryDeferredPainter::paintPendingIndexes()
    46. {
    47. foreach(const QModelIndex& index, m_indexes)
    48. m_view->update(index);
    49.  
    50. m_indexes.clear();
    51. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by victor.fernandez; 28th August 2009 at 08:56. Reason: added example

  5. The following user says thank you to victor.fernandez for this useful post:

    rakkar (28th August 2009)

  6. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    Don't load the images on every refresh. Load them once and then store in a pixmap cache or even subclass your model and make it return the images directly as the decoration role for its indexes.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. The following user says thank you to wysota for this useful post:

    rakkar (28th August 2009)

  8. #6
    Join Date
    Aug 2009
    Posts
    56
    Thanks
    14
    Thanked 1 Time in 1 Post

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    I tried the deferred loading but it didn't look good while scrolling.

    I'll load images in a thread. It will load images around the current view automatically. If you scroll, it will add images to load in a fixed-size buffer. That way, if you scroll fast, the buffer will overflow and you won't load images you won't see anyway.

  9. #7
    Join Date
    Aug 2009
    Posts
    56
    Thanks
    14
    Thanked 1 Time in 1 Post

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    Actually, using a cache increased the performance enough I can use it. Here's the code

    Qt Code:
    1. #ifndef __BYTE_ARRAY_AS_IMAGE_ITEM_DELEGATE_H_
    2. #define __BYTE_ARRAY_AS_IMAGE_ITEM_DELEGATE_H_
    3.  
    4. #include <QItemDelegate>
    5. #include <QTimer>
    6.  
    7. class ModelIndicesDeferredPainter;
    8.  
    9. // If an item is a byte array, wait 100 milliseconds, then load it as an image if possible.
    10. class ByteArrayAsImageItemDelegate : public QItemDelegate
    11. {
    12. Q_OBJECT
    13. public:
    14. ByteArrayAsImageItemDelegate(QWidget *parent = 0) : QItemDelegate(parent) {}
    15.  
    16. virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
    17. const QModelIndex &index) const;
    18.  
    19. // This is needed because you can't emit events from paint() since paint() is const
    20. void SetDeferredPainter(ModelIndicesDeferredPainter *df) {deferredPainter=df;}
    21.  
    22. signals:
    23. void paintingDeferred(const QModelIndex& index);
    24.  
    25. protected:
    26. ModelIndicesDeferredPainter *deferredPainter;
    27. };
    28.  
    29. class ModelIndicesDeferredPainter : public QObject
    30. {
    31. Q_OBJECT
    32.  
    33. public:
    34. ModelIndicesDeferredPainter(QAbstractItemView *view, QObject *parent);
    35. bool paintLater(const QModelIndex& index);
    36.  
    37. protected slots:
    38. void paintPendingIndexes();
    39.  
    40. protected:
    41. QModelIndexList indicesToPaint;
    42. QAbstractItemView *storedItemView;
    43.  
    44. // Don't immediately load images. This way, if an image immediately goes out of viewable area, it is not drawn
    45. QTimer timer;
    46.  
    47. // This is needed so we know not to just call paintLater() again from ByteArrayAsImageItemDelegate
    48. bool isPaintingLater;
    49. };
    50.  
    51.  
    52. #endif
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include "ByteArrayAsImageItemDelegate.h"
    2. #include <QPainter>
    3. #include <QBuffer>
    4. #include <QImageReader>
    5. #include <QAbstractItemView>
    6. #include <QPixmapCache>
    7.  
    8. // From RakNet
    9. #include "SuperFastHash.h"
    10.  
    11. void ByteArrayAsImageItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
    12. const QModelIndex &index) const
    13. {
    14. const QVariant &v = index.data();
    15. if (v.type()==QVariant::ByteArray)
    16. {
    17. QByteArray ba = v.toByteArray();
    18. unsigned int hash = SuperFastHash(ba.data(),ba.length());
    19. QString hashKey;
    20. // Safer collision code commented out, in case I need it
    21. //hashKey.sprintf("%i%i%i",index.row(),index.column(),hash);
    22. // Faster, in case images are duplicated
    23. hashKey.sprintf("%i",hash);
    24. QPixmap pixmap;
    25. bool foundPixmap = QPixmapCache::find(hashKey, pixmap);
    26. bool paintLater;
    27. if (foundPixmap==false)
    28. {
    29. paintLater=deferredPainter->paintLater(index);
    30. if (paintLater==false)
    31. {
    32. // Load pixmap
    33. QBuffer buffer;
    34. buffer.setBuffer(&ba);
    35. buffer.open(QIODevice::ReadOnly);
    36. qir.setDevice(&buffer);
    37. QImage image;
    38. if (qir.read(&image))
    39. {
    40. pixmap = QPixmap::fromImage(image);
    41.  
    42. // Save to cache
    43. QPixmapCache::insert(hashKey,pixmap);
    44. }
    45. else
    46. {
    47. // Not an image?
    48. QItemDelegate::paint(painter,option,index);
    49. return;
    50. }
    51. }
    52. }
    53.  
    54. if (foundPixmap==true || paintLater==false)
    55. {
    56. // Paint
    57. QSize imageSize = pixmap.size();
    58. QRect drawRect;
    59. float scaleWidth, scaleHeight;
    60. float drawWidth, drawHeight;
    61. scaleWidth = (float) imageSize.width() / (float)option.rect.width();
    62. scaleHeight = (float)imageSize.height() / (float)option.rect.height();
    63. // Downscale by the larger of the two proportions
    64. if (scaleHeight > scaleWidth)
    65. {
    66. drawWidth=(float)imageSize.width()/scaleHeight;
    67. drawHeight=(float)imageSize.height()/scaleHeight;
    68. }
    69. else
    70. {
    71. drawWidth=(float)imageSize.width()/scaleWidth;
    72. drawHeight=(float)imageSize.height()/scaleWidth;
    73. }
    74.  
    75. float centerX = (float)option.rect.left() + (float)option.rect.width()/2.0;
    76. float centerY = (float)option.rect.top() + (float)option.rect.height()/2.0;
    77. drawRect.setLeft(centerX-drawWidth/2.0);
    78. drawRect.setRight(centerX+drawWidth/2.0);
    79. drawRect.setTop(centerY-drawHeight/2.0);
    80. drawRect.setBottom(centerY+drawHeight/2.0);
    81. painter->drawPixmap(drawRect, pixmap);
    82. }
    83.  
    84. }
    85. else
    86. {
    87. QItemDelegate::paint(painter,option,index);
    88. }
    89. }
    90. ModelIndicesDeferredPainter::ModelIndicesDeferredPainter(QAbstractItemView *view, QObject *parent)
    91. : QObject(parent)
    92. {
    93. storedItemView = view;
    94.  
    95. timer.setSingleShot(true);
    96. timer.setInterval(100);
    97. connect(&timer, SIGNAL(timeout()),
    98. this, SLOT(paintPendingIndexes()));
    99. isPaintingLater=false;
    100. }
    101.  
    102. bool ModelIndicesDeferredPainter::paintLater(const QModelIndex& index)
    103. {
    104. if (isPaintingLater)
    105. return false;
    106.  
    107. if (indicesToPaint.contains(index)==false)
    108. {
    109. indicesToPaint.append(index);
    110. timer.start();
    111. }
    112.  
    113. return true;
    114. }
    115.  
    116. void ModelIndicesDeferredPainter::paintPendingIndexes()
    117. {
    118. // This flag is needed so ByteArrayAsImageItemDelegate::paint does not just call paintLater again()
    119. isPaintingLater=true;
    120.  
    121. foreach(const QModelIndex& index, indicesToPaint)
    122. storedItemView->update(index);
    123. storedItemView->repaint();
    124.  
    125. isPaintingLater=false;
    126.  
    127. indicesToPaint.clear();
    128. }
    To copy to clipboard, switch view to plain text mode 

  10. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Using QAbstractItemDelegate to display a TGA from a database

    Why are you deferring anything? Not that I see what you are deferring...
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Threads and database connection
    By probine in forum Qt Programming
    Replies: 9
    Last Post: 7th August 2013, 09:30
  2. Regarding Database Display through user interface
    By Tavit in forum Qt Programming
    Replies: 1
    Last Post: 1st April 2008, 11:32
  3. Multiple database connections
    By cyberboy in forum Qt Programming
    Replies: 3
    Last Post: 30th March 2008, 17:56
  4. Display only PNG image on desktop
    By durbrak in forum Qt Programming
    Replies: 32
    Last Post: 15th March 2008, 22:55
  5. Database Master-Detail Entry Form
    By Phan Sin Tian in forum Newbie
    Replies: 4
    Last Post: 3rd February 2008, 15:31

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.