Results 1 to 7 of 7

Thread: Painting / moving in a single step to avoid flickering

  1. #1
    Join Date
    Nov 2007
    Posts
    53
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Question Painting / moving in a single step to avoid flickering

    As it was not related to an ARGB widget and there is no answer, I start a new short thread to know if there is a solution to this problem.

    I will take the shaped clock sample to explain. I've attached the modified code to this message.

    Here is what I've had in the shapedclock.h :

    Qt Code:
    1. protected:
    2. void timerEvent(QTimerEvent *event); // <==
    3. void mouseMoveEvent(QMouseEvent *event);
    4.  
    5. private:
    6. QPoint dragPosition;
    7. int step; // <==
    8. QBasicTimer timer; // <==
    To copy to clipboard, switch view to plain text mode 

    Here is what I've had in the shapedclock's constructor

    Qt Code:
    1. setWindowTitle(tr("Shaped Analog Clock"));
    2.  
    3. step = 0; // <==
    4. this->timer.start(200, this); // <==
    To copy to clipboard, switch view to plain text mode 

    Here is the added timerEvent() method :

    Qt Code:
    1. void ShapedClock::timerEvent(QTimerEvent *event)
    2. {
    3. if(event->timerId() == timer.timerId())
    4. {
    5. ++step;
    6. resize(width() + step, height() + step);
    7. update();
    8. }
    9. else
    10. QWidget::timerEvent(event);
    11. }
    To copy to clipboard, switch view to plain text mode 

    And finally, here is the added line in resizeEvent for moving the widget on screen :

    Qt Code:
    1. void ShapedClock::resizeEvent(QResizeEvent * /* event */)
    2. {
    3. move(x() - 5, y() - 5);
    To copy to clipboard, switch view to plain text mode 

    And you will see clearly the clock shaking when resizing / moving.

    As I told in my previous post, there is a simple way to deal with it. Defining a larger size QWidget and painting at the correct location. But for a very large widget that can grow by more than 3 times its size and can be shifted by more than 2 times its size, it consume much more memory and perhaps it won't be efficient to deal with a large QWidget even if it contains reserved transparency areas for growing / offseting ?

    So, do you think there is a way to paint and move in a single step to avoid dealing with a very large QWidget just to solve this shaking motion ?

    Thanks for your answer on this very tricky problem.
    Attached Files Attached Files

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Painting / moving in a single step to avoid flickering

    If you resize a widget and then move it (as move schedules another event) then it's obvious that it will flicker, especially if it's repainted in the meantime. You have to make sure it is repainted after you move it. Instead of resize() you might have used setGeometry() and everything would be fine - the widget would be resized and moved in one go. Sending a move event instead of calling move() might also work. This way it would be executed before the scheduled paint event.

  3. #3
    Join Date
    Nov 2007
    Posts
    53
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Painting / moving in a single step to avoid flickering

    Thanks for your answer.

    Anyway, I've tried a setGeometry() with the shaped clock sample previously attached and I had no luck with it. It is flickering as well.

    Qt still does it in two steps even if you make a single function call.

  4. #4
    Join Date
    Oct 2006
    Posts
    279
    Thanks
    6
    Thanked 40 Times in 39 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Painting / moving in a single step to avoid flickering

    I think this is a problem with the window manager and not Qt. On WinXP for instance, you will get this behaviour on any window, when you resize it by the upper left corner.
    See also http://labs.trolltech.com/blogs/2007...f-all-flicker/

  5. #5
    Join Date
    Nov 2007
    Posts
    53
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Painting / moving in a single step to avoid flickering

    Thanks for the link spud. But I wonder if it is really the same problem here. Shaped clock is a single widget without childs. But perhaps the QT solution cover too this painting / moving aspect.

  6. #6
    Join Date
    Oct 2006
    Posts
    279
    Thanks
    6
    Thanked 40 Times in 39 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Painting / moving in a single step to avoid flickering

    None the less, I think it's a symptom of the same problem. Think about it: When you move a window, the WM repaints the window without calling paint(). When you move and resize a window first the WM repaints the window on the new position with the old size, then you repaint it in paint() with the new size. This will lead to flicker. Non rectangular windows only make the problem more noticable.

    P.S. You're right. Qt's new approach won't help in this case

  7. #7
    Join Date
    Nov 2007
    Posts
    53
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Painting / moving in a single step to avoid flickering

    Hi,

    This is time to give feedback on this problem.

    As I said in the another post ( http://www.qtcentre.org/forum//forum...uote=1&p=59426 ), I was dealing with UpdateLayeredWindow() to solve the flickering problem but I was out-of sync with childs events.

    In fact, the approach work perfectly !!! My code was quite wide and complex and in a particular place, I was doing a Qt move() call without repainting my widget (so without calling UpdateLayeredWindow()) but I didn't update my private widget members holding the coordinates so later during a repaint, all the pos / mouseEvents for child widgets were out-of-sync.

    So, you could deal with the problem if you have such one with UpdateLayeredWindow() (or equivalent non-layered native paint method).

    The dark side is this is not multi-platorm so you should play with ifdef and find similar native paint methods on OS X and Linux.

    Here is a code sample :

    Qt Code:
    1. class MyWidget : public QWidget
    2. {
    3. protected:
    4. void paintEvent(QPaintEvent *event);
    5. void mouseMoveEvent(QMouseEvent *event);
    6.  
    7. private:
    8. QPixmap widgetMask;
    9. int myWidgetX; // <==
    10. int myWidgetY; // <==
    11. updateAlpha();
    12. }
    13.  
    14. void MyWidget::paintEvent(QPaintEvent *event)
    15. {
    16. // Code for painting on a QPixmap rather than on screen
    17. QPainter painter(&widgetMask);
    18. ...
    19.  
    20. // If a move is needed with the resizing of the widget, no move there
    21. // but update of the private integers, it will be synced in the native call
    22. myWidgetX = newXPos; // <==
    23. myWidgetY = newXPos; // <==
    24.  
    25. // Native call to handle semi-transparency on win32 (with the wonderful cheat for move&resize in one go)
    26. updateAlpha()
    27. }
    28.  
    29. void mouseMoveEvent(QMouseEvent *event)
    30. {
    31. // Let's suppose the widget should be moved but a repaint is not needed
    32. // calling Qt move() but DON'T FORGET to update myWidgetX & myWidgetY to avoid OUT-OF-SYNC
    33. // move(newXPos, newXPos); <= bad if you forget to update myWidgetX&Y
    34.  
    35. myWidgetX = newXPos; // <==
    36. myWidgetY = newXPos; // <==
    37. move(myWidgetX, myWidgetY); // real Qt move(), I don't need to do repaint there
    38. }
    39.  
    40. void MyWidget::updateAlpha()
    41. {
    42. HBITMAP oldBitmap;
    43. HBITMAP hBitmap;
    44. SIZE size;
    45. size.cx = widgetMask.width();
    46. size.cy = widgetMask.height();
    47. HDC screenDc = GetDC(NULL);
    48. POINT pointSource;
    49. pointSource.x = 0;
    50. pointSource.y = 0;
    51. POINT topPos;
    52. topPos.x = myWidgetX; // <==
    53. topPos.y = myWidgetY; // <==
    54. HDC memDc = CreateCompatibleDC(screenDc);
    55. BLENDFUNCTION blend;
    56. blend.BlendOp = AC_SRC_OVER;
    57. blend.BlendFlags = 0;
    58. blend.SourceConstantAlpha = alpha;
    59. blend.AlphaFormat = AC_SRC_ALPHA;
    60. hBitmap = widgetMask.toWinHBITMAP(QPixmap::PremultipliedAlpha);
    61. oldBitmap = (HBITMAP)SelectObject(memDc, hBitmap);
    62. UpdateLayeredWindow(winId(), screenDc, &topPos, &size, memDc, &pointSource, 0, &blend, ULW_ALPHA);
    63. ReleaseDC( NULL, screenDc);
    64.  
    65. if (hBitmap!=NULL)
    66. {
    67. SelectObject(memDc, oldBitmap);
    68. DeleteObject(hBitmap);
    69. DeleteObject(hBitmap);
    70. }
    71.  
    72. DeleteDC(memDc);
    73. move(myWidgetX, myWidgetY); // <==
    74. }
    To copy to clipboard, switch view to plain text mode 

    Before finding my mistake on the out-of-sync problem, I have made a suggestion to TrollTech but it's still usefull so I hope that TrollTech will add a Qt way of doing it without dealing with native paint methods (except if I really need alpha-transparency top-level support on Windows).

    This is the task 194678 on the task-tracker : http://trolltech.com/developer/task-tracker but no news for it at the moment...
    Last edited by nooky59; 21st February 2008 at 10:45.

Similar Threads

  1. KDE/QWT doubt on debian sarge
    By hildebrand in forum KDE Forum
    Replies: 13
    Last Post: 25th April 2007, 06:13

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.