PDA

View Full Version : attach more widgets to a QScrollArea



franco.amato
14th January 2010, 18:23
Hi to all,
I'm able to attach a widget to a scrollarea. I would know if it's possible to attach more than one qwidget to the same scrollarea.
So when I move the scrollbar, both widgets should be moved.

I tried with this code:


/* scroll area */
QScrollArea* sa = new QScrollArea( this );
sa->setWidgetResizable( true );
sa->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
sa->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn );

QScrollBar *scrollBar = sa->horizontalScrollBar();

m_WaveDisplay = new WaveDisplay; //QWidget
m_TimeDisplay = new TimeWidget; //QWidget

sa->setWidget(m_TimeDisplay);
sa->setWidget(m_WaveDisplay);

QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget( sa );

..more code..

but I get a crash when the application starts.
Maybe is not possible?

Best

faldzip
14th January 2010, 19:57
you can do it like this:


QWidget w = new QWidget(this);
QVBoxLayout *lo = new QVBoxLayout;
lo->addWidget(m_TimeDisplay);
lo->addWidget(m_WaveDisplay);
w->setLayout(lo);
sa->setWidget(w);

franco.amato
15th January 2010, 01:14
you can do it like this:


QWidget w = new QWidget(this);
QVBoxLayout *lo = new QVBoxLayout;
lo->addWidget(m_TimeDisplay);
lo->addWidget(m_WaveDisplay);
w->setLayout(lo);
sa->setWidget(w);


It works, thank you

franco.amato
15th January 2010, 19:48
you can do it like this:


QWidget w = new QWidget(this);
QVBoxLayout *lo = new QVBoxLayout;
lo->addWidget(m_TimeDisplay);
lo->addWidget(m_WaveDisplay);
w->setLayout(lo);
sa->setWidget(w);


I spoken too early.
It doesn't work.
In the ctor of the m_TimeDisplay I have


setMinimumSize( QSize(800, 20) );
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // it must expand only orizzontally

In the ctor of the m_WaveDisplay I have



setMinimumSize( QSize(800, 250) );
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // it must expand only orizzontally


Now in the ctor of the WaveWidget that must contains both m_TimeDisplay and m_WaveDisplay
I have the code you suggested to me:


/* scroll area */
QScrollArea* sa = new QScrollArea( this );
sa->setWidgetResizable( true );
sa->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
sa->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn );

QScrollBar *scrollBar = sa->horizontalScrollBar();

QWidget* w = new QWidget();
w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
w->setMinimumSize(800, 271); // 271 = 250(m_WaveDisplay) + 20(m_TimeDisplay) + 1

QVBoxLayout* il = new QVBoxLayout;
il->addWidget( m_TimeDisplay );
il->addWidget( m_WaveDisplay );
w->setLayout(il);
sa->setWidget(w);

QVBoxLayout* layout = new QVBoxLayout();

layout->addWidget(sa);
layout->addLayout( infoLayout );
layout->addLayout(lo);
setLayout(layout);

The result is in this image ( also attached )4145
You can see that there are some not desired spaces and the widget w doesn't occupies all scrollarea surface.

I don't know where I'm wrong.

Best Regards,
Franco

pezmaster31
15th January 2010, 22:02
You can see that there are some not desired spaces

check out QBoxLayout::setSpacing()


the widget w doesn't occupies all scrollarea surface

check out QAbstractScrollArea::setViewportMargins()

pezmaster31
15th January 2010, 22:04
nevermind on my 2nd tip - QAbstractScrollArea::setViewportMargins() is protected

wysota
15th January 2010, 22:09
Add a spacer after the last widget and also play with setWidgetResizable().

franco.amato
15th January 2010, 22:20
check out QBoxLayout::setSpacing()

I set il->setSpacing(1) ans the above space is reduced to 1 pixel but I still have problems with the bottom space.
I'm trying all.
I'm sure the problem is in set the parents, in the logic.


check out QAbstractScrollArea::setViewportMargins()

I tried to call it but is protected and doc says that default values are 0 ( what I want, overall for the bottom space ).
The widget doesn't fit well the scroll area.
When I try to resize the widget ( with a zoom ) for an instant it fit all scroll area and then it come back to the previous size.
Something as a pulse.

Any idea?

franco.amato
15th January 2010, 22:27
Add a spacer after the last widget and also play with setWidgetResizable().

