Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: ритт от Июль 27, 2008, 03:22



Название: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: ритт от Июль 27, 2008, 03:22
написал лэйоут, функционально похожий на examples/layouts/flowlayout.
метод minimumSize, ответственный за минимальный размер, возвращает максимальные ширину и высоту виджетов из списка + маржины
Код:
QSize FlowLayout::minimumSize() const
{
    QSize size;
    QLayoutItem *item;
    foreach (item, itemList)
        size = size.expandedTo(item->minimumSize());

    size += QSize(2*margin(), 2*margin());
    return size;
}
но если подсунуть этот лэйут виджету, на котором расположены ещё какие-нибудь виджеты, некорректное вычисление минимального размера сразу станет заметно - виджеты фловлэйоута будут пересекаться с виджетами на "родных" лэйоутах (которые нормально рассчитывают размеры)

в этом как раз и проблема - никак не удаётся реализовать правильный обсчёт. когда опрашивается minimumSize, геометрия уже сброшена и мы просто не знаем какие ширина/высота были удовлетворительными секунду назад чтобы вернуть их в качестве временного минимального размера.
если, например, минимальный размер может измениться в зависимости от размера, переданного в setGeometry, то как уведомить виджет о том, что его минимальный размер изменился и виджет должен соответствующим образом пересчитать собственную геометрию?! parentWidget()->updateGeometry() не помогает...апдейт, инвалидэйт, постИвент - чего я только уже не пробовал.
не могу сообразить каким макаром минимальный размер учитывается для верхнего виджета при каждом ресайзе, а для дочернего - лишь по праздникам...рррррррр :(


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: lit-uriy от Июль 27, 2008, 11:48
Цитировать
метод minimumSize, ответственный за минимальный размер, возвращает максимальные ширину и высоту виджетов из списка + маржины
в статье "Классы компоновки (http://crossplatform.ru/documentation/qtdoc4.3/layout.php)" написано:
"sizeHint() и minimumSize() обычно имеют очень похожие реализации. Размеры, возвращаемые обеими функциями, должны включать spacing(), но не должны включать margin(). "


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: ритт от Июль 27, 2008, 15:04
у троллей сайзХинт, минимумСайз и максимумСайз включают margin

Код:
void QBoxLayoutPrivate::setupGeom()
//...
    minSize = QSize(minw, minh);
    maxSize = QSize(maxw, maxh).expandedTo(minSize);
    sizeHint = QSize(hintw, hinth).expandedTo(minSize).boundedTo(maxSize);

    q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
    int left, top, right, bottom;
    effectiveMargins(&left, &top, &right, &bottom);
    QSize extra(left + right, top + bottom);

    minSize += extra;
    maxSize += extra;
    sizeHint += extra;
//...

QSize QBoxLayout::sizeHint() const
{
    Q_D(const QBoxLayout);
    if (d->dirty)
        const_cast<QBoxLayout*>(this)->d_func()->setupGeom();
    return d->sizeHint;
}

но это к теме не относится. вопрос остаётся открытым: как лэйуоту заставить виджет пересчитать ограничивающие размеры?


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: Alex03 от Июль 28, 2008, 11:28
А что за виджеты внутри Вашего лэйаута?
Воpвращают ли они корректный minimumSize?
Может так:
Код:
    foreach (item, itemList)
    {
        size = size.expandedTo(item->minimumSize());
        size = size.expandedTo(item->minimumSizeHint());
    }
Да и ИМХО не логично это, это минимальные размеры по каждой оси, но не совместные.
Но видимо дело не в этом...

Этот лэйаут засунут в виджет, а виджет в другой лэйаут или как?
Константин, минимальный примерчик компилябельный забубень, совместно поковыряемся. :)

С вложенными лэйаутами "особенностей" тоже хватает...
А уж с hasHeightForWidth()/heightForWidth(int width) тожа не всё гладко.


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: ритт от Июль 28, 2008, 14:26
>  size = size.expandedTo(item->minimumSizeHint());
у QLayoutItem нет метода minimumSizeHint
действительно, это нелогично, но работает именно так, как требуется...пока этот лэйоут установлен на топ-виджет

