PDA

View Full Version : Create a marquee with QGraphicsScene



plitex
31st May 2013, 11:55
Hi all,

I'm looking to create a marquee like the ones we could watch on TV, normally horizontal scrolls. What I'm having is a lot of flickering on the animation, and I would like to have other opinions because I'm a newbie on Qt Graphics.

If I resize the window, the animation stops, is there a way to avoid that? I don't know if there is a way to have a thread for the scene.

Here is the main code I'm using, but you can find attached all the project.



Item::Item(QGraphicsItem * parent)
: QGraphicsItem(parent)
{
setCacheMode(DeviceCoordinateCache);
_boundingRect = QRectF(0, 0, 960, 220);
_animationSpeed = 0.5;
}

QRectF Item::boundingRect() const
{
return _boundingRect;
}

void Item::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
painter->setBrush(Qt::yellow);
painter->drawRoundedRect(2, 2, 84, 84, 4, 4);
painter->setBrush(QColor(50,50,50));
painter->drawRoundedRect(90, 2, 84, 84, 4, 4);
painter->drawRoundedRect(176, 2, 534, 84, 4, 4);
painter->drawRoundedRect(712, 2, 245, 84, 4, 4);
}

void Item::advance(int phase)
{
if (phase == 1)
{
moveBy(-(_animationSpeed), 0.0);
}
}

void Item::setAnimationSpeed(qreal value)
{
_animationSpeed = value;
}




MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

QGraphicsScene *scene = new QGraphicsScene();
scene->setBackgroundBrush(Qt::black);

ui->graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
ui->graphicsView->setScene(scene);
ui->graphicsView->setSceneRect(0,0,960,230);

for (int i = 0; i < 50; i++)
{
Item *item = new Item();
item->setPos(item->boundingRect().width() * i, 0);
item->setAnimationSpeed(ui->horizontalSlider->value() / 10.0);
scene->addItem(item);
_items.append(item);
}

QTimer *timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(timer_timeout()));
timer->start(1);

_elapsedTimer = new QElapsedTimer();
_elapsedTimer->start();
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::timer_timeout()
{
if (_elapsedTimer->hasExpired(8))
{
_elapsedTimer->start();
ui->graphicsView->scene()->advance();
}
}

void MainWindow::on_horizontalSlider_valueChanged(int value)
{
foreach(Item *i, _items)
i->setAnimationSpeed(value / 10.0);
}

d_stranz
31st May 2013, 20:17
Why are you using a 1ms timeout for your main QTimer? That is much too fast for any practical purposes. Typical video is 30 fps, which translates to a refresh period of 33 ms. Even at 33 ms, that is still too fast for your brain to see individual frames. If you item doesn't need to move that fast, then set a more realistic timeout.

What is your marquee being drawn on top of? Is it a mostly static image or is it a video? One way to avoid flicker is to avoid the need to refresh anything except the immediate region being drawn or to set a cache on the background image so it doesn't actually paint but simply bitblts the areas that are changed by the moving item.

plitex
4th June 2013, 15:30
Hi,

I've tested with several intervals, but 16 or 33 are showing unacceptable flickering... I really don't know why is so unstable. I changed the code to use a QGraphicsItemAnimation and QTimeLine, and it looks more stable, but only with 1 ms interval is running smoothly.

I have no background, how should I configure the background cache?

pkj
4th June 2013, 16:53
Have you tried using QGL::DoubleBuffer?

plitex
5th June 2013, 11:51
Yes, I did it.

I also tried to do a simple animation with Qt Quick because some people tell me it's optimized for smooth transitions, but I get also a lot of "jumps" on the animation. Here is the code I used:



import QtQuick 1.1

Rectangle {
id: window
width: 960
height: 360
color: "#000000"

states : State {
name: "left"
PropertyChanges { target: item1; x: -962 }
}

MouseArea {
id: mouseArea
onClicked: if (window.state == '') window.state = "left"; else window.state = ''
anchors.fill: parent
anchors.margins: -5 // Make MouseArea bigger than the rectangle, itself
}

transitions: Transition {
NumberAnimation { properties: "x"; easing.type: Easing.Linear; duration: 4000 }
}

Item {
id: item1
x: 0
y: 274
width: 1923
height: 86

Item {
id: pos1
x: 0
y: 0
width: 960
height: 86
smooth: false
clip: false

Rectangle {
id: rectangle3
x: 0
y: 0
width: 960
height: 41
color: "#424242"
radius: 5
Text {
id: text3
x: 0
y: 0
width: 791
height: 41
color: "#ffffff"
text: qsTr("Some Text")
font.pixelSize: 40
font.family: "Helvetica"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}

Rectangle {
id: rectangle4
x: 0
y: 45
width: 960
height: 41
color: "#424242"
radius: 5
Text {
id: text4
x: 0
y: 0
width: 791
height: 41
color: "#ffffff"
text: qsTr("Some Text")
font.family: "Helvetica"
font.pixelSize: 40
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}

Item {
id: pos2
x: 962
y: 0
width: 959
height: 86
clip: false
smooth: false

Rectangle {
id: rectangle7
x: 0
y: 0
width: 960
height: 41
color: "#424242"
radius: 5
Text {
id: text7
x: 0
y: 0
width: 960
height: 41
color: "#ffffff"
text: qsTr("Some other text")
font.family: "Helvetica"
font.pixelSize: 40
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}

Rectangle {
id: rectangle8
x: 0
y: 45
width: 960
height: 41
color: "#424242"
radius: 5
Text {
id: text8
x: 0
y: 0
width: 960
height: 41
color: "#ffffff"
text: qsTr("Some other text")
font.family: "Helvetica"
font.pixelSize: 40
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
}
}