Hi,
how can add a spacer? I don't use designer. I played with setWidgetResizable but if I set it to false I can not zoom,
what I don't want.

Thank you

wysota
15th January 2010, 22:52
how can add a spacer?
QSpacerItem


I played with setWidgetResizable but if I set it to false I can not zoom,
I don't really know what you mean by "zoom" in this situation. In general this property should be set rather to true than to false (the latter is default).

franco.amato
15th January 2010, 23:16
QSpacerItem


I don't really know what you mean by "zoom" in this situation. In general this property should be set rather to true than to false (the latter is default).

Dear wysota in my case the m_TimeDisplay and m_WaveDisplay are used to show an audio wave were user can zoom in/out to navigate into the sound.
I would attach such widgets to a QScrollArea to leave to Qt manage when user zoom.

This is what I meant

wysota
15th January 2010, 23:36
That's not the way to go, really... Nevertheless, I don't see the problem. Would you care to explain?

franco.amato
15th January 2010, 23:44
That's not the way to go, really... Nevertheless, I don't see the problem. Would you care to explain?

Which is the way to go?

Well the problem is that the widget doesn't fit the scroll area.
I'm not sure the logic I used is correct ( assign the correct parent of every widget )

pezmaster31
16th January 2010, 00:21
Not sure if this is the ideal way to achieve this sort of behavior... but this seems to work on my end (if I understand you correctly)




// set size policy for your WaveDisplay widget to use as much vertical space on its parent as is available
m_WaveDisplay->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);

QVBoxLayout* il = new QVBoxLayout;
il->setSpacing(0);
il->addWidget(m_TimeDisplay);
il->addWidget(m_WaveDisplay);

QWidget* w = new QWidget();
// you had the widget's vertical size policy set to Fixed, so there's no way it could ever expand vertically, changed to Ignored (same as WaveDisplay)
// w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
w->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
w->setMinimumSize(800, 271); // 271 = 250(m_WaveDisplay) + 20(m_TimeDisplay) + 1
w->setLayout(il);

QScrollArea* sa = new QScrollArea;
sa->setWidgetResizable(true);
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn );
sa->setWidget(w);

wysota
16th January 2010, 00:52
Which is the way to go?
Either a completely custom widget derived from QAbstractScrollArea or Graphics View.


Well the problem is that the widget doesn't fit the scroll area.
setWidgetResizable(true) would fix the problem.

franco.amato
16th January 2010, 01:06
Either a completely custom widget derived from QAbstractScrollArea or Graphics View.


setWidgetResizable(true) would fix the problem.

Hi, I already set it to true. It doesn't solve the problem. I posted above the most important code. If you can give a look you can see that the setWidgetResizable(true) is set to true

franco.amato
16th January 2010, 01:21
Either a completely custom widget derived from QAbstractScrollArea or Graphics View.

I can rewrite it if it's the case. Can you give me some hints on how to do it? As now I inherited from QWidget.
I wrote WaveWidget : QWidget.
WaveWidget contains vertically aligned
1) TimeDisplay : QWidget
2) WaveDisplay : QWidget

I would attach a QScrollArea to WaveWidget as I said to allow user zoom without results :mad:

franco.amato
16th January 2010, 01:51
Not sure if this is the ideal way to achieve this sort of behavior... but this seems to work on my end (if I understand you correctly)




// set size policy for your WaveDisplay widget to use as much vertical space on its parent as is available
m_WaveDisplay->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);

QVBoxLayout* il = new QVBoxLayout;
il->setSpacing(0);
il->addWidget(m_TimeDisplay);
il->addWidget(m_WaveDisplay);

QWidget* w = new QWidget();
// you had the widget's vertical size policy set to Fixed, so there's no way it could ever expand vertically, changed to Ignored (same as WaveDisplay)
// w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
w->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored);
w->setMinimumSize(800, 271); // 271 = 250(m_WaveDisplay) + 20(m_TimeDisplay) + 1
w->setLayout(il);

QScrollArea* sa = new QScrollArea;
sa->setWidgetResizable(true);
sa->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn );
sa->setWidget(w);


Hi now the widget fit the scroill area but I still have some problems.
1) when I resize the widget ( for example user zoom in ) the widget seems to pulse. It grow and shrank (in the orizontally direction that must be fixed) continuosly every time user press zoom button
2) The scroll bar is not shown. The widget grow ( in a bad way ) but I can not navigate in it with the scroll bar.

May be my code of zoom is not correct.
This is the code


