Russian Qt Forum

Qt => Model-View (MV) => Тема начата: Fregloin от Май 21, 2013, 18:01



Название: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 21, 2013, 18:01
Привет, такая проблема.
В делегате в createEditor нужно создать в ячейке горизонтальный лейаут, в котором будет три виджета, 2 кнопки и 1 произволный.
Лейаут должен быть таким
[  <--- expanding -- QWidget ---expanding -->][ QToolButton ][ QToolButton ]
Дело в том, что все виджеты которые я использую кроме QComboBox,QLineEdit рисуются нормально по размерам, а вот эти в упор не хотят растягиваться.
Уже и SizePolicy ставил и Stretch. Ничего не помогает.

Привожу код
Код:
class OBJECTINSPECTORSHARED_EXPORT QPropertyEditWidget : public QWidget
{
    Q_OBJECT

    QToolButton *   feditButton;
    QToolButton *   fresetButton;
    QWidget     *   fwidget;
    QWidget     *   fcontainer;
    QHBoxLayout *   flayout;

protected:

    void    resizeEvent(QResizeEvent *event);

public:
    explicit QPropertyEditWidget(QWidget *parent = 0);
   
    QWidget *   widget()    const;

    void    setEditable(bool Value = true);
    void    setResatable(bool Value = true);

signals:

    void    editButtonClicked();
    void    resetButtonClicked();
   
public slots:

    void    setWidget(QWidget * Widget);
   
};

Код:
#include <QResizeEvent>
#include "qpropertyeditwidget.h"

QPropertyEditWidget::QPropertyEditWidget(QWidget *parent) :
    QWidget(parent)
{
    fwidget = NULL;

    flayout = new QHBoxLayout(this);
    flayout->setContentsMargins(0,0,0,0);
    flayout->setSpacing(1);

    fcontainer = new QWidget(this);
    fcontainer->setAutoFillBackground(true);

    feditButton = new QToolButton(this);
    feditButton->setIcon(QIcon(":/icons/pencil"));
    feditButton->setMaximumSize(26,26);
    feditButton->setMinimumSize(10,10);
    feditButton->setVisible(false);

    fresetButton = new QToolButton(this);
    fresetButton->setText("*");
    fresetButton->setMaximumSize(10,26);
    fresetButton->setMinimumSize(5,10);
    fresetButton->setVisible(false);

    flayout->addWidget(fcontainer,1);
    flayout->addWidget(feditButton);
    flayout->addWidget(fresetButton);

    setFocusProxy(feditButton);
    setLayout(flayout);
    connect(feditButton,SIGNAL(clicked()),this,SIGNAL(editButtonClicked()));
    connect(fresetButton,SIGNAL(clicked()),this,SIGNAL(resetButtonClicked()));
}

QWidget *QPropertyEditWidget::widget() const
{
    return fwidget;
}

void QPropertyEditWidget::setEditable(bool Value)
{
    feditButton->setVisible(Value);
    updateGeometry();
}

void QPropertyEditWidget::setResatable(bool Value)
{
    fresetButton->setVisible(Value);
    updateGeometry();
}

void QPropertyEditWidget::setWidget(QWidget *Widget)
{
    if(fwidget!=Widget)
    {
        if(fwidget)
        {
            fwidget->setParent(NULL);
        }
        fwidget = Widget;
        if(fwidget)
        {
            fwidget->setParent(fcontainer);
            updateGeometry();
        }
    }
}

//Это для отладки, так работает (не это же костыли... + не учитываются размеры 2х кнопок)
void QPropertyEditWidget::resizeEvent(QResizeEvent * event)
{
    if(fwidget)
        fwidget->setGeometry(0,0,event->size().width(),event->size().height());
}

А вот как создаю в делегате
Код:
QWidget *CObjectInspectorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    Q_UNUSED(option)
...
if(currentProperty.isEnumType())
            {
                QPropertyEditWidget *   enumEditWidget = new QPropertyEditWidget(parent);
                enumEditWidget->setResatable(currentProperty.isResettable());
                QMetaEnum       currentEnumerator = currentProperty.enumerator();
                QComboBox   *   comboBox = new QComboBox();
                //comboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
                comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
                for(int i=0;i<currentEnumerator.keyCount();i++)
                {
                    comboBox->addItem(currentEnumerator.key(i));
                }
                connect(comboBox,SIGNAL(currentIndexChanged(QString)),this,SLOT(setStringValue(QString)));
                connect(enumEditWidget,SIGNAL(resetButtonClicked()),this,SLOT(resetProperty()));
                enumEditWidget->setWidget(comboBox);
                return  enumEditWidget;
            }

Вот что получаем в результате ...


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 21, 2013, 18:13
Однако ошибся, все виджеты так рисуются с неправильными размерами (QSpinBox например)...
Я подозреваю что то недоделал с лейаутом, но не пойму что конкретно.


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: GreatSnake от Май 21, 2013, 18:19
Не видно что такое CObjectInspectorDelegate?
Скорее всего у него отсутствует updateEditorGeometry().


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 22, 2013, 12:08
updateEditorGeometry есть, в нем просто задается виджету размер. не помогло.


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: GreatSnake от Май 22, 2013, 12:21
QPropertyEditWidget::setWidget(QWidget *Widget) на самом деле не помещает Widget в лэйаут.


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 22, 2013, 16:47
Вот выкладваю исходники PropertyEditor

