QGridLayout, 3 panes, not expanding properly - qt

I'm trying to layout a window (all in code) with a QGridLayout. I can add widgets to the layout and they display in my window, but I can't figure out how to resize them properly. Here's what I'd like
[Leftmost][--------Center---------][Rightmost]
Those are the 3 "panes" of my window (all three of them lists). The left and right ones should be of a static width and hug their respective sides, and the center should expand to fill the width as the window grows (or shrinks).
Some code:
// Create the subviews, add them to a grid layout, and set the layout to the window.
QTableView *list = new QTableView(0);
list->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QTableView *flashList = new QTableView(0);
flashList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QPushButton *infoButton = new QPushButton("Info!");
QPushButton *flashFeedsButton = new QPushButton("Flashfeeds");
QGridLayout *gridLayout = new QGridLayout;
// Set the minimum widths for all three columns of the grid
gridLayout->setColumnMinimumWidth(GridColumnFirst, 300);
gridLayout->setColumnMinimumWidth(GridColumnSecond, 300);
gridLayout->setColumnMinimumWidth(GridColumnThird, 300);
// Set the minimum heights for all rows of the grid
int headerFooterHeight = 44;
gridLayout->setRowMinimumHeight(GridRowFirst, headerFooterHeight);
gridLayout->setRowMinimumHeight(GridRowSecond, 200);
gridLayout->setRowMinimumHeight(GridRowThird, headerFooterHeight);
// Set the stretch factors
gridLayout->setColumnStretch(GridColumnFirst, 1);
gridLayout->setColumnStretch(GridColumnFirst, 2);
gridLayout->setColumnStretch(GridColumnThird, 1);
gridLayout->addWidget(list, 1, 0, Qt::AlignLeft);
gridLayout->addWidget(flashList, 1, 1, Qt::AlignCenter);
gridLayout->addWidget(infoButton, 0, 3, Qt::AlignRight);
gridLayout->addWidget(flashFeedsButton, 0, 1, Qt::AlignLeft);
_mainWindow->setLayout(gridLayout);
(As you might be able to tell, this is going to eventually be a 9x9 grid, but the point remains, I'm trying to get my middle row (GridRowSecond) to have the stretchy columns).
The rows themselves expand just fine. The problem seems to be getting the widgets at each cell to expand to take up their containing space. How do I do this? (also, vertically, my list is expanding properly, but not horizontally).

Look at the docs on QGridLayout::AddWidget:
The default alignment is 0, which means that the widget fills the entire cell.
But you have the following:
gridLayout->addWidget(list, 1, 0, Qt::AlignLeft);
gridLayout->addWidget(flashList, 1, 1, Qt::AlignCenter);
gridLayout->addWidget(infoButton, 0, 3, Qt::AlignRight);
gridLayout->addWidget(flashFeedsButton, 0, 1, Qt::AlignLeft);
Thus, you've specifically told the grid layout that you want your widget aligned to the left, center, right, and left of their cells, respectively. In your case you probably want to use the default alignment allowing the widgets to fill the cells and follow their own respective size policies.

It should just be a matter of setting the proper size policy on your widgets. So the buttons on the left and right:
button->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
and for the middle button
button->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
where the first argument defines the horizontal size policy and the second one defines the vertical size policy.
See the size policy documentation as well

You have a lot of variables going here (different widgets, different size policies on widgets, and size policies working on the layout itself, so it's a bit difficult to know where things are going wrong. A couple of suggestions:
1) First try to accomplish what you want with just one type of widget. For example, all QLabels with all Expanding size policies.
2) Only adjust the size policies of the widgets, I found that adding stuff in the grid layout starts making things confusing. The stretch factor for the widget's size policy should work fine.
3) Don't be afraid to try different ratios for stretch factors.
I've found that this is one of the things where Qt Designer (Creator) is helpful for puzzling these things out. It's much faster to adjust things in Designer and resize then the run compile cycle. After you have solved the issue there, you can take the properties you have found and put it in your code instead of a edit, compile, run.

Related

Space between widgets in QVBoxLayout