// executed when user press zoonin button
void WaveWidget::zoomIn()
{
float f = m_ZoomFactor + 0.12;
qDebug() << "WaveWidget::zoomIn - f: " << f;
m_WaveDisplay->setZoomFactor( f );
}

And then the code to expand the WaveDisplay


/************************************************** **********************/
/* setZoomFactor */
/************************************************** **********************/
void WaveDisplay::setZoomFactor( float f )
{
int w, h;

w = width() * f;
h = height();

setMinimumSize( w, h );
QWidget* p = dynamic_cast<QWidget*>( parent() );
if (p)
resize( p->width(), p->height() );
repaint();
}

I'm sure my code is wrong but I don't know where...
The zoom is wrote in very few time and I'm not sure is a correct way to do it.
The code of the zoom of TimeDisplay is not implemented yet..

Regards

franco.amato
16th January 2010, 02:14
I changed the code of the zoom so:


/************************************************** **********************/
/* setZoomFactor */
/************************************************** **********************/
void WaveDisplay::setZoomFactor( float f )
{
int w, h;

w = width() * f;
h = height();

setMinimumSize( w, h );
QWidget* p = dynamic_cast<QWidget*>( parent() );
if (p)
{
//resize( p->width(), p->height() );
resize(w, h); // <--------------------------------------------------------CHANGED
}

repaint();
}

And now I don't get the "grow and shrank" effect when I zoom. But the status bar still doesn't appear.
I can not navigate into the wave.
Any idea?

Best

wysota
16th January 2010, 09:56
The zoom is wrote in very few time and I'm not sure is a correct way to do it.
Defintely not :)

You are artificially manipulating the size of each child widget which is not a very good idea. Using graphics view or implementing everything as one widget derived from QAbstractScrollArea would be a much better approach.

franco.amato
16th January 2010, 16:12
Defintely not :)

You are artificially manipulating the size of each child widget which is not a very good idea. Using graphics view or implementing everything as one widget derived from QAbstractScrollArea would be a much better approach.

Thank you very much.
Can you give some line the code just to start the widget derived from QAbstractScrollArea?

Best

wysota
16th January 2010, 16:44
I can't give you a complete 10 line sample. I can tell you it is just like any ordinary widget with exception that at each time you only see part of it and the part seen is manipulated using QAbstractScrollArea::scrollContentsBy() that you will need to implement.

franco.amato
17th January 2010, 18:57
I can't give you a complete 10 line sample. I can tell you it is just like any ordinary widget with exception that at each time you only see part of it and the part seen is manipulated using QAbstractScrollArea::scrollContentsBy() that you will need to implement.

Why I can not inherits from QScrollArea instead of QAbstractScrollArea?

wysota
17th January 2010, 19:01
You can but in my opinion this is a bad idea for the functionality you are trying to implement.

franco.amato
17th January 2010, 22:57
You can but in my opinion this is a bad idea for the functionality you are trying to implement.


Is a bit difficult...and I can not find a valid example

wysota
17th January 2010, 23:03
What is so difficult in it? As for examples, you have the code of Qt, you also have examples of classes that are derived from classes that are derived from QAbstractScrollArea (like views in Item Views).

franco.amato
18th January 2010, 06:03
What is so difficult in it? As for examples, you have the code of Qt, you also have examples of classes that are derived from classes that are derived from QAbstractScrollArea (like views in Item Views).

I can not find such example in my Qt 4.6.0 installation

wysota
18th January 2010, 08:15
I can not find such example in my Qt 4.6.0 installation

Qt source code is one big example :) But you may also look at the "chart" example.

franco.amato
18th January 2010, 16:53
Qt source code is one big example :) But you may also look at the "chart" example.

Thank you very much wysota, but I think what I need is simpler that it appear to be.
I wrote a routine that draw an audio graph depending on how many audio samples I would display and which is the width of the widget containing the graph.
So in case of

resizing
zoomIn
zoomOut


what change (automatically resizing, or manually zooming) is the width of the widget accordingly to that I draw the correct audio wave.
So I think I don't need to go so deeply reimplementing the method you suggested to me. Maybe I'm wrong.
What do you think?

Best Regards

wysota
18th January 2010, 18:00
At some point there comes a time where you have to go past your current skills and examples. I think the time has come for you, especially that it seems you have over two years of experience with Qt. You either do it wrong (like you are doing now) and learn nothing or you make some effort, learn and do the thing properly.

