Как сохранить соотношение сторон виджетов в Qt?
-
19-08-2019 - |
Вопрос
Как можно сохранить соотношение сторон виджетов в Qt и как насчет центрирования виджета?
Решение
Вам не нужно реализовывать свой собственный менеджер макета. Вы можете сделать с наследованием QWidget
и переопределением
int QWidget::heightForWidth( int w ) { return w; }
чтобы оставаться на месте. Однако heightForWidth()
не работает на окнах верхнего уровня на X11, поскольку, очевидно, протокол X11 этого не поддерживает. Что касается центрирования, вы можете передать Qt::AlignCenter
в качестве третьего параметра QBoxLayout::addWidget()
или пятого параметра QGridLayout::addWidget()
.
Примечание: . По крайней мере, в более новых версиях Qt QWidget больше не имеет heightForWidth
или widthForHeight
(поэтому их нельзя переопределить), и поэтому setWidthForHeight(true)
или setHeightForWidth(true)
действуют только для потомков QGraphicsLayout .
Другие советы
Правильный ответ — создать собственный менеджер макетов.Это возможно путем подкласса QLayout.
Методы, реализуемые при создании подкласса QLayout
- void addItem (элемент QLayoutItem*);
- Добавляет элемент в макет.
- интервал счетчика () константа;
- Возвращает количество элементов.
- QLayoutItem* itemAt(int index) const;
- Возвращает ссылку на элемент по индексу или 0, если ее нет.
- QLayoutItem* takeAt(int index);
- Берет и возвращает элемент из макета из индекса или возвращает 0, если его нет.
- Qt::Ориентации ExpandingDirections() const;
- Возвращает направления расширения макетов.
- bool hasHeightForWidth() const;
- Сообщает, обрабатывает ли макет высоту для расчета ширины.
- QSize minSize() const;
- Возвращает минимальный размер макета.
- void setGeometry (const QRect& rect);
- Задает геометрию макета и элементов внутри него.Здесь вам придется сохранить соотношение сторон и выполнить центрирование.
- QSize sizeHint() const;
- Возвращает предпочтительный размер макета.
дальнейшее чтение
Вызов resize()
изнутри resizeEvent()
никогда не работал для меня хорошо - в лучшем случае это вызовет мерцание, поскольку окно изменено в два раза (как у вас), в худшем - бесконечный цикл.
Я думаю, что " правильный " Способ поддержания фиксированного соотношения сторон заключается в создании пользовательского макета. Вам придется переопределить только два метода, QLayoutItem::hasHeightForWidth()
и QLayoutItem::heightForWidth()
.
В моем случае переопределение heightForWidth () не работает. И для кого-то было бы полезно получить рабочий пример использования события resize.
Сначала подкласс qObject для создания фильтра. Подробнее о фильтрах событий. р>
class FilterObject:public QObject{
public:
QWidget *target = nullptr;//it holds a pointer to target object
int goalHeight=0;
FilterObject(QObject *parent=nullptr):QObject(parent){}//uses QObject constructor
bool eventFilter(QObject *watched, QEvent *event) override;//and overrides eventFilter function
};
Тогда функция eventFilter. Этот код должен быть определен вне определения FilterObject, чтобы предотвратить предупреждение. Благодаря этому ответу.
bool FilterObject::eventFilter(QObject *watched, QEvent *event) {
if(watched!=target){//checks for correct target object.
return false;
}
if(event->type()!=QEvent::Resize){//and correct event
return false;
}
QResizeEvent *resEvent = static_cast<QResizeEvent*>(event);//then sets correct event type
goalHeight = 7*resEvent->size().width()/16;//calculates height, 7/16 of width in my case
if(target->height()!=goalHeight){
target->setFixedHeight(goalHeight);
}
return true;
};
А затем в основном коде создайте FilterObject и установите его в качестве прослушивателя EventFilter для целевого объекта. Благодаря этому ответу.
FilterObject *filter = new FilterObject();
QWidget *targetWidget = new QWidget();//let it be target object
filter->target=targetWidget;
targetWidget->installEventFilter(filter);
Теперь фильтр будет получать все события targetWidget и устанавливать правильную высоту при изменении размера.