+ Reply to Thread
Results 1 to 6 of 6

Thread: Drawing widgets with transparent backgrounds over a specialized widget

  1. #1
    Join Date
    Apr 2009
    Location
    www.JaminGrey.com
    Posts
    61
    Thanks
    9
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Drawing widgets with transparent backgrounds over a specialized widget

    Hello. I'm trying to draw a QWidget over another QWidget that is drawn by the SFML API.

    Everything works fine, I have my main widget be Qt-controlled, I have additional widgets around the sides, and the center widget is a QScrollArea with the SFML QWidget owned by the QScrollArea.
    Events work fine, drawing works fine.

    However, when I give the SFML-drawn QWidget a layout and a child widget, despite everything I do, I can't see the SFML-drawn widget through the background of the child widget.

    It looks like this:
    blackbar.jpg

    The one on the left is behaving properly (it's outside the SFML widget), but the one on the right (a child of the SFML widget) with it's transparent background shows black instead of the background drawn by SFML.

    All my SFML drawing happens within the QPaint of the SFML QWidget.

    I've tried tons of different methods to try and get the background to be transparent.

    I've tried:
    Qt Code:
    1. QPalette p = rightTabBar->palette();
    2. rightTabBar.setBrush(QPalette::Window, Qt::transparent);
    3. rightTabBar->setPalette(p);
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. rightTabBar->setObjectName("MyVerticalTabBar");
    2. rightTabBar->setStyleSheet("#MyVerticalTabBar { background-color: transparent; }");
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. rightTabBar->setAutoFillBackground(false);
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. rightTabBar->setAttribute(Qt::WA_TranslucentBackground);
    To copy to clipboard, switch view to plain text mode 

    And:
    Qt Code:
    1. rightTabBar->setAttribute(Qt::WA_NoSystemBackground);
    To copy to clipboard, switch view to plain text mode 

    I'm under the sneaking suspicion that the background is properly transparent, but that the parent's background (the SFML-drawn widget) is somehow being propagated to the child before the SFML widget gets drawn, and that the child then draws the propagated blank background over the now-drawn background.
    Or else, maybe the child gets drawn first, and some kind of clip-rect gets set to the SFML-drawn window, keeping those pixels under the child from getting drawn (Despite Qt::WA_PaintUnclipped being set on the parent).
    Attached Images Attached Images
    Last edited by ComServant; 17th March 2012 at 22:14.

  2. #2
    Join Date
    Apr 2009
    Location
    www.JaminGrey.com
    Posts
    61
    Thanks
    9
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing widgets with transparent backgrounds over a specialized widget

    Updated info:

    Infact, aside from the widgets, the area with the blackbar isn't drawn at all. Not even flood-filled, apparently, because if I remove one of the widgets after the window is created, then when the layout re-arranges the remaining widgets, they leave after-images from where they previously were.

    Observe:
    Attachment 7513

    So the black bar appears to get filled once at creation, and never filled again, only drawn over by the widget that owns the black bar, and that widget's children.
    If, during runtime, I hide the widget with the black bar, the black bar disappears and I can see the SFML-drawn widget's background.

    This tells me:
    A) The black bar IS the widget's background, despite every attempt to say: "Don't give me a background! Don't draw the background! Give me a transparent background!"
    B) The black bar IS NOT being redrawn (Good!), even when the children widgets are.
    C) The parent widget's background IS being drawn (Good!), it's just covered (Bad!) by the definitely-not-transparent black-bar.

    Furthermore, if I disable 'QWidget::setAttribute(Qt::WA_PaintOnScreen);' on the parent, then we get the very interesting effect of the entire widget flickering between two states: The SFML-drawing (OpenGL under the hood), and the Qt drawing. It flickers between: Seeing the entire SFML-drawn widget (no Qt-drawn children), and seeing only the Qt-drawn widgets over a black background (no SFML-drawn parent).
    No doubt this is because SFML is drawing as fast as possible using OpenGL hardware-accelerated drawing and it's own buffer, drawing over the Qt-drawn children, and when the Qt-drawn stuff appears, it draws over the entire widget (Probably starting with the children and working up the ancestry tree?).

    Still, it _should_ work. I just need to tell the Qt-drawn stuff not to update it's background... Or maybe it's the SFML-drawn widget that is clearing the background, but using Qt's draw functions, before paintEvent() is called.

    Any thoughts or suggestions?

    [Edit:]

    Even if I have every widget, from the children widgets to the SFML-drawn widgets, to the top-most parent widget of everything, even if I have all of them not draw their backgrounds with:
    setAutoFillBackground(false);
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_TranslucentBackground);

    It still shows the black bar over the SFML-drawn widget, and the window looks like this:
    blahpu.jpg

    Even if there's some kind of timing issue, like the children getting drawn before the parent, which I'm sure is likely, I'm still telling them: Don't draw your background.

    Theory: All the Qt-drawn widgets are drawing to internal buffers, and then the buffers are drawn on screen. SFML-drawn widget is drawing to it's own internal buffer, and then drawing to the screen. Therefore, the Qt-drawn widgets only see the blank/empty SFML-ignored Qt widget buffer, and assimilate that as their background.

    Solution (if theory is correct): Is there a way I can tell Qt widgets to not bother double-buffering, and just draw directly, and to update every frame regardless of need? (I wont need to do this for the entire application, just the five or six widgets drawn over the SFML-drawn one).
    It seems like I can only do this if I want to implement my own paint engine ( http://qt-project.org/faq/answer/how...t_composition_ ).

    Any thoughts?
    Last edited by ComServant; 17th March 2012 at 22:43.

  3. #3
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,317
    Thanks
    20
    Thanked 377 Times in 371 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing widgets with transparent backgrounds over a specialized widget

    I don't have time (at the moment) to read all you have written, its just to long.
    However - if your special widget is not drawn by Qt, you wont be able to get to see it through a child widget.
    The reason for this is simple - for the transparency to work, Qt must know what is under the child widget, and if Qt didn't draw it, it can't draw what ever should be seen through the child widget.
    The problem can be often observed with QGLWidgets as well.
    If you have the information in your hand to the drawn content of your special externally drawn widget, you could pass this buffer and the correct region to the child widget - but that will be not trivial and probably not easy.
    Recommended off-line reading:
    The Foundations of Qt Development (ISBN: 1-59059-831-8)

  4. #4
    Join Date
    Apr 2009
    Location
    www.JaminGrey.com
    Posts
    61
    Thanks
    9
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing widgets with transparent backgrounds over a specialized widget

    I'm not wanting transparency as in translucency. If I wanted something like glass (partial transparency), Qt would need to know about it. But if I'm wanting parts of a widget to be 100% transparent (i.e. entirely invisible), Qt shouldn't need that information (though the API might require it, the logical concept itself doesn't).

    I suppose I could grab the correct portion of the SFML widget, save it to a buffer, convert that buffer to a QPixmap, and draw that QPixmap as the child QWidget's background.
    That's kinda hacky programming that I'd like to avoid though, as it creates ties between the two separate classes that just shouldn't be there. I'll look into anyway, though.

    Could I get the entire buffer of the child widget, somehow, and then use that to create a mask for the widget?

  5. #5
    Join Date
    Apr 2009
    Location
    www.JaminGrey.com
    Posts
    61
    Thanks
    9
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Drawing widgets with transparent backgrounds over a specialized widget

    This works:

    Qt Code:
    1. QWidget *myWidget = new QWhateverWidget();
    2. myWidget->setAutoFillBackground(false);
    3. QPixmap pixmap = QPixmap::grabWidget(myWidget);
    4. myWidget->setMask(pixmap.createHeuristicMask();
    To copy to clipboard, switch view to plain text mode 

    Easy, functional, and doesn't require custom widgets. You just need to remember to update the mask whenever the widget's layout changes.

    functioning.png

    Note: Since createHeurisiticMask() uses whatever colors are in each of the corners and chips away from there, if your widget has legitimate pixels in one of the corners they will be eaten.
    If such is the case, you might prefer createMaskFromColor() instead, using the color of the transparent pixel Qt uses. For me, this oddly appears to be QColor(173, 240, 13).
    I tried to find a constant defined somewhere with that value, but I can't locate one. Qt::transparent, and Qt::color0 / Qt::color1 don't match it.
    If QColor(173,240,13) doesn't work for you, you can instead save the pixmap (pixmap->save()) and see what color is used in your version of Qt. Obviously this method isn't future-proof however.

    [Edit:] ROFL. QColor, being lime green, I thought they were just using the color from the Qt logo (which is actually quite a bit darker). Turns out in hexadecimal it's 0xADF00D, so in ARGB (but the alpha gets lost) it's probably 0xBAADF00D, or maybe 0xDEADF00D, common debug/error values.
    Someone should submit a patch for this, and make it use Qt::transparent as the color, or create a new color for it (Qt::invisible), so it can be assured to not break in future builds.
    Or, preferablly, just return a 32 bit pixmap with proper alpha. Then you can just do: pixmap->mask().

  6. #6
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,317
    Thanks
    20
    Thanked 377 Times in 371 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Drawing widgets with transparent backgrounds over a specialized widget

    But if I'm wanting parts of a widget to be 100% transparent (i.e. entirely invisible),Qt shouldn't need that information
    That is true - but I thought you wanted translucency.
    Recommended off-line reading:
    The Foundations of Qt Development (ISBN: 1-59059-831-8)

+ Reply to Thread

Similar Threads

  1. Freehand drawing on transparent widget.
    By vaibhav in forum Qt Programming
    Replies: 4
    Last Post: 24th November 2010, 07:33
  2. Replies: 2
    Last Post: 31st May 2010, 12:57
  3. Replies: 0
    Last Post: 15th May 2009, 16:38
  4. Widgets on Graphicsview backgrounds
    By pherthyl in forum Qt Programming
    Replies: 4
    Last Post: 29th July 2008, 19:02
  5. Regarding drawing on Transparent Window
    By Shalabh in forum Qt Programming
    Replies: 3
    Last Post: 31st May 2007, 11:32

Tags for this Thread

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