Код:
class OBJECTINSPECTORSHARED_EXPORT QPropertyEditWidget : public QWidget
{
    Q_OBJECT

    QToolButton *   feditButton;
    QToolButton *   fresetButton;
    QWidget     *   fwidget;
    QWidget     *   fcontainer;
    QHBoxLayout *   flayout;

protected:

    void    resizeEvent(QResizeEvent *event);
    void    recalculate();

public:
    explicit QPropertyEditWidget(QWidget *parent = 0);
   
    QWidget *   widget()    const;

    void    setEditable(bool Value = true);
    void    setResatable(bool Value = true);

signals:

    void    editButtonClicked();
    void    resetButtonClicked();
   
public slots:

    void    setWidget(QWidget * Widget);
   
};

Код:
#include <QResizeEvent>
#include "qpropertyeditwidget.h"

QPropertyEditWidget::QPropertyEditWidget(QWidget *parent) :
    QWidget(parent)
{
    fwidget = NULL;

    flayout = new QHBoxLayout(this);
    flayout->setContentsMargins(0,0,0,0);
    flayout->setSpacing(1);

    fcontainer = new QWidget(this);
    fcontainer->setAutoFillBackground(true);

    feditButton = new QToolButton(this);
    feditButton->setIcon(QIcon(":/icons/pencil"));
    feditButton->setMaximumSize(26,26);
    feditButton->setMinimumSize(10,10);
    feditButton->setVisible(false);

    fresetButton = new QToolButton(this);
    fresetButton->setText("*");
    fresetButton->setMaximumSize(10,26);
    fresetButton->setMinimumSize(5,10);
    fresetButton->setVisible(false);

    flayout->addWidget(fcontainer,1);
    flayout->addWidget(feditButton);
    flayout->addWidget(fresetButton);

    setFocusProxy(feditButton);
    setLayout(flayout);
    connect(feditButton,SIGNAL(clicked()),this,SIGNAL(editButtonClicked()));
    connect(fresetButton,SIGNAL(clicked()),this,SIGNAL(resetButtonClicked()));

    recalculate();
}

QWidget *QPropertyEditWidget::widget() const
{
    return fwidget;
}

void QPropertyEditWidget::setEditable(bool Value)
{
    feditButton->setVisible(Value);
    recalculate();
}

void QPropertyEditWidget::setResatable(bool Value)
{
    fresetButton->setVisible(Value);
    recalculate();
}

void QPropertyEditWidget::setWidget(QWidget *Widget)
{
    if(fwidget!=Widget)
    {
        if(fwidget)
        {
            fwidget->setParent(NULL);
        }
        fwidget = Widget;
        if(fwidget)
        {
            fwidget->setParent(fcontainer);
            recalculate();
        }
    }
}


void QPropertyEditWidget::resizeEvent(QResizeEvent * event)
{
    Q_UNUSED(event)

        recalculate();
}

void QPropertyEditWidget::recalculate()
{
    if(fwidget)
    {
        int w = width();
        if(fresetButton->isVisibleTo(this))
            w-=fresetButton->width();
         if(feditButton->isVisibleTo(this))
            w-=feditButton->width();
        fwidget->resize(w,height());
    }
}

С принудительной recalculate() все заработало как надо, но почему дочерний виджет fwidget не изменяет свои размеры согласно размерам fcontainer я так и не понял.
Задавал разные sizePolicy как для fwidget так и для fconatiner - эффекта не было.


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 22, 2013, 17:58
странно QComboBox все равно проглючивает сначала, пока не вызывается первый resize(). А вот другие виджеты нормально подгоняют свои размеры.


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 22, 2013, 18:04
еще заметил, что комбобокс при первом показе сначала растягивается как надо, но сразу же меняет свой под размер содержимого (хотя я это ему явно запретил делать)...
кто подскажет как побороть эту гадость?


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: GreatSnake от Май 22, 2013, 18:14
QPropertyEditWidget::setWidget(QWidget *Widget) на самом деле не помещает Widget в лэйаут.
Ещё раз повторяю - Widget не помещается в лэйаут установленный в QPropertyEditWidget, поэтому при изменении геометрии QPropertyEditWidget-а его геометрия не учитывается.
Зачем делать всякие recalculate() и вызывать его в resizeEvent(), когда достаточно было сделать  QPropertyEditWidget::layout()->insertWidget( 0, Widget )???

PS: может имеет смысл сначала освоить Управление компоновкой (http://www.doc.crossplatform.ru/qt/4.7.x/layout.html)?


Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: Fregloin от Май 23, 2013, 09:13
Ваш совет не помог.

Зато помогло следующее
Код:
QComboBox   *   comboBox = new QComboBox();
comboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);

Дальше как по коду ...






Название: Re: Вложеные лейауты в делегатах и некоректный размер QComboBox,QLineEdit
Отправлено: GreatSnake от Май 23, 2013, 10:08
Ваш совет не помог.

Зато помогло следующее
Код:
QComboBox   *   comboBox = new QComboBox();
comboBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);

Что-то слабо верится, т.к. QSizePolicy используется только в случае помещения виджета в лэйаут, чего у тебя не наблюдается.