I'm trying to make a sign-in form with Qt5.0.1. I created 2 Widgets and I put my labels and line edits in one of them, and my button in other one. Then I put these 2 widgets in a QVBoxLayout, but the space between two widget in layout is more than purpose. I tried setSpacing and setContentsMargin but they didn't work for this program.
vhandle->setSpacing(0);
vhandle->setMargin(0);
vhandle->setContentsMargins(0,0,0,0);
vhandle->addWidget(handle,0, Qt::AlignTop);
vhandle->addWidget(handle2,0, Qt::AlignTop);
but nothing changed in space between two widgets:
what should I do?
The issue is not the margin settings of the QVboxLayout, but the margin settings of the layout of your container widgets and the spacing setting of the QVBoxLayout. You already have set the spacing to 0, this should be fine. In addition, assumed that upperWidgetLayout is the layout of the upper widget and lowerWidgetLayout the layout of the lower widget, try
upperWidgetLayout->setContentsMargins(-1, -1, -1, 0);
lowerWidgetLayout->setContentsMargin(-1, 0, -1, -1);
This sets the bottom margin of the upper widget's layout and the top margin of the lower widget's layout to 0, so that there is no space between the contents of the two widgets:
Temporarily coloring the various widgets is usually a good approach to track down such issues. You can also use Qt Designer to design the UI and have a look at the source code which is being generated (or use the .ui file directly in your project).
The extra space between widgets or layout can be removed by setting the alignment at top here is an example:
self.layout_scrollarea_v=QVBoxLayout(self.frame)
self.layout_scrollarea_v.setAlignment(Qt.AlignTop)
self.layout_scrollarea_v.addLayout(self.layout_scrollarea_h1)
self.layout_scrollarea_v.addLayout(self.layout_scrollarea_h3)
self.layout_scrollarea_v.addLayout(self.layout_scrollarea_h2)
in your code use
vhandle->setAlignment(Qt::AlignTop)

Separate Layers like feature on QGraphicsView

In my QGraphicsView, I display a map. I need to display a horizontal ruler and a vertical ruler on the top edge and left edge respectfully.
The map needs to scrolled but the above rulers should be displayed at their fixed positions, but change their scale values.
I tried to implement this using drawForeground method. Due to the maps large size I only paint the visible area. So I need to update() every time scrolling is done. But this result sometimes flickers.
I feel it would be best to have separate layer like approach.
What is the best way to approach the problem?
The correct way to implement a ruler on the top and left is to derive from QGraphicsView, and then call in the constructor:
// add two rulers on top and left.
setViewportMargins(20, 20, 0, 0);
// add grid layout
QGridLayout* gridLayout = new QGridLayout();
gridLayout->setSpacing(0);
gridLayout->setMargin(0);
// create rulers
hRuler = new Ruler(Qt::Horizontal);
vRuler = new Ruler(Qt::Vertical);
// add items to grid layout
QWidget* corner = new QWidget();
corner->setBackgroundRole(QPalette::Window);
corner->setFixedSize(20, 20);
gridLayout->addWidget(corner, 0, 0);
gridLayout->addWidget(hRuler, 0, 1);
gridLayout->addWidget(vRuler, 1, 0);
gridLayout->addWidget(viewport(), 1, 1);
// finally set layout
setLayout(gridLayout);
This solution was initially presented here, and it works very well. The result looks like this.
I just changed ViewportUpdateMode of the graphics view to FullViewportUpdate to get away from flicker.
You can use SmartViewportUpdate for somewhat good results also.
The downside is, during animations, this takes more process power.

Expanding a Qt Layout : how to put a widget on the right side and the let the other widget to fully fill the left?

I want to put a widget on the right side of a QHBoxLayout, and the other spaces should expand the left side. I've set the widget's SizePolicy to Expanding, but it's not valid. Anyone could offer some help? Thanks.
Code is here:
QHBoxLayout* tmplayout = new QHBoxLayout(this);
tmplayout->setContentsMargins(0, 0, 0, 0);
lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
tmplayout->addWidget(lineEdit, 0, Qt::AlignRight);
tmplayout->addWidget(pushButton, 0, Qt::AlignRight);
lineEdit should expand.
Try changing:
tmplayout->addWidget(lineEdit, 0, Qt::AlignRight);
tmplayout->addWidget(pushButton, 0, Qt::AlignRight);
To:
tmplayout->addWidget(lineEdit);
tmplayout->addWidget(pushButton);
When dealing with simple layouts like this, there is no need to specify alignments or stretch factors explicitly.
If you want to force pushButton to specific size, you can use setMinimumSize, setMaximumSize, and setFixedSize
Best regards
For the widgets you want to be on the left and expand, try to simply add them before the ones on the right, and add a 1 for their stretch factor. For example,
tmplayout->addWidget(exampleWidget, 1);
Then, you could simply add the widgets you want to be on the right side after the ones on the left, using just:
tmplayout->addWidget(lineEdit);
tmplayout->addWidget(pushbutton);
This will automatically give them a stretch factor of 0.
Since the stretch factor of exampleWidget in this example is 1 which is higher than the default 0, exampleWidget will expand; and, since you add it before the others, it will be on the left.
I am not sure if I understand your problem correctly, but maybe you need to look into QSpacerItem. If that is not helpful, maybe you can make a rough mock-up in Qt-Creator and post the screen shots (one example showing approx. what you have, one example showing what you want)
Try fixed or minimum size policies. Even you may want to fix the maximum width.

Problem with a Qt layout, I can not remove a space

