Example screenshot showing the text "This is an example text. It will be scrolled horizontally.". Note the alpha blending at both sides.
The code:
scrolltext.h:
#ifndef SCROLLTEXT_H #define SCROLLTEXT_H #include <QWidget> #include <QStaticText> #include <QTimer> class ScrollText : public QWidget { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(QString separator READ separator WRITE setSeparator) public: explicit ScrollText(QWidget *parent = 0); public slots: QString text() const; void setText(QString text); QString separator() const; void setSeparator(QString separator); protected: virtual void paintEvent(QPaintEvent *); virtual void resizeEvent(QResizeEvent *); private: void updateText(); QString _text; QString _separator; QStaticText staticText; int singleTextWidth; QSize wholeTextSize; int leftMargin; bool scrollEnabled; int scrollPos; QImage alphaChannel; QImage buffer; QTimer timer; private slots: virtual void timer_timeout(); }; #endif // SCROLLTEXT_H
scrolltext.cpp:
#include "scrolltext.h" #include <QPainter> ScrollText::ScrollText(QWidget *parent) : QWidget(parent), scrollPos(0) { staticText.setTextFormat(Qt::PlainText); setFixedHeight(fontMetrics().height()); leftMargin = height() / 3; setSeparator(" --- "); connect(&timer, SIGNAL(timeout()), this, SLOT(timer_timeout())); timer.setInterval(50); } QString ScrollText::text() const { return _text; } void ScrollText::setText(QString text) { _text = text; updateText(); update(); } QString ScrollText::separator() const { return _separator; } void ScrollText::setSeparator(QString separator) { _separator = separator; updateText(); update(); } void ScrollText::updateText() { timer.stop(); singleTextWidth = fontMetrics().width(_text); scrollEnabled = (singleTextWidth > width() - leftMargin); if(scrollEnabled) { scrollPos = -64; staticText.setText(_text + _separator); timer.start(); } else staticText.setText(_text); staticText.prepare(QTransform(), font()); wholeTextSize = QSize(fontMetrics().width(staticText.text()), fontMetrics().height()); } void ScrollText::paintEvent(QPaintEvent*) { QPainter p(this); if(scrollEnabled) { buffer.fill(qRgba(0, 0, 0, 0)); QPainter pb(&buffer); pb.setPen(p.pen()); pb.setFont(p.font()); int x = qMin(-scrollPos, 0) + leftMargin; while(x < width()) { pb.drawStaticText(QPointF(x, (height() - wholeTextSize.height()) / 2) + QPoint(2, 2), staticText); x += wholeTextSize.width(); } //Apply Alpha Channel pb.setCompositionMode(QPainter::CompositionMode_DestinationIn); pb.setClipRect(width() - 15, 0, 15, height()); pb.drawImage(0, 0, alphaChannel); pb.setClipRect(0, 0, 15, height()); //initial situation: don't apply alpha channel in the left half of the image at all; apply it more and more until scrollPos gets positive if(scrollPos < 0) pb.setOpacity((qreal)(qMax(-8, scrollPos) + 8) / 8.0); pb.drawImage(0, 0, alphaChannel); //pb.end(); p.drawImage(0, 0, buffer); } else { p.drawStaticText(QPointF(leftMargin, (height() - wholeTextSize.height()) / 2), staticText); } } void ScrollText::resizeEvent(QResizeEvent*) { //When the widget is resized, we need to update the alpha channel. alphaChannel = QImage(size(), QImage::Format_ARGB32_Premultiplied); buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied); //Create Alpha Channel: if(width() > 64) { //create first scanline QRgb* scanline1 = (QRgb*)alphaChannel.scanLine(0); for(int x = 1; x < 16; ++x) scanline1[x - 1] = scanline1[width() - x] = qRgba(0, 0, 0, x << 4); for(int x = 15; x < width() - 15; ++x) scanline1[x] = qRgb(0, 0, 0); //copy scanline to the other ones for(int y = 1; y < height(); ++y) memcpy(alphaChannel.scanLine(y), (uchar*)scanline1, width() * 4); } else alphaChannel.fill(qRgb(0, 0, 0)); //Update scrolling state bool newScrollEnabled = (singleTextWidth > width() - leftMargin); if(newScrollEnabled != scrollEnabled) updateText(); } void ScrollText::timer_timeout() { scrollPos = (scrollPos + 2) % wholeTextSize.width(); update(); }
Something like the following should work. The padding is hard-coded at 25, which is what is sounded like you wanted. If you wanted the label to always be a certain size, you could use something like
QString::leftJustified
.
class MarqueeLabel : public QLabel { public: explicit MarqueeLabel(const QString &text) : QLabel(text), pos_(0) { QString pad(25, ' '); actual_text_ = text + pad; startTimer(100); } protected: void timerEvent(QTimerEvent *) { pos_ = ++pos_ % actual_text_.length(); setText(actual_text_.mid(pos_).append(actual_text_.left(pos_))); } private: QString actual_text_; int pos_; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); MarqueeLabel lbl("WidgetMarqueeLabel"); lbl.show(); return a.exec(); }