-1

I have a custom layout BoardLayout, which inherits QLayout. It is written in analogy to BorderLayout example (https://doc.qt.io/qt-5/qtwidgets-layouts-borderlayout-example.html), with a following setGeometry() method:

void BoardLayout::setGeometry(const QRect &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});
        }
    }
}

It also has an altered BoardLayout::calculateSize method, but since the widget it is applied on is a centralWidget of a window, it probably does not matter; this method is also not called in the problematic part of runtime).

I set this layout for a window, and added to it (in the position of Board) an instance of a BoardView class, (BoardView inherits QGraphicsView):

auto lt = new BoardLayout();
setLayout(lt);
    
board_view_ = new BoardView(config_, this);
lt->addWidget(board_view_, BoardLayout::Board);

I did not add any other objects into the layout, so it could maybe be written simpler, but the structure and the API of BoardLayout are kept the same to maintain the analogy with the working example.

This BoardView class has an overriden method resizeEvent, in order to keep the inside objects to occupy all the space of the viewport by changing scale each time it is resized:

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);
    }
}

The problem is that, in such a setup, when I start the app, BoardView::resizeEvent is called non-stop with a pair of different QSize's, one after another, even though the window (and hence the containing widget, that has the BoardLayout as a layout) is not being resized. During this, BoardLayout::setGeometry is not called, so I don't get where this resize events could come from.

Also, if I delete scale(k, k); from BoardView::resizeEvent it works normally as expected (resize events only come after resizing the window, triggered by e->item->setGeometry in BoardLayout::setGeometry).

Same thing happens if I change the layout to one of the standard ones, or choose some different rectangles for e->item->setGeometry({50, 50, d, d});.

So, I would be grateful if someone could explain what is wrong with this architecture, and how are the unnecessary resizeEvents triggered.

user87035
  • 11
  • 3

1 Answers1

0

It turns out that the events were issued by two QScrollBars that appear when viewport is too small for the scene. However it only happens when objects are on the edge between fitting and not fitting into the scene and the scrollbars actually appear and disappear and something complicated happens in the event cycle that I cannot understand because it is hard to find the docs on what happens and when.

However, if we change the scaling coefficient so that scrollbars would either always appear, or always not, everything works fine. It may be that it is not a correct solution and only works in practice because some events always get processed fast enough, which is not guaranteed.

user87035
  • 11
  • 3