Discussion:
[Interest] Finished resizing a window?
John Weeks
2014-02-24 21:56:01 UTC
Permalink
We have windows in our application that are potentially expensive to repaint, so when the user resizes a window we may need to put off repainting until the resizing is finished. It seems that we don't get mouse down/mouse up events when the user clicks in the window frame/resize grip area, so I can't wait until mouse up.

Is that correct?
Is there a solution to this?

Thanks!

-John Weeks
Thiago Macieira
2014-02-24 22:24:00 UTC
Permalink
Post by John Weeks
We have windows in our application that are potentially expensive to
repaint, so when the user resizes a window we may need to put off
repainting until the resizing is finished. It seems that we don't get mouse
down/mouse up events when the user clicks in the window frame/resize grip
area, so I can't wait until mouse up.
Is that correct?
Is there a solution to this?
That's something entirely controlled by the window manager. Sorry.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
John Weeks
2014-02-24 22:30:29 UTC
Permalink
Post by Thiago Macieira
That's something entirely controlled by the window manager. Sorry.
Thanks, Thiago. That's good to know.

-John
Thiago Macieira
2014-02-25 17:56:00 UTC
Permalink
Post by John Weeks
Post by Thiago Macieira
That's something entirely controlled by the window manager. Sorry.
Thanks, Thiago. That's good to know.
Here's a suggestion: do a delayed repainting after you get a resize event.

If you wait 200 ms before repainting, if the window keeps getting resized, the
delay keeps resetting. So effectively, you won't repaint until the window
settles.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
w***@analog.com
2014-02-25 18:08:34 UTC
Permalink
Post by Thiago Macieira
Post by John Weeks
Post by Thiago Macieira
That's something entirely controlled by the window manager. Sorry.
Thanks, Thiago. That's good to know.
Here's a suggestion: do a delayed repainting after you get a resize event.
If you wait 200 ms before repainting, if the window keeps getting resized, the
delay keeps resetting. So effectively, you won't repaint until the window
settles.
But if the user pauses for more than 200ms
the expensive redraw will commence and annoy.

Perhaps...

Break the redraw up into a number of parts,
each of which takes a relatively short amount of time.

resize() {
partToDraw = 1; // Start over.
cancelAnyExistingTimer();
singleshot(200,timeout());
}