franco.amato
18th January 2010, 18:07
At some point there comes a time where you have to go past your current skills and examples. I think the time has come for you, especially that it seems you have over two years of experience with Qt. You either do it wrong (like you are doing now) and learn nothing or you make some effort, learn and do the thing properly.

Already done but seems you didn't agree with my solution :)

wysota
18th January 2010, 19:24
Already done but seems you didn't agree with my solution :)

Your solution will fall apart once you need to add more functionality to it. Composing your GUI from already existing widgets is not the only possibility, sometimes you need to create a custom widget consisting of something more than just a paint event.

franco.amato
18th January 2010, 23:23
Your solution will fall apart once you need to add more functionality to it. Composing your GUI from already existing widgets is not the only possibility, sometimes you need to create a custom widget consisting of something more than just a paint event.

I started rewriting a custom widget derived from QScrollArea so:


class WaveDisplay : public QScrollArea
{
..code..
};

As I understood until now, QScrollArea show its scroll bars only when the child widgets are bigger than the scrollarea viewport right?
Here I have a doubt. If my widget inherits from QScrollArea, then it doesn't have a child widget as it's the child widget. So it's size will never
be bigger than the viewport. It's size will always be equal the viewport and the scroll bars will never appears of I'm saying something foo?

I hope someone can clarify this to me.

Best

wysota
19th January 2010, 10:19
Deriving from QScrollArea doesn't make sense because eventually you will do the same what you did before. You have to use QAbstractScrollArea and abandon your wave widget class and move its code inside your new class. The point of deriving from QAbstractScrollArea is that you can provide zooming and panning facilities without the need to manipulate widget sizes and layouts. If that's too complicated for you then derive from QScrollArea like you did before but don't use a layout for your scrolled widget and instead position the widgets manually upon every need to do so.

franco.amato
19th January 2010, 11:00
Deriving from QScrollArea doesn't make sense because eventually you will do the same what you did before. You have to use QAbstractScrollArea and abandon your wave widget class and move its code inside your new class. The point of deriving from QAbstractScrollArea is that you can provide zooming and panning facilities without the need to manipulate widget sizes and layouts. If that's too complicated for you then derive from QScrollArea like you did before but don't use a layout for your scrolled widget and instead position the widgets manually upon every need to do so.

Hi before I didn't derived from QScrollArea...is what I'm trying to do now. Please can you help me with a little example of zooming in this case?
My experience is too little at the moment. I'll really appreciate it.

Best Regards

wysota
19th January 2010, 11:11
Hi before I didn't derived from QScrollArea...is what I'm trying to do now.
Deriving or using.. what's the difference?


Please can you help me with a little example of zooming in this case?
No, because in my opinion this is a wrong approach. If you insist on doing this, use QWidget::setGeometry() to change the geometry of child widgets.

franco.amato
19th January 2010, 11:19
Deriving or using.. what's the difference?

No difference



No, because in my opinion this is a wrong approach. If you insist on doing this, use QWidget::setGeometry() to change the geometry of child widgets.

I would use a better approach, but I'm sure you understood that I'm unable to do.
I have a very poor experience in writing gui and how can I improve it if I don't get help? Sometime a very basic example is very usefull starting point. I did't ask to you to provide a complete software

wysota
19th January 2010, 11:36
I have a very poor experience in writing gui and how can I improve it if I don't get help?
Come on, man... Registration date - Nov 2007, 163 posts and no experience?


Sometime a very basic example is very usefull starting point.
Always relying on mimicing existing code doesn't lead to extending your skills. What example would you want me to give you? Something like this?

QWidget *w = new QWidget(viewport());
w->setGeometry(20, 20, 200, 100);

franco.amato
19th January 2010, 16:45
Come on, man... Registration date - Nov 2007, 163 posts and no experience?

In my work only write very basic gui...until now
That's my experience.



Always relying on mimicing existing code doesn't lead to extending your skills. What example would you want me to give you? Something like this?

QWidget *w = new QWidget(viewport());
w->setGeometry(20, 20, 200, 100);

What I didn't understand is (with an object inherited from QScrollArea)
for example MyWidget : QScrollArea the view port is always = to the width right or not? This is my doubt. If so how scrollarea manage scroll bars?

wysota
19th January 2010, 17:47
Viewport is always smaller than the view.

If so how scrollarea manage scroll bars?
It reimplements QAbstractScrollArea::scrollContentsBy().