PDA

View Full Version : Widget layout problem



QtMaci
28th January 2012, 00:17
Hi everyone!

Currently I'm working on a new widget subclass which should implement a control
like the navigation bars known from the MS Office applications. It should like the following screenshot:

7330

My basic problem is to layout QPushButtons vertically, without free space between the
QPushButtons. I thought: oh, that's easy. I'll take a QVBoxLayout, add the QPushButtons into that
layout and a vertical spacer at last. I'll set the layout stretch to (0,0,0,...,1), the layout spacing to zero and it will work.
I tried that concept in Designer, and ... it worked.

But in my real implementation, I don't want add pure QPushButtons to the layout, but a special
own widget. And here's the problem: If I subclass QWidget (for example MyButton : public QWidget) and
add instances of that class to the layout,there is always some space between the widgets.
I tried that with a primitive subclass of QWidget which only added a QPushButton. The ui looks now like the screenshot:

7331

I don't understand: where does this space come from?

I tried a lot of things like overriding the minimumSizeHint() function and so on. But nothing helped.
Any ideas are very welcome!

Lykurg
28th January 2012, 08:04
See QLayout::setContentMargins(). And have you seen QToolBox?

QtMaci
28th January 2012, 16:28
Lykurg, thanks for your answer.

Yes I already placed a call to setContentMargin(0, 0, 0, 0, 0) in my code. But that doesn't help.
And yes I know the QToolBox class. I just want to do the navigation widget as an exercise!

KillGabio
28th January 2012, 17:30
hi i had the same problem...take a look at the StyleSheets they usually solve everything :D http://doc.qt.nokia.com/4.7-snapshot/stylesheet-examples.html

hope it helps i can give you the stylesheet code of my application if you want

Lykurg
28th January 2012, 17:35
No! Style sheets are deprecated. Don't use them.

Then post a example on how you use the layout, because without any code we can only guess... (And add a spacer/stretch as a last item!)

KillGabio
28th January 2012, 19:23
Wow men didnt know they were being deprecated :S I use the following layout for the menu


ui->menuBar->setStyleSheet ( "QMenuBar"
"{"
" background-color: qlineargradient( x1:0, y1:0, x2:0, y2:1, "
" stop: 0 #b0c4de, "
" stop: 0.8 #e6e6e8, "
" stop: 1 #b0c4de ); "
" margin: 0px; "
" padding: 5px; "
" spacing: 5px; "
"}"
"QMenuBar::item"
"{"
" background-color: qlineargradient( x1:0, y1:0, x2:0, y2:1, "
" stop: 0 #b0c4de, "
" stop: 0.8 #c8dcf6, "
" stop: 1 #4682b4 ); "
" border-width: 1px; "
" border-color: darkkhaki; "
" border-style: solid; "
" border-radius: 5px; "
" margin: 3px; "
" padding: 4px; "
" spacing: 20px; "
"}"
"QMenuBar::item:selected { /* when selected using mouse or keyboard */"
"background: #a8a8a8;"
"}"
"QMenuBar::item:pressed {"
"background: #888888;"
"}"
"QMenu {"
"background-color: white;"
"margin: 5px; /* some spacing around the menu */"
"width: 180px;"
"}"
"QMenu::item {"
"padding: 10px 28px 10px 23px;"
"font: bold 12px;"
"border: 1px solid transparent; /* reserve space for selection border */}"
"QMenu::item:selected {"
"border-color: darkblue;"
"background: rgba(100, 100, 100, 150);"
"}"
"QMenu::icon:checked { /* appearance of a 'checked' icon */"
"background: gray;"
"border: 1px inset gray;"
"position: absolute;"
"top: 1px;"
"right: 1px;"
"bottom: 1px;"
"left: 1px;}"
"QMenu::separator {"
"height: 2px;"
"background: lightblue;"
"margin-left: 10px;"
"margin-right: 5px;}"
"QMenu::indicator {"
"width: 13px;"
"height: 13px;}"

);

QtMaci
29th January 2012, 00:48
Ok here comes the code. The following code is created by designer. I use two QPushButtons and a vertical spacer. They are put into a vertical layout. The vertical stretch factors are 0, 0, 1. The spacing is set to 11 so the buttons are aligned.

void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(400, 300);
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
widget = new QWidget(centralWidget);
widget->setObjectName(QString::fromUtf8("widget"));
widget->setGeometry(QRect(0, 0, 114, 113));
verticalLayout = new QVBoxLayout(widget);
verticalLayout->setSpacing(11);
verticalLayout->setContentsMargins(11, 11, 11, 11);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
verticalLayout->setContentsMargins(0, 0, 0, 0);
pushButton = new QPushButton(widget);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setStyleSheet(QString::fromUtf8("QPushButton { background: rgb(77, 77, 77); color: rgb(255, 255, 255)}"));

