0

For the last couple of days i am trying to solve a particular problem with the Qt Layout system. I'll try to generalize it: I have a widget with two rows. On the first row there are tree buttons( or whatever other controls ). Their layout is shown on the picture: enter image description here

The center button is taking all the extra space available( and is expanding as the widget increases its size ). The thing is that i want to programmatically want to resize the center widget( button ) and maintain the layout. With my current implementation when i resize the center button this is what happens:

enter image description here

I want the right button to be aligned on the right of the center button( without the extra space ). Now when i resize the widget it is going back to position 1 ( center takes all the extra space ), but this is not the effect i want.

Here is my current implementation:

#include "Widget_Old.h"

#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDebug>

WidgetOld::WidgetOld(QWidget *parent) :
    QWidget(parent)
{
    QVBoxLayout* mainLayout = new QVBoxLayout( this );

    QWidget* firstRowWidget = new QWidget( this );

    QPushButton* left   = new QPushButton;
    left->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
    left->setText( "left" );

    m_center = new QPushButton;
    m_center->setText( "centerr");
    m_center->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );

    QPushButton* right  = new QPushButton;
    right->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );
    right->setText( "right" );

    QHBoxLayout* firstRowLayout = new QHBoxLayout( firstRowWidget );

    firstRowLayout->addWidget( left );
    firstRowLayout->addWidget( m_center );
    firstRowLayout->addWidget( right );

    QHBoxLayout* secondRowLayout = new QHBoxLayout;
    QPushButton* button = new QPushButton( "resize" );
    connect( button, SIGNAL(clicked()), SLOT(decrement()) );
    secondRowLayout->addWidget( button );

    mainLayout->addWidget( firstRowWidget  );
    mainLayout->addLayout( secondRowLayout );
}

WidgetOld::~WidgetOld()
{
}


void WidgetOld::decrement()
{
    qDebug() << "Changing width from " << m_center->width() << " to " << m_center->width()/2;
    m_center->resize( m_center->width()/2, m_center->height() );
}

Notes:

I've tried aligning the center, and right widget Qt::AlignLeft, but no result. Actually when aligning widget left in a layout it tries to take the minimal size which breaks the expanding functionality:(

I've shared my code if any reference is needed: https://drive.google.com/file/d/0B-mc4aKkzWlxTWdNNmpuQ0ptQ3M/edit?usp=sharing

Thanks for reading my post, hope you know the solution:)

GeneralFailure
  • 1,085
  • 3
  • 16
  • 32

3 Answers3

0

when you use layouts you move responsibility of managing the size to a layout, so you should NEVER resize items manually when they are in layout.

try this:

WidgetOld::WidgetOld(QWidget *parent) :
    QWidget(parent)
{
    QVBoxLayout* mainLayout = new QVBoxLayout( this );

    QWidget* firstRowWidget = new QWidget( this );

    QPushButton* left   = new QPushButton;
    left->setText( "left" );
    left->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );

    m_center = new QPushButton;
    m_center->setText( "centerr");
    m_center->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );

    QPushButton* right  = new QPushButton;
    right->setText( "right" );
    right->setSizePolicy( QSizePolicy::Maximum, QSizePolicy::Preferred );

    QHBoxLayout* firstRowLayout = new QHBoxLayout( firstRowWidget );

    firstRowLayout->addWidget( left );
    firstRowLayout->addStretch();
    firstRowLayout->addWidget( m_center );
    firstRowLayout->addStretch();
    firstRowLayout->addWidget( right );

    QHBoxLayout* secondRowLayout = new QHBoxLayout;
    QPushButton* button = new QPushButton( "resize" );
    connect( button, SIGNAL(clicked()), SLOT(decrement()) );
    secondRowLayout->addWidget( button );

    mainLayout->addWidget( firstRowWidget  );
    mainLayout->addLayout( secondRowLayout );
}
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • Thanks for the quick reply, but this doesn't really work. I think the stretches actually add spacing between the buttons and i want them to be tied together:) Concerning that rule for not re-sizing custom widgets do you have any ideas on how to solve the problem using another approach. – GeneralFailure Jan 20 '14 at 11:32
  • maybe I don't understand what are you trying to achieve. I thought that center button should be centered with spacing with other buttons. If you need other combination just put stretching in different position (where you need space). – Marek R Jan 20 '14 at 11:39
  • I will add stretch after the last button and this should work. But when I increment the size of the center button, the right one is not moving and its geometry should be updated manually. – GeneralFailure Jan 20 '14 at 14:08
  • read again first sentence from my answer. You can enforce different size for example by changing minimum `minimumWidth`. – Marek R Jan 20 '14 at 14:31
0

You have to set the maximum size of your central widget. For the right widget to adapt, set its size policy to MinimumExpanding when you resize the central one:

void WidgetOld::decrement ()
{
    qDebug() << "Changing width from " << m_center->width() << " to " << m_center->width()/2;
    m_center->setMaximumWidth (m_center->width()/2);
    m_right->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
}

Alternatively, if you resize the central widget manually (which is deprecated, as the above commenter noted), you must also update the geometry of the right one manually. Then your decrement method should look like

void WidgetOld::decrement ()
{
    qDebug() << "Changing width from " << m_center->width() << " to " << m_center->width()/2;
    m_center->resize( m_center->width()/2, m_center->height() );
    int rightPosX = m_center->pos().x() + m_center->width() + m_firstRowLayout->spacing ();
    int rightWidth = centralWidget()->pos().x() + centralWidget()->width() - m_mainLayout->margin() - rightPosX;
    m_right->setGeometry (rightPosX, m_right->pos().y(), rightWidth, m_right->height());
}

In this case, you should also update your custom sizes on resize, as the layout will try to restore default proportions.

Anton Poznyakovskiy
  • 2,109
  • 1
  • 20
  • 38
  • Actually with the first approach indeed the right button will remain to the left, but it will also increase its size. I guess if i want to keep the right button its size, I should add a stretch after the last button? – GeneralFailure Jan 20 '14 at 13:50
  • So you want the right widget to retain its size, so that you have blank space to the right when you resize the central widget? In this case, you don't need to set size policy in `WidgetOld::decrement`, instead add `firstRowLayout->setAlignment( Qt::AlignLeft );` in the constructor. – Anton Poznyakovskiy Jan 20 '14 at 14:09
0

I don't know if it's a bad idea.

Could you make your firstRowLayout global and then dynamically add a stretch to the layout in the end in your decrement() SLOT function?

void WidgetOld::decrement(){
    qDebug() << "Changing width from " << m_center->width() << " to " << m_center->width()/2;
    m_center->resize( m_center->width()/2, m_center->height() );
    firstRowLayout->addStretch(1);
}

this way the stretch will push all your buttons to the left

Komgcn
  • 323
  • 2
  • 12