PDA

View Full Version : Resize QGraphicsScene to the view size at startup



lni
10th September 2015, 15:02
Hi,

I want to resize the QGraphicsScene to fit the view the first time when the view is shown. However, I can't get it to work.

I re-implement QWidget::showEvent(), but the first time it gives me wrong geometry.

Then I re-implement as follwoing, which give warning from time to time about "recursive paint" (not all the times).

How can I do what I need? Thanks!



MyWidget::paintEvent( QPaintEvent* event )
{
static bool firstTime( true );
if ( firstTime ) {
fitSceneToView();
firstTime = false;
}

QWidget::paintEvent( event );

}



If I do it in QWidget::event() when QEvent::PolishRequest occurs, it is too late, causing widget to blink.

anda_skoa
10th September 2015, 15:52
1) Don't modify anything inside paintEvent().

2) Have you fetched the geometry in showEvent() after passing the event to the base class?

Cheers,
_

lni
10th September 2015, 16:46
1) Don't modify anything inside paintEvent().

2) Have you fetched the geometry in showEvent() after passing the event to the base class?

Cheers,
_

I did as following, and the 1st showEvent gives wrong geometry (very small), the 2nd time the geometry is correct.




void MyWidget::showEvent( QShowEvent* event )
{
static bool firstTime( true );
if ( firstTime ) {

setupSceneSize( geometry() );

firstTime = false;
}

QWidget::showEvent( event );
}

anda_skoa
10th September 2015, 17:32
So the answer to my question is "no".

So my next question would be: why do you expect the widget to have finished reacting to an event that it hasn't gotten a chance to process yet?

Cheers,
_

lni
10th September 2015, 20:09
So the answer to my question is "no".

So my next question would be: why do you expect the widget to have finished reacting to an event that it hasn't gotten a chance to process yet?

Cheers,
_

I thought I did fetch the geometry in the code.

In setupSceneSize( geometry() ), I got the geometry, pass it to the function, where it tries to set the size of the scene. The 1st time it give wrong geometry.

It doesn't matter if I call QWidget::showEvent before or after fetching the geometry, same wrong geometry in 1st time.

anda_skoa
10th September 2015, 20:46
It doesn't matter if I call QWidget::showEvent before or after fetching the geometry, same wrong geometry in 1st time.

Well, it would definitely not work to fetch it before passing on the event, since then the event has not happened yet as far as the object is concerned.

You could check if you have more luck with the viewport's show event though.

Cheers,
_

lni
11th September 2015, 04:29
I re-implement QGraphicsView::event( QEvent* ) trying to print out the geometry as follows:


virtual bool event ( QEvent * evnt ) {
bool result = QGraphicsView::event( evnt );
qDebug() << "event type =" << evnt->type() << ", size =" << geometry().size();
return result;
}


Here is what I got

event type = 109 , size = QSize(100, 30)
event type = 69 , size = QSize(100, 30)
event type = 69 , size = QSize(100, 30)
event type = 100 , size = QSize(100, 30)
event type = 170 , size = QSize(100, 30)
event type = 97 , size = QSize(100, 30)
event type = 39 , size = QSize(100, 30)
event type = 70 , size = QSize(100, 30)
event type = 70 , size = QSize(100, 30)
event type = 70 , size = QSize(100, 30)
event type = 75 , size = QSize(100, 30)
event type = 69 , size = QSize(100, 30)
event type = 39 , size = QSize(100, 30)
event type = 97 , size = QSize(100, 30)
event type = 97 , size = QSize(100, 30)
event type = 39 , size = QSize(100, 30)
event type = 100 , size = QSize(100, 30)
event type = 68 , size = QSize(100, 30)
event type = 68 , size = QSize(150, 75)
event type = 13 , size = QSize(150, 75)
event type = 14 , size = QSize(150, 75)
event type = 17 , size = QSize(150, 75)
event type = 26 , size = QSize(150, 75)
event type = 18 , size = QSize(150, 75)
event type = 8 , size = QSize(150, 75)
event type = 68 , size = QSize(150, 75)
event type = 68 , size = QSize(1169, 817)
event type = 14 , size = QSize(1169, 817)
event type = 17 , size = QSize(1169, 817)
event type = 9 , size = QSize(1169, 817)
event type = 67 , size = QSize(1169, 817) // <---- ChildInsertedRequest for QT3_SUPPORT
event type = 12 , size = QSize(1169, 817) // <---- QPaintEvent
event type = 74 , size = QSize(1169, 817)
event type = 43 , size = QSize(1169, 817)
event type = 43 , size = QSize(1169, 817)
event type = 71 , size = QSize(1169, 817)
event type = 71 , size = QSize(1169, 817)
event type = 43 , size = QSize(1169, 817)
event type = 43 , size = QSize(1169, 817)
event type = 76 , size = QSize(1169, 817)
event type = 71 , size = QSize(1169, 817)
event type = 71 , size = QSize(1169, 817)
event type = 43 , size = QSize(1169, 817)
event type = 43 , size = QSize(1169, 817)

The correct size is QSize(1169, 817) . The event that gets this size in first time is type 67. But I look at Qt codes, it is defined as



