views:

289

answers:

4

Hello,

I have implemented a marquee text widget using Qt4. I painted the text content onto a pixmap first. And then paint a portion of this pixmap onto a paint device by calling painter.drawTiledPixmap(offsetX, offsetY, myPixmap)

My Imagination is that, Qt will fill the whole marquee text rectangle with the content from myPixmap.

Is there a ever faster way, to shift all existing content to left by 1px and than fill the newly exposed 1px wide and N-px high area with the content from myPixmap?

A: 

Greetings,

one possibility to achieve this would be to:

  1. Create a QGraphicsScene + View and put the pixmap on that twice (as QGraphicsPixmapItem), so they are right next to each other.
  2. Size the view to fit the size of the (one) pixmap.
  3. Then, instead of repainting the pixmap, you simply reposition the view's viewport, moving from one pixmap to the next.
  4. Jump back at the end to create the loop.

This may or may not be faster (in terms of performance) - I have not tested it. But may be worth a try, if only for the sake of experiment.

Robin
thanks. but QGraphicsScene is float coordicate based, not integer based. is this approach faster?
stanleyxu2005
I think, what matters is not the usage of qreal vs. int, but how the drawing is handled internally. My guess is that moving the view's viewport is much more optimized than actually drawing the pixmap again and again for every single frame. But as I said: I haven't made any tests or benchmarks with this. If you try it, please tell me your results, will you?
Robin
A: 

Your approach is probably one of the fastest one since you use low level painting methods. You can implement an intermediate approach between low level painting and the QGraphicsScene option : using a scroll area containing a label.

Here is a sample of code that create a new scroll area containing a text label. You may scroll the label automatically using a QTimer to trigger the scrolling effect, that gives you a nice marquee widget.

QScrollArea *scrollArea = new QScrollArea();

// ensure that scroll bars never show
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

QLabel *label = new QLabel("your scrolling text");

// resize the scroll area : 50px length and an height equals to its content height.
scrollArea->resize(50, label->size().height());
scrollArea->setWidget(label);
label->show(); // optionnal if the scroll area is not yet visible

The text label inside the scroll area can be moved from left to right by one pixel using the QScrollArea::scrollContentsBy(int dx, int dy) with a dx parameter equals to -1.

Lohrun
A: 

Well. This is a trick I used to do with slower hardware back in the old days. Basically, the image buffer is allocated twice as wide as needed with 1 extra line at the beginning. Build the image to the left of the buffer. Then draw the image repeatedly with the buffer advancing 1 pixel at a time in the buffer.

int w = 200;
int h = 100;
int rowBytes = w * sizeof(QRgb) * 2; // line buffer is twice as the width
QByteArray buffer(rowBytes * (h + 1), 0xFF); // 1 more line than the height
uchar * p = (uchar*)buffer.data() + rowBytes; // start drawing the image content at 2nd line
QImage image(p, w, h, rowBytes, QImage::Format_RGB32); // 1st line is used as the padding at the start of scroll
image.fill(qRgb(255, 0, 0)); // well. do something to the image

p = image.bits() - rowBytes / 2; //  start scrolling at the middle of the 1st (blank) line
for(int i=0;i<w;++i, p+=sizeof(QRgb)) {
    QImage  scroll(p, w, h, rowBytes, QImage::Format_RGB32); // scrool 1 pixel at a time
    scroll.save(QString("%1.png").arg(i));
}

I am not sure this will be any faster than just change the offset of the image and draw it strait. The hardware today is really powerful which renders a lot of old tricks useless. But it's fun to play obscure tricks. :)

Stephen Chu
A: 

Why not just do it on a pixel by pixel basis? Due to the way caches work writing the pixel to the one before it all the way until you get to the end. Then you can fill the final column by reading from your other image.

Its then pretty easy to SIMD optimise it as well; though you start getting into per-platform optimisations at this point.

Goz