verticalLayout->addWidget(pushButton);

pushButton_2 = new QPushButton(widget);
pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));
pushButton_2->setStyleSheet(QString::fromUtf8("QPushButton { background: rgb(77, 77, 77); color: rgb(255, 255, 255)}"));

verticalLayout->addWidget(pushButton_2);

verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);

verticalLayout->addItem(verticalSpacer);

verticalLayout->setStretch(2, 1);
MainWindow->setCentralWidget(centralWidget);
menuBar = new QMenuBar(MainWindow);
menuBar->setObjectName(QString::fromUtf8("menuBar"));
menuBar->setGeometry(QRect(0, 0, 400, 22));
MainWindow->setMenuBar(menuBar);
mainToolBar = new QToolBar(MainWindow);
mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);
statusBar = new QStatusBar(MainWindow);
statusBar->setObjectName(QString::fromUtf8("statusBar"));
MainWindow->setStatusBar(statusBar);

retranslateUi(MainWindow);

QMetaObject::connectSlotsByName(MainWindow);
} // setupUi

This result is:

7333

That's fine.

Now I replace the QPushButtons in the code by a class of mine "MyButton". The MyButton class:


class MyButton : public QWidget
{
Q_OBJECT
public:
explicit MyButton(QWidget *parent = 0);

QSize minimumSizeHint() const;
signals:

public slots:

private:
QPushButton* m_button;
};



MyButton::MyButton(QWidget *parent) :
QWidget(parent)
{
m_button = new QPushButton("PushButton", this);
}


QSize MyButton::minimumSizeHint() const {
return m_button->minimumSizeHint();
}


The result is now this:

7334

I guess the problem is the MyButton class. Because when I change MyButton to derive from QPushButton the blank space is not there. So, where do I go wrong in the MyButton class? Which method do I have to override?

wysota
29th January 2012, 00:59
Control the sizeHint and sizePolicy of your widget.

Lykurg
29th January 2012, 09:12
MyButton::MyButton(QWidget *parent) :
QWidget(parent)
{
m_button = new QPushButton("PushButton", this);
}Shouldn't you also install a layout on the custom widget?

QtMaci
31st January 2012, 19:29
Hello again!

Now I tried several things:

1. As Lykurg mentioned I added a layout in the MyButton class:


MyButton::MyButton(QWidget *parent) :
QWidget(parent)
{
QVBoxLayout* layout = new QVBoxLayout();
m_button = new QPushButton("PushButton", this);
layout->addWidget(m_button);
layout->addStretch(1);
layout->setSpacing(0);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
}

But that doesn't change the result: the gap between two MyButton widgets is there :-(

2. As wysota suggested I reimplemented the sizeHint() method as follows:

QSize MyButton::sizeHint() const {
return m_button->sizeHint();
}

and to consider the sizePolicy property I added the following line to the MyButton cstr. above:
setSizePolicy(m_button->sizePolicy());

The result is: the height of the buttons shrinked, the gap is there - see the following screenshot:

7347

Any more ideas?

Lykurg
31st January 2012, 20:04
Don't add a stretch in MyButton!

Spitfire
1st February 2012, 10:06
I can't see a problem here, just get the MyButton above, stick it in the layout and it works. You just have to configure container layout correctly:

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QVBoxLayout* lay = new QVBoxLayout();
lay->setSpacing( 0 );
lay->setMargin( 0 );
lay->addWidget( new MyButton() );
lay->addWidget( new MyButton() );
lay->addWidget( new MyButton() );
lay->addStretch( 1 ); // to push the buttons close together

QWidget* w = new QWidget();
w->setLayout( lay );
this->setCentralWidget( w );
}
button code as posted above:
MyButton::MyButton(QWidget *parent) :
QWidget(parent)
{
QVBoxLayout* layout = new QVBoxLayout();
QPushButton* m_button = new QPushButton("PushButton", this);
layout->addWidget(m_button);
layout->addStretch(1); // not needed
layout->setSpacing(0); // not needed if only single item is in the layout
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
}

QtMaci
1st February 2012, 18:53
I tried the solution of Spitfire and it works. That's exactly what I wanted to do. I compared it again to the layout code created by designer (see a mile above). I detected two problems: the verticalLayout is never set to a widget and the size needed is not 11 but 0. But: the sizeHint() method needs to be reimplemented in MyButton. That's the solution. All my faults...
A big thank you and a round of drinks goes to everyone answered to this thread. Thanks a lot!!!