// Draw the parts.
// If a new resize arrives, the process restarts
// in a short amount of time, without having to
// wait for the complete redraw to complete.
timeout() {
drawPart(partToDraw)
if( ++partToDraw != numberOfParts )
singleshot(0,timeout(); // Return to event loop.
}
Jason H
2014-02-25 21:37:18 UTC
Permalink
Have you tried  implementing a layout that has a locking mechanism?
In theory you can get the root layout to not layout until you approve the change? This will produce an unfilled area until you unlock it.



________________________________
From: "***@analog.com" <***@analog.com>
To: ***@qt-project.org
Sent: Tuesday, February 25, 2014 1:08 PM
Subject: Re: [Interest] Finished resizing a window?
Post by Thiago Macieira
Post by John Weeks
Post by Thiago Macieira
That's something entirely controlled by the window manager. Sorry.
Thanks, Thiago. That's good to know.
Here's a suggestion: do a delayed repainting after you get a resize event.
If you wait 200 ms before repainting, if the window keeps getting resized, the
delay keeps resetting. So effectively, you won't repaint until the window
settles.
But if the user pauses for more than 200ms
the expensive redraw will commence and annoy.

Perhaps...

Break the redraw up into a number of parts,
each of which takes a relatively short amount of time.

resize() {
    partToDraw = 1;        // Start over.
    cancelAnyExistingTimer();
    singleshot(200,timeout());
}

// Draw the parts.
// If a new resize arrives, the process restarts
// in a short amount of time, without having to
// wait for the complete redraw to complete.
timeout() {
    drawPart(partToDraw)
    if( ++partToDraw != numberOfParts )
        singleshot(0,timeout();        // Return to event loop.

}
Tony Rietwyk
2014-02-24 23:45:43 UTC
Permalink
Hi John,



I would suggest a short single-shot timer roughly:



resizeEvent

base::resizeEvent

if !mTimer.isRunning

mTimer.start



paintEvent

if !mTimer.isRunning

base::paintEvent



timer slot:

repaint



I'm not sure whether overriding the paintEvent is enough to prevent the
child widgets from painting.



Good luck - please let the group know what you decide with this.



Tony





From: interest-bounces+tony=***@qt-project.org
[mailto:interest-bounces+tony=***@qt-project.org] On Behalf Of
John Weeks
Sent: Tuesday, 25 February 2014 8:56 AM
To: ***@qt-project.org Interest
Subject: [Interest] Finished resizing a window?



We have windows in our application that are potentially expensive to
repaint, so when the user resizes a window we may need to put off repainting
until the resizing is finished. It seems that we don't get mouse down/mouse
up events when the user clicks in the window frame/resize grip area, so I
can't wait until mouse up.



Is that correct?

Is there a solution to this?



Thanks!



-John Weeks
Jason H
2014-02-25 01:46:47 UTC
Permalink
Also, note that the Qt event loop will collapse all pending resizes into one final one. 

You should be able to block updating the layouts until the timer expires. Its been a while but you'll need to subclass the window and don't call the base class resizes until the timer is done.

I don't think the below will work, but like I said, it's been a whole for me working with widgets. 


________________________________
From: Tony Rietwyk <***@rightsoft.com.au>
To: ***@qt-project.org
Sent: Monday, February 24, 2014 6:45 PM
Subject: Re: [Interest] Finished resizing a window?



Hi John,
 
I would suggest a short single-shot timer roughly:
 
resizeEvent
                base::resizeEvent
                if !mTimer.isRunning
                                mTimer.start
 
paintEvent
                if !mTimer.isRunning
                                base::paintEvent
 
timer slot:
                repaint
 
I'm not sure whether overriding the paintEvent is enough to prevent the child widgets from painting.
 
Good luck - please let the group know what you decide with this.
 
Tony
 
 
From:interest-bounces+tony=***@qt-project.org [mailto:interest-bounces+tony=***@qt-project.org] On Behalf Of John Weeks
Sent: Tuesday, 25 February 2014 8:56 AM
To: ***@qt-project.org Interest
Subject: [Interest] Finished resizing a window?
 
We have windows in our application that are potentially expensive to repaint, so when the user resizes a window we may need to put off repainting until the resizing is finished. It seems that we don't get mouse down/mouse up events when the user clicks in the window frame/resize grip area, so I can't wait until mouse up.
 
Is that correct?
Is there a solution to this?
 
Thanks!
 
-John Weeks
 
w***@analog.com
2014-02-25 01:46:33 UTC
Permalink
Post by John Weeks
We have windows in our application that are potentially expensive to repaint, so
when the user resizes a window we may need to put off repainting until the
resizing is finished. It seems that we don't get mouse down/mouse up events when
the user clicks in the window frame/resize grip area, so I can't wait until
mouse up.
Could you use this to watch for (then paint on) the mouse release?

Qt::MouseButtons QApplication::mouseButtons() [static]

Bill
Jason H
2014-02-25 01:50:40 UTC
Permalink
The problem is the window resize does not come from the application, it comes from the OS/Window Manager.



________________________________
From: "***@analog.com" <***@analog.com>
To: ***@qt-project.org
Sent: Monday, February 24, 2014 8:46 PM
Subject: Re: [Interest] Finished resizing a window?
Post by John Weeks
We have windows in our application that are potentially expensive to repaint, so
when the user resizes a window we may need to put off repainting until the
resizing is finished. It seems that we don't get mouse down/mouse up events when
the user clicks in the window frame/resize grip area, so I can't wait until
mouse up.
Could you use this to watch for (then paint on) the mouse release?

    Qt::MouseButtons QApplication::mouseButtons() [static]

Bill
John Weeks
2014-02-25 17:29:51 UTC
Permalink
Right- this is what Thiago meant in his reply to my original posting.

And verified on Mac OS X: before posting, I tried QApplication::mouseButtons() to detect the mouse state, and got false information. The mouse events that drive the resizing aren't getting to Qt at all.

Well, then again, putting a breakpoint in my resize handler, I see this:

0 grafRec::doResizeEvent GrafRecImplementation.cpp 966 0x1011b0247
1 wDataClass::baseDoResizeEvent WM_WinClasses.cpp 1803 0x1010b5f40
2 IgorWindowWdPContentArea::resizeEvent IgorWindowContentArea.cpp 205 0x100a724a6
3 QWidget::event qwidget.cpp 8541 0x108547e4f
4 IgorWindowWdPContentArea::event IgorWindowContentArea.cpp 181 0x100a73225
5 QApplicationPrivate::notify_helper qapplication.cpp 4562 0x1084d520f
6 QApplication::notify qapplication.cpp 4527 0x1084d85f5
7 IgorAppObject::notify IgorAppObject.cpp 537 0x100a48d4d
8 QCoreApplication::notifyInternal qcoreapplication.cpp 949 0x109aefa2a
9 QCoreApplication::sendEvent qcoreapplication.h 231 0x10003be39
10 QWidgetPrivate::setGeometry_sys_helper qwidget_mac.mm 4624 0x10844af89
11 QWidgetPrivate::setGeometry_sys qwidget_mac.mm 4556 0x10844b7c8
12 QWidget::setGeometry qwidget.cpp 6974 0x108543a71
13 QWidget::setGeometry qwidget.h 1018 0x1085141ba
14 QWidgetItem::setGeometry qlayoutitem.cpp 490 0x108517855
15 QGridBox::setGeometry qgridlayout.cpp 85 0x1085093ae
16 QGridLayoutPrivate::distribute qgridlayout.cpp 964 0x108507411
17 QGridLayout::setGeometry qgridlayout.cpp 1460 0x108507534
18 QLayoutPrivate::doResize qlayout.cpp 679 0x108513721
19 QLayout::widgetEvent qlayout.cpp 703 0x108513dc9
20 QApplicationPrivate::notify_helper qapplication.cpp 4553 0x1084d51d9
21 QApplication::notify qapplication.cpp 4527 0x1084d85f5
22 IgorAppObject::notify IgorAppObject.cpp 537 0x100a48d4d
23 QCoreApplication::notifyInternal qcoreapplication.cpp 949 0x109aefa2a
24 QCoreApplication::sendSpontaneousEvent qcoreapplication.h 234 0x10843d6cf
25 qt_sendSpontaneousEvent qapplication.cpp 5560 0x1084d4770
26 -[QCocoaWindowDelegate syncSizeForWidget:toSize:fromSize:] qcocoawindowdelegate_mac.mm 139 0x10845d1bd
27 -[QCocoaWindowDelegate windowDidResize:] qcocoawindowdelegate_mac.mm 219 0x10845cd68
28 _nsnote_callback 0x7fff868e6ad5
29 __CFXNotificationPost 0x7fff88f6cfd0
30 _CFXNotificationPostNotification 0x7fff88f59548
31 -[NSNotificationCenter postNotificationName:object:userInfo:] 0x7fff868dda36
32 -[NSWindow _setFrameCommon:display:stashSize:] 0x7fff807d284a
33 -[NSTitledFrame resizeWithEvent:] 0x7fff80d79845
34 -[NSTitledFrame mouseDown:] 0x7fff809ec255
35 -[NSThemeFrame mouseDown:] 0x7fff809ec1bb
36 -[NSWindow sendEvent:] 0x7fff808ea3a7
37 -[QCocoaWindow sendEvent:] qcocoasharedwindowmethods_mac_p.h 183 0x10845a01b
38 -[NSApplication sendEvent:] 0x7fff8081fafa
39 -[QNSApplication sendEvent:] qcocoaapplication_mac.mm 186 0x1084604b7
40 -[NSApplication run] 0x7fff807b66de
41 QEventDispatcherMac::processEvents qeventdispatcher_mac.mm 615 0x10846d37a
42 QEventLoop::processEvents qeventloop.cpp 149 0x109aec3ca
43 QEventLoop::exec qeventloop.cpp 204 0x109aec61c
44 QCoreApplication::exec qcoreapplication.cpp 1221 0x109af03a0
45 QApplication::exec qapplication.cpp 3823 0x1084d8630
46 main IgorQtMain.cpp 497 0x101f0fd77

The lines at 39 and 37 are Qt code where the NSEvent type is 1, a mouse-down event. So Qt does have the information, but chooses not to use it. I haven't looked at Windows, and we're not yet in a position to look at Linux, so I don't know how it works there.

I was looking at writing a bit of Cocoa code (yuck) to catch NSWindowWillStartLiveResizeNotification and NSWindowDidEndLiveResizeNotification, but a QTimer would be easier. The square brackets are in the right places, and it works on Windows, too.
Post by Jason H
The problem is the window resize does not come from the application, it comes from the OS/Window Manager.
Sent: Monday, February 24, 2014 8:46 PM
Subject: Re: [Interest] Finished resizing a window?
Post by John Weeks
We have windows in our application that are potentially expensive to repaint, so
when the user resizes a window we may need to put off repainting until the
resizing is finished. It seems that we don't get mouse down/mouse up events when
the user clicks in the window frame/resize grip area, so I can't wait until
mouse up.
Could you use this to watch for (then paint on) the mouse release?
Qt::MouseButtons QApplication::mouseButtons() [static]
Bill
_______________________________________________
Interest mailing list
http://lists.qt-project.org/mailman/listinfo/interest
_______________________________________________
Interest mailing list
http://lists.qt-project.org/mailman/listinfo/interest
-John
Till Oliver Knoll
2014-02-25 06:26:32 UTC
Permalink
Post by Tony Rietwyk
Hi John,
Yes, using a timer should work, I did this in a 3D "point rendering/editing" application where rendering the "point cloud" (in software - and we talk about the year 2000 ;)) was expensive.

So while the timer did not shoot I simply resized the (already) rendered pixmap (giving some sort of interactive feeling), and after the user did not resize the window for, say, 200 ms then I would do the full rendering/update.

Cheers,
Oliver
John Weeks
2014-03-05 18:45:50 UTC
Permalink
Post by Tony Rietwyk
Good luck - please let the group know what you decide with this.
I finally went with a timer:

void grafRec::doResizeEvent(QResizeEvent * event)
{
lastResizeRect.left = lastResizeRect.top = 0;
lastResizeRect.right = event->size().width();
lastResizeRect.bottom = event->size().height();

if (lastFullRedrawTime > SLOWDRAWINGGRAPHTIME)
{
if (_growTimer.isActive())
_growTimer.setInterval(SLOWGRAPHRESIZEWAIT);
else
_growTimer.start();
}
else
{
DoGrfGrow(this, &lastResizeRect);
DirtifyThisGraf(this);
}
}

void grafRec::_onGrowTimerTimedOut()
{
DoGrfGrow(this, &lastResizeRect);
DirtifyThisGraf(this);
}

If the graph took more than 0.2 seconds to draw the last time it was painted, then the timer is set to time out in 0.2 s.

-John

Sean Harmer
2014-02-25 15:58:44 UTC
Permalink
Post by John Weeks
We have windows in our application that are potentially expensive to
repaint, so when the user resizes a window we may need to put off
repainting until the resizing is finished. It seems that we don't get mouse
down/mouse up events when the user clicks in the window frame/resize grip
area, so I can't wait until mouse up.
Is that correct?
Is there a solution to this?
Thanks!
-John Weeks
One option is to grab the window contents upon the first resize event, do a
crude scaling using that. In your resize handler trigger a timer that when it
expires does a "real" resize and update of your content. If you get another
resize event before this timer fires, reset the timer.

Cheers,

Sean
André Somers
2014-02-26 16:49:50 UTC
Permalink
Post by John Weeks
We have windows in our application that are potentially expensive to
repaint, so when the user resizes a window we may need to put off
repainting until the resizing is finished. It seems that we don't get
mouse down/mouse up events when the user clicks in the window
frame/resize grip area, so I can't wait until mouse up.
Is that correct?
Is there a solution to this?
Others have already suggested timers. I usually use this [1] solution
for this and similar problems.

André

[1] http://qt-project.org/wiki/Delay_action_to_wait_for_user_interaction
Loading...