#ifdef QT3_SUPPORT
ChildInsertedRequest = 67, // send ChildInserted compatibility events to receiver
ChildInserted = 70, // compatibility child inserted
LayoutHint = 72, // compatibility relayout request
#endif


Next is type 12, which is QPaintEvent.

So it looks like I will have to intercept paintEvent( QPaintEvent* ) to set the scene size, but then ocasionally I got recursive painting warning...



virtual void paintEvent( QPaintEvent* event ) {

if ( m_firstTime ) {
fitView(); // call fitView to set the scene size to fit the view
m_firstTime = false;
}

QGraphicsView::paintEvent( event );

}

anda_skoa
11th September 2015, 07:45
I re-implement QGraphicsView::event( QEvent* ) trying to print out the geometry as follows:

You could also check the viewport events, the QGrahicsView is a QAbstractScrollArea and thus has a view port



event type = 68 , size = QSize(1169, 817)
event type = 14 , size = QSize(1169, 817)
event type = 17 , size = QSize(1169, 817)
event type = 9 , size = QSize(1169, 817)
event type = 67 , size = QSize(1169, 817) // <---- ChildInsertedRequest for QT3_SUPPORT
event type = 12 , size = QSize(1169, 817) // <---- QPaintEvent

The correct size is QSize(1169, 817) . The event that gets this size in first time is type 67.

Interesting, your posted list says it is 68.


Next is type 12, which is QPaintEvent.

Interesting, you posted list says it is 14, which is Resize.



So it looks like I will have to intercept paintEvent( QPaintEvent* ) to set the scene size, but then ocasionally I got recursive painting warning...



virtual void paintEvent( QPaintEvent* event ) {

if ( m_firstTime ) {
fitView(); // call fitView to set the scene size to fit the view
m_firstTime = false;
}

QGraphicsView::paintEvent( event );

}

If you do that you need to make sure that fitView() does not change anything in the view or the scene, see earlier in this thread.
If fitView() does change something, make at least sure it cannot be called twice.
Better yet call it also delayed.

Cheers,
_

lni
11th September 2015, 10:05
Yes, type 68 sees the correct geometry first, but that event type also occurs earlier, so I can't use that type to set up my scene size. Same as type 14. And type 9 is FocusOut, I don't think that event type can be used for my purpose...

See these output lines:

event type = 68 , size = QSize(150, 75)
event type = 14 , size = QSize(150, 75)

The problem is recursive painting only occurs occasionally, making it very difficult to debug....

d_stranz
11th September 2015, 16:36
The problem is recursive painting only occurs occasionally, making it very difficult to debug....

Recursive painting will occur any time you do anything in the paintEvent() which triggers an update - resizing, moving, changing graphical properties or almost *anything* else about the appearance the current widget or its children. Don't do it. The paint event should be treated as exactly what it implies: to paint the widget's contents as they existed at the moment the call is made.

That your recursive repainting occurs only infrequently is pure luck, probably based on timing issues in your own development environment. Move to release mode, move to another faster / slower PC, and you'll see a different and unpredictable set of issues. Don't do it.

I successfully use showEvent() and resizeEvent() all the time to change scene geometry to match the size of the widget. The resize event will occur multiple times before the widget is shown as a result of the layout system doing its job. You simply check the isVisible() flag before taking any action. It will be false until after the widget is shown.

lni
12th September 2015, 06:32
I think I find out the problem. It should be a Qt bug

My drawing area is a Mdi subwindow. I call showMaximized() to show the subwindow, which gives me two show events, I have to check isMaximized() to get the correct geometry.

However, what if the subwindow is not shown using showMaximized, says, first it calls QMdiSubWindow::resize( ... ), then call show(), then my code would break again.

The problem is within showMaximized(), which call setWindowState( ... ), this triggers showEvent even before show() is called.

Simply comment out all show methods in following examples, and use w.setWindowState( Qt::WindowMaximized ), the subwindow will still be shown.




#include <QApplication>
#include <QMdiSubWindow>
#include <QMdiArea>
#include <QDebug>

class MyMdiSubWindow : public QMdiSubWindow {

protected:

virtual void showEvent( QShowEvent* event ) {
QWidget::showEvent( event );

qDebug() << "showEvent: isVisible =" << isVisible()
<< ", isMaximized =" << isMaximized()
<< ", geom =" << geometry();
}

};

int main( int argc, char** argv )
{
QApplication app( argc, argv );

QMdiArea area;
area.resize( 500, 500 );
area.show();

MyMdiSubWindow w;
area.addSubWindow( &w );

//w.resize( 100, 100 );
//w.show();
//w.showNormal();

//w.setWindowState( Qt::WindowMaximized );

w.showMaximized();

return app.exec();

}

lni
14th September 2015, 06:27
How do I report this bug? I switch to Qt 5.5.0, the same error occurs too.

"If the window is not visible (i.e. isVisible() returns false), the window state will take effect when show() is called." is NOT true for my test code.

anda_skoa
14th September 2015, 09:23
https://bugreports.qt.io/secure/Dashboard.jspa

Cheers,
_