Sunday, 7 November 2010

Retrofitting a Qt Layout

I've been re-visiting my AffineTransforms demo to add a GUI to it, I quickly created a suitable ui in Qt Designer and got the program running.

Problem was when I re-sized the window this happens

As you can see the main window re-sizes but the child widgets are the same size. This is the default procedure and I needed to add a layout manager to the ui, "simple I thought", then oh no it isn't, after lots of  RTFM and finding this post I finally managed to get this

First off you need to think about how the UI should look and what you are actually trying to achieve,  Qt has 4 main layout options Form and Grid are the main ones for the type of UI I was going for (decided the splitter one was not really applicable to this project).

So I clicked on the central widget for the main window and tried the formLayout and this happened

No really what I wanted, "oh well lets try the Grid Layout"

Slightly better but still not right, however if you start moving widgets around they sort of locks in place and I ended up with this

Originally I had a QFrame widget with the OpenGL window placed into as a child using this code
// now we create our glwindow class
m_gl = new GLWindow(m_ui->m_glFrame);

However for some reason this doesn't work and the GLWindow doesn't get the re-size or parenting to the frame (I'm presuming as it's not added to a layout it doesn't get the re-size event)
So I decided to "read the source" and see what the uic produced in the .h file from the form.

m_glFrame = new QFrame(m_centralwidget);

gridLayout_6->addWidget(m_glFrame, 0, 0, 5, 6);

gridLayout_6 WTF is that? It turns out that as I've been fighting with the designer this was the 6th grid widget I'd created and not named it. So I searched in the Object viewer only to not find this layout. WTF again! Finally I found that the layout was hidden here
So I renamed it to s_mainGridLayout ( s_ as it's effectively a static member I tend to call all  ui elements s_  when they are not modified by the code being written despite the fact that the Qt engine does) and I can now access it in my code, so to create the GLWindow I just need to do the following 

// now we create our glwindow class
m_gl = new GLWindow(this);
m_ui->s_mainGridLayout->addWidget(m_gl, 0, 0, 6, 6);

Where the addWidget command is prototyped as
void QGridLayout::addWidget ( QWidget * widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0 )

As we have 6 widgets across the bottom of the screen (the controls for choosing the model etc) this is the size we need.

This seems to work now,  finally all I had to do was to ensure the other container widgets didn't re-size as the main window is changed, to do this we set the size policy of the container widgets
So what have I learnt?
  1. Always set the main widget layout before adding other elements
  2. Use containers within containers for layouts
  3. retrofitting is a pain ;-)
Finally a teapot

No comments:

Post a comment