#qt #qgraphicsview #qlayout #qevent
#qt #qgraphicsview #qlayout #qevent
Вопрос:
У меня есть пользовательский макет BoardLayout, который наследует QLayout. Это написано по аналогии с примером BorderLayout (https://doc.qt.io/qt-5/qtwidgets-layouts-borderlayout-example.html ), с помощью следующего setGeometry()
метода:
void BoardLayout::setGeometry(const QRect amp;rect)
{
QLayout::setGeometry(rect);
int d = qMin(rect.width() - 175, rect.height() - 100);
for (auto e : list) {
if (e->position == Board) {
e->item->setGeometry({50, 50, d, d});
}
}
}
У него также есть измененный BoardLayout::calculateSize
метод, но поскольку виджет, к которому он применяется, является centralWidget
частью окна, это, вероятно, не имеет значения; этот метод также не вызывается в проблемной части времени выполнения).
Я установил этот макет для окна и добавил к нему (в позиции Board
) экземпляр BoardView
класса, ( BoardView
наследуемый QGraphicsView
):
auto lt = new BoardLayout();
setLayout(lt);
board_view_ = new BoardView(config_, this);
lt->addWidget(board_view_, BoardLayout::Board);
Я не добавлял никаких других объектов в макет, поэтому, возможно, его можно было бы написать проще, но структура и API BoardLayout
сохранены неизменными для поддержания аналогии с рабочим примером.
Этот BoardView
класс имеет переопределенный метод resizeEvent
, позволяющий внутренним объектам занимать все пространство окна просмотра, изменяя масштаб при каждом изменении его размера:
void BoardView::resizeEvent(QResizeEvent *event) {
if (event->oldSize().width() == -1) {
qreal k = (qreal)qMin(width(), height()) / ((config_->scene_cell_size 4) * config_->board_size);
scale(k, k);
}
else {
qreal prev_w = event->oldSize().width(), prev_h = event->oldSize().height();
qreal w = event->size().width(), h = event->size().height();
qreal k = qMin(w, h) / qMin(prev_w, prev_h);
scale(k, k);
}
}
Проблема в том, что при такой настройке, когда я запускаю приложение, оно BoardView::resizeEvent
вызывается без остановки с парой разных QSize
‘s, одно за другим, даже если размер окна (и, следовательно, содержащего виджет, который имеет BoardLayout
в качестве макета) не изменяется.
Во время этого BoardLayout::setGeometry
не вызывается, поэтому я не понимаю, откуда могли взяться эти события изменения размера.
Кроме того, если я удаляю scale(k, k);
из BoardView::resizeEvent
, это работает нормально, как и ожидалось (события изменения размера появляются только после изменения размера окна, вызванного e->item->setGeometry
in BoardLayout::setGeometry
).
То же самое произойдет, если я изменю макет на один из стандартных или выберу несколько других прямоугольников для e->item->setGeometry({50, 50, d, d});
.
Итак, я был бы признателен, если бы кто-нибудь мог объяснить, что не так с этой архитектурой, и как вызываются ненужные resizeEvents
.
Ответ №1:
Оказывается, что события были выданы двумя QScrollBar
s, которые появляются, когда область просмотра слишком мала для сцены. Однако это происходит только тогда, когда объекты находятся на грани между подгонкой и не подгонкой к сцене, и полосы прокрутки действительно появляются и исчезают, и в цикле событий происходит что-то сложное, чего я не могу понять, потому что трудно найти документы о том, что происходит и когда.
Однако, если мы изменим коэффициент масштабирования так, чтобы полосы прокрутки либо всегда появлялись, либо всегда нет, все работает нормально. Возможно, это неправильное решение и работает только на практике, потому что некоторые события всегда обрабатываются достаточно быстро, что не гарантируется.