PDA

View Full Version : timeline



franco.amato
5th December 2009, 05:03
Hi to all, I'm developing an audio editor that at the moment has basic functionalities as draw the sound waveform, play the sound.
I would implement a time line ( a moving vertical line ) that give to the user an idea of which part of the sound is playing.
In the paintEvent I have to draw the waveform ( cached in a QImage ) and the time line.

This is my paintEvent

void WaveWidget::paintEvent( QPaintEvent* pe )
{
// Update the ev->rect area with the wave from the rendered QPixmap here

if( m_waveCachePixmap.isNull() )
{
updateWave();
}

QPainter p( this );
QPen pen = QPen(Qt::blue, 1);
p.setRenderHint( QPainter::Antialiasing, true );
p.drawImage( 0, 0, m_waveCachePixmap );

QRect& rect = QRect(pe->rect());
p.setPen(pen);

p.drawLine( rect.x(), 0, rect.x(), height() );
}

I also have to delete the previous line before to draw the new? Or the final result is a growing rectangle. How can I do?

Best,
Franco

wysota
5th December 2009, 14:14
What exactly is the problem?

franco.amato
5th December 2009, 16:42
What exactly is the problem?

Instead of drawing a horizzontally moving line it draw a rectangle that grow.

wysota
5th December 2009, 23:36
The rect() you get in the paint event can be an arbitrary rectangle from within your widget's coordinates. I don't think you want to paint arbitrary rectangles on your widget...

franco.amato
6th December 2009, 20:19
The rect() you get in the paint event can be an arbitrary rectangle from within your widget's coordinates. I don't think you want to paint arbitrary rectangles on your widget...

Sorry but I didn't get you.
So what must I do? Where my code is wrong?

wysota
7th December 2009, 08:35
So what must I do?
Draw a line in coordinates you want it to be drawn at, not the ones passed to you by the event.


Where my code is wrong?

Here:

QRect& rect = QRect(pe->rect());
p.setPen(pen);

p.drawLine( rect.x(), 0, rect.x(), height() );

franco.amato
7th December 2009, 19:39
Draw a line in coordinates you want it to be drawn at, not the ones passed to you by the event.



Here:

QRect& rect = QRect(pe->rect());
p.setPen(pen);

p.drawLine( rect.x(), 0, rect.x(), height() );


Sorry but I don't understand you.
How can I draw I line where I want whitout considering the rect()? How can I pass the coordinates of the line to the paintEvent?

Can you explain to me?

Best

franco.amato
7th December 2009, 21:44
I solved it.
The problem was the rect I passed to the paintEvent. It must completely contain the 2 lines ( old and new ). Something like this
QRect r = QRect( old_line - 1, 0, new_line + 1, height() ) and pass r to the paintevent

update( r )

Regards,
Franco

wysota
8th December 2009, 08:16
No, that's wrong as well. Take a window from another application and start moving it around over your widget. You will see it's getting messy.

franco.amato
8th December 2009, 09:12
No, that's wrong as well. Take a window from another application and start moving it around over your widget. You will see it's getting messy.

So please let me know how must I do.


Thank you

wysota
8th December 2009, 09:57
So please let me know how must I do.

I already told you - draw the line in a place where you want it drawn, not in a random place. The line has some logic behind it, right? Are you able to tell exactly where the line should be drawn at a specified arbitrary moment based on the state of the application?

franco.amato
8th December 2009, 18:07
I already told you - draw the line in a place where you want it drawn, not in a random place. The line has some logic behind it, right? Are you able to tell exactly where the line should be drawn at a specified arbitrary moment based on the state of the application?

Yes Is exactly what I did

wysota
8th December 2009, 19:37
Yes Is exactly what I did

You mean now or when? Because none of the code you pasted does what I said.

franco.amato
8th December 2009, 22:50
You mean now or when? Because none of the code you pasted does what I said.

Here my last code:


void WaveWidget::paintEvent( QPaintEvent* pe )
{
if( m_waveCachePixmap.isNull() )
{
updateWave();
}

QPainter p( this );
QPen pen = QPen(Qt::blue, 1);
p.setRenderHint( QPainter::Antialiasing, true );
//wave
p.drawPixmap( 0, 0, m_waveCachePixmap );

//timeline
p.setPen(pen);
p.drawLine( m_CurrentTimePosition, 0, m_CurrentTimePosition, height() );
}

and the setCurrentTimePosition (as in my last post):

void WaveWidget::setCurrentTimePosition()
{
uint newTimeValue = getCurrentPos();

/* trasform time coord in widget coord */
qreal samplesPerPixel = m_wave->getSamples() / width();
qreal x_pos = newTimeValue / samplesPerPixel;

if( x_pos == m_CurrentTimePosition )
return; //no change

QRect r = QRect( m_CurrentTimePosition - 1, 0, x_pos, height() );
update( r );

/* update current pos */
m_CurrentTimePosition = x_pos;
}

Is what did you suggested to me?

wysota
8th December 2009, 23:26
Yes, it's much better now. The only thing I could suggest is to move updateWave() to setCurrentTimePosition() method. Your paintEvent() would then execute a bit faster which might be beneficial if complexity of your application grows.

franco.amato
9th December 2009, 02:02
Yes, it's much better now. The only thing I could suggest is to move updateWave() to setCurrentTimePosition() method. Your paintEvent() would then execute a bit faster which might be beneficial if complexity of your application grows.

Hi. Imagine that scenario:
1) I load an audio file -> the waveform is generated.
2) I resize the window WITHOUT PLAY THE FILE
in this case I have to update the wave so I can not move the updatewave inside the setCurrentTimePosition

Did you get me?

Best

wysota
9th December 2009, 08:10
2) I resize the window WITHOUT PLAY THE FILE
in this case I have to update the wave so I can not move the updatewave inside the setCurrentTimePosition

Call updateWave() from the resizeEvent() as well. It's still worth it to write another method to have the paint event not have to execute the if statement every time your widget is redrawn.

franco.amato
10th December 2009, 00:28
Call updateWave() from the resizeEvent() as well. It's still worth it to write another method to have the paint event not have to execute the if statement every time your widget is redrawn.

I moved the updateWave inside the resize event but the resizing process now seems slower.

What do you think about?

wysota
10th December 2009, 01:28
During every resize your wave is being updated. It would be wise to update it only when the user stops resizing but then it might not be worth the effort. Maybe you should stick with generating the pixmap during paint event for now until you reach a point where it becomes a bottleneck.