Бесконечные вызовы QGraphicsView::resizeEvent

#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, которые появляются, когда область просмотра слишком мала для сцены. Однако это происходит только тогда, когда объекты находятся на грани между подгонкой и не подгонкой к сцене, и полосы прокрутки действительно появляются и исчезают, и в цикле событий происходит что-то сложное, чего я не могу понять, потому что трудно найти документы о том, что происходит и когда.

Однако, если мы изменим коэффициент масштабирования так, чтобы полосы прокрутки либо всегда появлялись, либо всегда нет, все работает нормально. Возможно, это неправильное решение и работает только на практике, потому что некоторые события всегда обрабатываются достаточно быстро, что не гарантируется.