Good morning,
I have to layout some QWidgets and layouts into a main layout, but I have a problem with a space that I can not remove.
Basically what I would achieve is a horizzontal layout containing a grid layout and some buttons ( all in a horizontal line ). The grid layout (2x2) contains 2 QLabels and 2 QLeds.
Unfortunately Qt place a space between the grid layout and the first button as you can see in the attached image here http://img413.imageshack.us/img413/9132/problemhu.png
I would remove such space.
Here the code I wrote:
QGridLayout* gl = new QGridLayout();
gl->setAlignment(Qt::AlignLeft);
gl->setContentsMargins(0, 0, 0, 0);
gl->addWidget(activeLabel, 0, 0);
gl->addWidget(m_focusLed, 0, 1);
gl->addWidget(encodingLabel, 1, 0);
gl->addWidget(m_encodingLed, 1, 1);
This created the grid layout and added the QLabels and QLeds on it.
Then I add the buttons into the horizontal layout so:
/* layout buttons */
QHBoxLayout* lo = new QHBoxLayout();
lo->setSpacing(0);
lo->addLayout(gl); // <--here I add the grid layout
lo->addWidget(m_goToBeginBtn);
lo->addWidget(m_goToEndBtn);
lo->addWidget(m_frewBtn);
lo->addWidget(m_fforBtn);
lo->addSpacing( 10 );
lo->addWidget(m_ffrewBtn);
lo->addWidget(m_ffforBtn);
lo->addSpacing(10);
lo->addWidget(m_prevBtn);
lo->addWidget(m_nextBtn);
lo->addWidget(m_playBtn);
lo->addWidget(m_stopBtn);
lo->addWidget(m_cutBtn);
lo->addSpacing(10);
lo->addWidget(m_zoomInBtn);
lo->addWidget(m_zoomOutBtn);
lo->addSpacing(10);
lo->addWidget(m_bgSndCheckBox);
lo->addWidget( m_showPanelBtn);
I don't know why Qt place such space between the grid layout and the first button. I would remove it. How can I do? I didn't get help from the Qt mailing list.
Best Regards
How to fix this largely depends on what behavior you want to see. I'm guessing what you want is for the labels and the Leds to stay exactly where they are, and keep their size.
What is happening is that the grid layout is resizing with your window, (like your buttons), but the left alignment is keeping the controls stuck to the left, thus the space.
First, remove the gl->setAlignment(Qt::AlignLeft) line.
Secondly, you want to make sure you set the sizePolicy properly on both your QLabels and your QLeds, because otherwise your QLeds will start to resize horizontally. What you want is a fixed horizontal size policy. Here is an example:
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
sizePolicy.setHeightForWidth(label->sizePolicy().hasHeightForWidth());
label->setSizePolicy(sizePolicy);
A completely different way to accomplish the same thing would be to add a bunch of calls to setStretch() on your horizontal layout. But you would have to do this for each column in your layout that you want to stretch. Basically each for each button, but skipping the grid layout in the first column. Like this...
lo->setStretch(1, 1); // Column 1 is your first button
lo->setStretch(2, 1);
...
lo->setStretch(19, 1)l // 19 columns in total, 15 buttons plus 4 spacing.

Layering components with QT

I am using QT Creator to develop a small GUI app. I have a GraphicsView component which spans the entire window. My question is, how can I place other widgets (such as transparent buttons) ontop of it in each of the four corners of the application. Also, how can I make sure that the lower right hand components get resized properly so that they stay in the lower right hand corner.
Ok, you can add a layout and QWidgets to a QGraphicsView so that they overlay the view underneath. You can't do this with QtDesigner (and I'm assuming QtCreator as well), so you'll have to do it in code. You can put the following code in the constructor of your window containing the QGraphicsView (named view) and it will add two buttons to a layout that will keep them anchored at the bottom right of the view:
QGridLayout *gridLayout;
QSpacerItem *horizontalSpacer;
QSpacerItem *verticalSpacer;
QPushButton *button1;
QPushButton *button2;
gridLayout = new QGridLayout(view);
horizontalSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
button1 = new QPushButton(view);
button1->setText("Button1");
button2 = new QPushButton(view);
button2->setText("Button2");
gridLayout->addWidget(button1, 1, 1, 1, 1);
gridLayout->addWidget(button2, 1, 2, 1, 1);
gridLayout->addItem(horizontalSpacer, 1, 0, 1, 1);
gridLayout->addItem(verticalSpacer, 0, 2, 1, 1);
It shouldn't be too much trouble to add two more buttons and two more spacers to achieve a button in each corner of the window.
Making standard QWidget controls transparent can be a bit tricky, especially buttons. Labels are easy though. You can refer to my answer to another question here for some hints for making transparent QPushButtons.
Ok I tried the thing with PySide now and it's not that bad.. Contrary to hacking the generated ui file, I'd suggest to do it afterwards!
So I'm designing 2 cells in a QGridLayout and arrange everything side by side. have it compiled and when building the ui I:
# take 2nd item and add it back to 0, 0 cell in the grid layout
layer = self.ui.gridLayout.takeAt(1)
self.ui.gridLayout.addLayout(layer, 0, 0, 1, 1)

Resources