минимальный пример - examples/layouts/flowlayout.
попробуй заменить
Код:
Window::Window()
{
    FlowLayout *flowLayout = new FlowLayout;

    flowLayout->addWidget(new QPushButton(tr("Short")));
    flowLayout->addWidget(new QPushButton(tr("Longer")));
    flowLayout->addWidget(new QPushButton(tr("Different text")));
    flowLayout->addWidget(new QPushButton(tr("More text")));
    flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
    setLayout(flowLayout);

    setWindowTitle(tr("Flow Layout"));
}
на
Код:
Window::Window()
{
QWidget* widget = new QWidget();
    FlowLayout *flowLayout = new FlowLayout;

    flowLayout->addWidget(new QPushButton(tr("Short")));
    flowLayout->addWidget(new QPushButton(tr("Longer")));
    flowLayout->addWidget(new QPushButton(tr("Different text")));
    flowLayout->addWidget(new QPushButton(tr("More text")));
    flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
    widget->setLayout(flowLayout);

QGridLayout* layout = new QGridLayout;
    layout->addWidget(widget, 0, 0);
    layout->addWidget(new QPushButton(tr("Even longer button text")), 1, 1);
    setLayout(layout);

    setWindowTitle(tr("Flow Layout"));
}
если ничего более не менять, баттоны из фловлэйоута при ресайзе поползут на область следующей строки гридлэйоута. если у фловлэйоута в минимумСайз учитывать высотуДляШирины, эта высота зафиксируется и при ресайзе высоту нельзя будет установить меньше, хотя фактическая высота уменьшилась


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: Alex03 от Июль 29, 2008, 06:32
минимальный пример - examples/layouts/flowlayout.
попробуй заменить на ....
ХМ... Работает нормально. Qt 4.3.3 Win XP.

Так тоже всё ОК:
Код:
Window::Window()
{
//    QWidget* widget = new QWidget();
    FlowLayout *flowLayout = new FlowLayout;

    flowLayout->addWidget(new QPushButton(tr("Short")));
    flowLayout->addWidget(new QPushButton(tr("Longer")));
    flowLayout->addWidget(new QPushButton(tr("Different text")));
    flowLayout->addWidget(new QPushButton(tr("More text")));
    flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
//    widget->setLayout(flowLayout);

    QGridLayout* layout = new QGridLayout;
//    layout->addWidget(widget, 0, 0);
    layout->addLayout(flowLayout, 0, 0);
    layout->addWidget(new QPushButton(tr("Even longer button text")), 1, 1);
    setLayout(layout);

    setWindowTitle(tr("Flow Layout"));
}


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: ритт от Июль 29, 2008, 07:29
блиаааааа...иптить!!!
попробуй в этом же примере сделать Виндов наследником кумэйнвиндов
Код:
class Window : public QMainWindow
{
//...snip
//...unchanged

QWidget* cw = new QWidget();
cw->setLayout(layout);
setCentralWidget(cw);

    setWindowTitle(tr("Flow Layout"));
}

ну, или даже проще - с минимальными изменениями:
Код:
{
    QWidget* widget = new QWidget();
    FlowLayout *flowLayout = new FlowLayout;

    flowLayout->addWidget(new QPushButton(tr("Short")));
    flowLayout->addWidget(new QPushButton(tr("Longer")));
    flowLayout->addWidget(new QPushButton(tr("Different text")));
    flowLayout->addWidget(new QPushButton(tr("More text")));
    flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
    widget->setLayout(flowLayout);

setCentralWidget(widget);

    setWindowTitle(tr("Flow Layout"));
}


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: Alex03 от Июль 29, 2008, 08:14
Угу... Глючит...
В файлах
  • qdockarealayout.cpp
  • qdockarealayout_p.h
  • qmainwindowlayout.cpp
  • qmainwindowlayout_p.h
  • qmainwindow.cpp
  • qmainwindow.h
нет упоминаний про heightForWidth. :(

Такая вот багофича.... :( :( :(


Название: Re: QLayout + minimumSize, изменяющийся динамически = рак мозга
Отправлено: ритт от Июль 29, 2008, 16:12
классно! обалдеть...
я на это два вечера угрохал и безрезультатно :(
наклепаю репорт и потом отпишусь