Results 1 to 4 of 4

Thread: Tricky problem with ARGB widget / UpdateLayeredWindow

  1. #1
    Join Date
    Nov 2007
    Thanked 3 Times in 2 Posts
    Qt products

    Question Tricky problem with ARGB widget / UpdateLayeredWindow

    Hi everybody,

    I've used the ARGB widget trick exposed in the WIKI for an advanced widget.

    My main widget can grow with my childs widgets. If this is the case, the position of the main widget is changed. I've set an animated effect with a QBasicTimer.

    I had a problem with the animation, sometimes there were a flickering during it : we can see a very short latency between the move at original size and when the new size is painted by the UpdateLayeredWindow function.

    I have solve it like this :

    Qt Code:
    1. topPos.x = myNewXpos; // instead of x(). Nice for animation but it sucks for mouseEvents
    2. topPos.y = myNewYpos; // instead of y(). Nice for animation but it sucks for mouseEvents
    3. ...
    4. UpdateLayeredWindow(winId(), screenDc, &topPos, &size, memDc, &pointSource, 0, &blend, ULW_ALPHA);
    5. move(myNewXpos, myNewYpos);
    To copy to clipboard, switch view to plain text mode 

    And I do the real move to synchronize the widget regarding its painted position on screen. It works like a charm ! The animation is now smooth.

    The really big problem is with the mouse events on childs widget (or even a call to underMouse() on the adequate widget from the parent widget). It is totally wrong. I put a mousePressEvent on my childs widget but this is not the good widget that is seen as clicked (even if everything seems good with the event->globalPos() and with the child items mapToGlobalPos()).

    The problem is really related to the topPos.x and topPos.y I don't set to x() and y().

    Does someone has already encountered the same problem and deal with it ?

    Sure, I have the idea to put an event filter on the main widget and decide myself which child widget has been clicked but I don't think it's elegant that Qt mouse events is disturbed by this. It sounds clearly like a design problem and it's bad.

  2. #2
    Join Date
    Nov 2007
    Thanked 3 Times in 2 Posts
    Qt products

    Lightbulb Re: Tricky problem with ARGB widget / UpdateLayeredWindow

    I answer to myself (and to whom could be concerned one day by a similar problem).

    I've excogitated more on the problem and the problem isn't related in any way to updateLayeredWindow().

    If I had programmed the same thing without handling the semi-transparency, in pure Qt, I could have noticed the same hickup in the animation of my widget : when moving a widget just before or just after resizing it, it's quite logical that an hickup could occur as the move and resize is doing in two steps !

    In such a case, you have to place the widget at the correct location when painting. It was what I did in the updateLayeredWindow() but it was a very bad idea for the mouse events.

    So, the correct way to do such a thing, with or without updateLayeredWindow() is to place the widget at the correct place when painting so the best idea is definitively to have transparent margins around the widget and to compute the offset when painting it.

    The other side of the coin is that my widget will be larger, consume a little more memory, and perhaps will repaint a little slower (is a fillRect() method really slowed when it had to fill a quite larger widget with transparency ?).

    Am i right ? I don't see any other way to handle a smooth animation with a widget that growth and move during the steps of the animation.

    I hope I am right and it could help other readers.

  3. #3
    Join Date
    Nov 2007
    Thanked 3 Times in 2 Posts
    Qt products

    Default Re: Tricky problem with ARGB widget / UpdateLayeredWindow

    I can confirm I consume more memory ! About 5 meg !!! Quite large.

    So, is there a Qt way to telling that I want to repaint the widget at a particulier location on the screen in one single step rather than calling update() and move() in two steps that give hickups in the animation ?

  4. #4
    Join Date
    Nov 2007
    Thanked 3 Times in 2 Posts
    Qt products

    Default Re: Tricky problem with ARGB widget / UpdateLayeredWindow


    This is time to give feedback on this problem.

    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.

    Here is a working code sample :

    Qt Code:
    1. class MyWidget : public QWidget
    2. {
    3. protected:
    4. void paintEvent(QPaintEvent *event);
    5. void mouseMoveEvent(QMouseEvent *event);
    7. private:
    8. QPixmap widgetMask;
    9. int myWidgetX; // <==
    10. int myWidgetY; // <==
    11. updateAlpha();
    12. }
    14. void MyWidget::paintEvent(QPaintEvent *event)
    15. {
    16. // Code for painting on a QPixmap rather than on screen
    17. QPainter painter(&widgetMask);
    18. ...
    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; // <==
    25. // Native call to handle semi-transparency on win32 (with the wonderful cheat for move&resize in one go)
    26. updateAlpha()
    27. }
    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
    35. myWidgetX = newXPos; // <==
    36. myWidgetY = newXPos; // <==
    37. move(myWidgetX, myWidgetY); // real Qt move(), I don't need to do repaint there
    38. }
    40. void MyWidget::updateAlpha()
    41. {
    42. HBITMAP oldBitmap;
    43. HBITMAP hBitmap;
    44. SIZE size;
    45. = widgetMask.width();
    46. = 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);
    65. if (hBitmap!=NULL)
    66. {
    67. SelectObject(memDc, oldBitmap);
    68. DeleteObject(hBitmap);
    69. DeleteObject(hBitmap);
    70. }
    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 : but no news for it at the moment...
    Last edited by nooky59; 21st February 2008 at 10:43.


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.