Transparent Backgrounds in Qt 4.1

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(в работе)
 
(6 промежуточных версий не показаны.)
Строка 1: Строка 1:
-
{{menu_Qt_Издания}}
+
{{Панель навигации по Qt Quarterly|Выпуск 16}}
by Andreas Aardal Hanssen'''
by Andreas Aardal Hanssen'''
Строка 5: Строка 5:
Qt 4.1 radically improves widget drawing through its new "backing store", allowing semi-transparent (alpha-blended) child widgets and faster widget painting, as well as solving long-standing issues with nonrectangular widgets.
Qt 4.1 radically improves widget drawing through its new "backing store", allowing semi-transparent (alpha-blended) child widgets and faster widget painting, as well as solving long-standing issues with nonrectangular widgets.
-
*[[#thesystemsbackground | The System's Background]]
+
__TOC__
-
*[[#contentspropagation | Contents Propagation]]
+
-
*[[#newinqt41thebackingstore | New in Qt 4.1: The Backing Store]]
+
</blockquote>
</blockquote>
Строка 21: Строка 19:
To better understand what has changed in Qt 4.1, we will start by reviewing how backgrounds work in Qt 3.x and 4.0 and how to obtain child widget transparency. Much of this is still applicable in Qt 4.1, so read on!
To better understand what has changed in Qt 4.1, we will start by reviewing how backgrounds work in Qt 3.x and 4.0 and how to obtain child widget transparency. Much of this is still applicable in Qt 4.1, so read on!
-
<div id="thesystemsbackground"></div>
+
 
== The System's Background ==
== The System's Background ==
-
A widget represents a distinct region of desktop real estate in which we can paint shapes and colors. Widgets can be stacked on top of each other, and the topmost widget covers the widget underneath it. If a child widget covers half of its parent widget, the parent widget can only draw onto its own exposed areas (available as [http://www.crossplatform.ru/documentation/qtdoc4.3/qpaintevent.php#region QPaintEvent::region()]). Painting operations on the child widgets are clipped away.
+
A widget represents a distinct region of desktop real estate in which we can paint shapes and colors. Widgets can be stacked on top of each other, and the topmost widget covers the widget underneath it. If a child widget covers half of its parent widget, the parent widget can only draw onto its own exposed areas (available as [[Qt:Документация_4.3.2/qpaintevent#region | QPaintEvent::region()]]). Painting operations on the child widgets are clipped away.
On all desktop platforms, a Qt widget is also an independent object known to the window system. By default, the system provides a background based on the widget's background role and palette, which is used whenever a new area of the widget is shown for the first time.
On all desktop platforms, a Qt widget is also an independent object known to the window system. By default, the system provides a background based on the widget's background role and palette, which is used whenever a new area of the widget is shown for the first time.
-
For example, the background role of a [[Qt:Документация_4.3.2/qlabel | QLabel]] is [http://www.crossplatform.ru/documentation/qtdoc4.3/qpalette.php#ColorRole-enum QPalette::Background], which traditionally corresponds to a gray color in the palette; for a [[Qt:Документация_4.3.2/qlineedit | QLineEdit]], the background role is [http://www.crossplatform.ru/documentation/qtdoc4.3/qpalette.php#ColorRole-enum QPalette::Base], which is usually white.
+
For example, the background role of a [[Qt:Документация_4.3.2/qlabel | QLabel]] is [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::Background]], which traditionally corresponds to a gray color in the palette; for a [[Qt:Документация_4.3.2/qlineedit | QLineEdit]], the background role is [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::Base]], which is usually white.
If we call <tt>update()</tt> or <tt>repaint()</tt> to repaint a widget, Qt automatically erases the widget using the background color, relieving us from painting all the widget's pixels. This is very convenient, but it comes at a price:
If we call <tt>update()</tt> or <tt>repaint()</tt> to repaint a widget, Qt automatically erases the widget using the background color, relieving us from painting all the widget's pixels. This is very convenient, but it comes at a price:
Строка 40: Строка 38:
In <tt>paintEvent()</tt>, we could now get away with drawing only the foreground. If we don't draw anything in <tt>paintEvent()</tt>, the widget will be totally white (or whatever color or brush <tt>Base</tt> stands for). Without having to draw anything, we can alter the widget's background color by changing the palette or setting a different background role.
In <tt>paintEvent()</tt>, we could now get away with drawing only the foreground. If we don't draw anything in <tt>paintEvent()</tt>, the widget will be totally white (or whatever color or brush <tt>Base</tt> stands for). Without having to draw anything, we can alter the widget's background color by changing the palette or setting a different background role.
-
If <tt>paintEvent()</tt> paints all the widget's pixels, we can tell Qt not to erase the widget (or the pixmap) with the background color by setting the [[Qt:Документация_4.3.2/qt.php#WidgetFlags-enum Qt::WNoAutoErase]] (Qt 3) or [[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_NoBackground]] (Qt 4) flag. In Qt 3, this is a common anti-flicker technique; in Qt 4, this is a minor speed optimization.
+
If <tt>paintEvent()</tt> paints all the widget's pixels, we can tell Qt not to erase the widget (or the pixmap) with the background color by setting the [http://doc.trolltech.com/3.3/qt.html#WidgetFlags-enum Qt::WNoAutoErase] (Qt 3) or [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_NoBackground]] (Qt 4) flag. In Qt 3, this is a common anti-flicker technique; in Qt 4, this is a minor speed optimization.
 +
 
 +
As a further optimization, we can also disable the window system background by calling [http://doc.trolltech.com/3.3/qwidget.html#setBackgroundMode setBackgroundMode(Qt::NoBackground)] (Qt 3) or [[Qt:Документация_4.3.2/qwidget#setAttribute | setAttribute(Qt::NoSystemBackground)]] (Qt 4). Now, the widget is truly uninitialized, and if we don't paint all the pixels in <tt>paintEvent()</tt>, we can see some interesting "artwork" as we move the window around.
-
As a further optimization, we can also disable the window system background by calling [http://www.crossplatform.ru/documentation/qtdoc4.3/3.3/qwidget.php#setBackgroundMode setBackgroundMode(Qt::NoBackground)] (Qt 3) or [[Qt:Документация_4.3.2/qwidget.php#setAttribute setAttribute(Qt::NoSystemBackground)]] (Qt 4). Now, the widget is truly uninitialized, and if we don't paint all the pixels in <tt>paintEvent()</tt>, we can see some interesting "artwork" as we move the window around.
 
-
<div id="contentspropagation"></div>
 
== Contents Propagation ==
== Contents Propagation ==
-
The purpose of [[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_NoSystemBackground]] is to speed up drawing by removing unnecessary background initialization, but it is often misinterpreted as a way to make the widget background transparent. Keep in mind that although the widgets are stacked on top of each other, the parent widget does not actually paint underneath child widgets.
+
The purpose of [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_NoSystemBackground]] is to speed up drawing by removing unnecessary background initialization, but it is often misinterpreted as a way to make the widget background transparent. Keep in mind that although the widgets are stacked on top of each other, the parent widget does not actually paint underneath child widgets.
-
We need a different approach if we want the parent widget's background to shine through. This is called "contents propagation", and Qt 4.0 supports this through its [[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_ContentsPropagated]] widget attribute. In Qt 3, there are several ways to simulate this feature:
+
We need a different approach if we want the parent widget's background to shine through. This is called "contents propagation", and Qt 4.0 supports this through its [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_ContentsPropagated]] widget attribute. In Qt 3, there are several ways to simulate this feature:
-
* You can use [[Qt:Документация_4.3.2/qpainter.php#redirect QPainter::redirect()]]and then call the parent widget's <tt>paintEvent()</tt> to have the parent draw itself onto the widget's background directly.
+
* You can use [http://doc.trolltech.com/3.3/qpainter.html#redirect QPainter::redirect()] and then call the parent widget's <tt>paintEvent()</tt> to have the parent draw itself onto the widget's background directly.
-
* You can set a transparency mask ([[Qt:Документация_4.3.2/qwidget.php#setMask QWidget::setMask()]]). The parent widget is aware of the child widget's mask and will paint all areas not covered by the mask.
+
* You can set a transparency mask ([http://doc.trolltech.com/3.3/qwidget.html#setMask QWidget::setMask()]). The parent widget is aware of the child widget's mask and will paint all areas not covered by the mask.
-
* If the parent doesn't paint anything underneath the child widget other than its background, you can fill the child widget's background by inheriting the parent widget's brush and applying a suitable offset by calling [[Qt:Документация_4.3.2/3.3/qwidget | QWidget]]::setBackgroundOrigin().
+
* If the parent doesn't paint anything underneath the child widget other than its background, you can fill the child widget's background by inheriting the parent widget's brush and applying a suitable offset by calling [http://doc.trolltech.com/3.3/qwidget.html QWidget]::setBackgroundOrigin().
-
Although Qt 3 doesn't support semi-transparency for widgets, we can simulate it using [[Qt:Документация_4.3.2/3.3/qimage | QImage]] if necessary.
+
Although Qt 3 doesn't support semi-transparency for widgets, we can simulate it using [http://doc.trolltech.com/3.3/qimage.html  QImage] if necessary.
<div style="margin: 1em; float: right; background: #9C9CFF; padding: 2px; width: 40%">
<div style="margin: 1em; float: right; background: #9C9CFF; padding: 2px; width: 40%">
Строка 67: Строка 65:
No matter which approach is taken, contents propagation takes its toll on the application's performance. Exposing a child widget will trigger a repaint for the parent widget. For complex hierarchies, the results can be unbearably slow. For every region with ''n'' overlapping widgets, the bottommost widget gets ''n'' repaints, and for every repaint we may have layouts, font metrics, clipping, and perhaps some complex operations such as an image-to-pixmap conversion or gradient generation. Contents propagation can result in ''n''І paint events, even for the simplest widget exposures.
No matter which approach is taken, contents propagation takes its toll on the application's performance. Exposing a child widget will trigger a repaint for the parent widget. For complex hierarchies, the results can be unbearably slow. For every region with ''n'' overlapping widgets, the bottommost widget gets ''n'' repaints, and for every repaint we may have layouts, font metrics, clipping, and perhaps some complex operations such as an image-to-pixmap conversion or gradient generation. Contents propagation can result in ''n''І paint events, even for the simplest widget exposures.
-
If two semi-transparent widgets overlap (e.g., a semi-transparent rubber band covers a semi-transparent graph widget background), things get even worse. Because of this, [[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_ContentsPropagated]] in Qt 4.0 does not support overlapping siblings.
+
If two semi-transparent widgets overlap (e.g., a semi-transparent rubber band covers a semi-transparent graph widget background), things get even worse. Because of this, [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum |Qt::WA_ContentsPropagated]] in Qt 4.0 does not support overlapping siblings.
 +
 
-
== New in Qt 4.1: The Backing Store
+
== New in Qt 4.1: The Backing Store ==
Qt's paint system has taken a big step forward in Qt 4.1 with the introduction of a backing store on all platforms. The backing store uses a ''persistent'' off-screen buffer for each window, and all raster paint operations are done directly to the backing store.
Qt's paint system has taken a big step forward in Qt 4.1 with the introduction of a backing store on all platforms. The backing store uses a ''persistent'' off-screen buffer for each window, and all raster paint operations are done directly to the backing store.
Строка 83: Строка 82:
* Because the backing store contains a complete rendering of the application's windows at all times, window system exposures don't generate any paint events. No matter how complex the widgets are and how deeply they are stacked, exposures are nearly instantaneous.
* Because the backing store contains a complete rendering of the application's windows at all times, window system exposures don't generate any paint events. No matter how complex the widgets are and how deeply they are stacked, exposures are nearly instantaneous.
*The backing store itself can do alpha blending and composition for all widgets, so we now have complete alpha-blending support for all widgets on all platforms. Repaints are only done for the widgets and regions that absolutely need the repaint to recompose the widget background. In the future, it will be possible for Qt to use hardware support to accelerate the composition even more.
*The backing store itself can do alpha blending and composition for all widgets, so we now have complete alpha-blending support for all widgets on all platforms. Repaints are only done for the widgets and regions that absolutely need the repaint to recompose the widget background. In the future, it will be possible for Qt to use hardware support to accelerate the composition even more.
-
*Qt now has full support for composition of overlapped siblings, which wasn't supported by [http://www.crossplatform.ru/documentation/qtdoc4.3/qt.php#WidgetAttribute-enum Qt::WA_ContentsPropagated].
+
*Qt now has full support for composition of overlapped siblings, which wasn't supported by [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_ContentsPropagated]].
How does all of this affect widget backgrounds? Here's a list of the most significant changes in 4.1:  
How does all of this affect widget backgrounds? Here's a list of the most significant changes in 4.1:  
-
*[[Qt:Документация_4.3.2/qpalette.php#ColorRole-enum QPalette::Background]] has been renamed [[Qt:Документация_4.3.2/qpalette.php#ColorRole-enum QPalette::Window]] to avoid the confusion between [[Qt:Документация_4.3.2/qwidget | QWidget]]'s [[Qt:Документация_4.3.2/qwidget.php#backgroundRole-prop backgroundRole]] property and [[Qt:Документация_4.3.2/qpalette | QPalette]]'s [http://www.crossplatform.ru/documentation/qtdoc4.3/qpalette.php#ColorRole-enum Background] role. Similarly, [[Qt:Документация_4.3.2/qpalette.php#ColorRole-enum QPalette::Foreground]] has been renamed [[Qt:Документация_4.3.2/qpalette.php#ColorRole-enum QPalette::WindowText]].
+
*[[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::Background]] has been renamed [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::Window]] to avoid the confusion between [[Qt:Документация_4.3.2/qwidget | QWidget]]'s [[Qt:Документация_4.3.2/qwidget#backgroundRole-prop | backgroundRole]] property and [[Qt:Документация_4.3.2/qpalette | QPalette]]'s [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | Background]] role. Similarly, [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::Foreground]] has been renamed [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::WindowText]].
-
*Window backgrounds are now initialized with the [[Qt:Документация_4.3.2/qpalette.php#ColorRole-enum QPalette::Window]] brush. All child widgets are by default "transparent"; Qt doesn't fill the widget for us. Because of this, painting with an alpha color can now be done directly in <tt>paintEvent()</tt>.
+
*Window backgrounds are now initialized with the [[Qt:Документация_4.3.2/qpalette#ColorRole-enum | QPalette::Window]] brush. All child widgets are by default "transparent"; Qt doesn't fill the widget for us. Because of this, painting with an alpha color can now be done directly in <tt>paintEvent()</tt>.
-
*[[Qt:Документация_4.3.2/qwidget | QWidget]] has a new property called [[Qt:Документация_4.3.2/qwidget.php#autoFillBackground-prop autoFillBackground]], which is <tt>false</tt> by default. Setting this to <tt>true</tt> will give your custom widgets the same background behavior that they had in Qt 4.0.
+
*[[Qt:Документация_4.3.2/qwidget | QWidget]] has a new property called [[Qt:Документация_4.3.2/qwidget#autoFillBackground-prop | autoFillBackground]], which is <tt>false</tt> by default. Setting this to <tt>true</tt> will give your custom widgets the same background behavior that they had in Qt 4.0.
-
*[[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_NoBackground]] is now called [[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_OpaquePaintEvent]], with the same meaning as before. By setting this option, you provide Qt with a guarantee that you will paint ''all'' the pixels in your paint event with non-transparent colors. (If you set [[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_OpaquePaintEvent]], or enable [[Qt:Документация_4.3.2/qwidget.php#autoFillBackground-prop QWidget::autoFillBackground]] and use an opaque background brush, Qt won't need to recompose the background. This will improve the rendering speed of your widgets significantly.)
+
*[[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_NoBackground]] is now called [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_OpaquePaintEvent]], with the same meaning as before. By setting this option, you provide Qt with a guarantee that you will paint ''all'' the pixels in your paint event with non-transparent colors. (If you set [[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_OpaquePaintEvent]], or enable [[Qt:Документация_4.3.2/qwidget#autoFillBackground-prop | QWidget::autoFillBackground]] and use an opaque background brush, Qt won't need to recompose the background. This will improve the rendering speed of your widgets significantly.)
-
*[[Qt:Документация_4.3.2/qt.php#WidgetAttribute-enum Qt::WA_ContentsPropagated]] has become superfluous, because each widget's contents are now propagated by default.
+
*[[Qt:Документация_4.3.2/qt#WidgetAttribute-enum | Qt::WA_ContentsPropagated]] has become superfluous, because each widget's contents are now propagated by default.
In some very rare cases, the change might affect the semantics of existing programs. If one of your custom widgets goes transparent, calling <tt>setAutoFillBackground(true)</tt> on the widget will fix the problem.
In some very rare cases, the change might affect the semantics of existing programs. If one of your custom widgets goes transparent, calling <tt>setAutoFillBackground(true)</tt> on the widget will fix the problem.
Строка 99: Строка 98:
|}
|}
-
The potential for performance using the backing store architecture is far beyond what we had before. What's more, our users now have the option of writing modern widgets that stand out from the competition, on all platforms, without requiring advanced graphics support on their deployed platforms (such as XRender on X11). See the [http://crossplatform.ru/?q=node/290 Fading Effects with Qt 4.1] article for a real-world application of semi-transparent child widgets.
+
The potential for performance using the backing store architecture is far beyond what we had before. What's more, our users now have the option of writing modern widgets that stand out from the competition, on all platforms, without requiring advanced graphics support on their deployed platforms (such as XRender on X11). See the [[Fading Effects with Qt 4.1]] article for a real-world application of semi-transparent child widgets.
-
With Qt 4.1, you can now use [[Qt:Документация_4.3.2/qpainter | QPainter]] to its full potential, with semi-transparent backgrounds and antialiased curves blended against the parent widget's background. And it won't just work on Mac OS X and Windows 2000 or better. It will work on all platforms, which is exactly what you'd expect from your favorite cross-platform GUI framework.
+
With Qt 4.1, you can now use [[Qt:Документация_4.3.2/qpainter | QPainter]] to its full potential, with semi-transparent backgrounds and antialiased curves blended against the parent widget's background. And it won't just work on Mac OS X and Windows 2000 or better. It will work on all platforms, which is exactly what you'd expect from your favorite cross-platform GUI framework.
-
'''Note: More information about contents propagation and child widget transparency can be found in the [[Qt:Документация_4.3.2/qwidget.php#transparency-and-double-buffering Transparency and Double Buffering section of the QWidget documentation]]'''.
+
'''Note: More information about contents propagation and child widget transparency can be found in the [[Qt:Документация_4.3.2/qwidget#transparency-and-double-buffering | Transparency and Double Buffering section of the QWidget documentation]]'''.
<hr align="center" width="25%" />
<hr align="center" width="25%" />
<div id="fn1"></div><sup>[1]</sup>
<div id="fn1"></div><sup>[1]</sup>
In Qt 4, this is not an issue because of double-buffering. When we paint on a widget, we're actually drawing on a pixmap that will be copied to the screen.
In Qt 4, this is not an issue because of double-buffering. When we paint on a widget, we're actually drawing on a pixmap that will be copied to the screen.

Текущая версия на 03:45, 20 февраля 2009

Image:qt-logo_new.png Image:qq-title-article.png
Qt Quarterly | Выпуск 16 | Документация


by Andreas Aardal Hanssen

Qt 4.1 radically improves widget drawing through its new "backing store", allowing semi-transparent (alpha-blended) child widgets and faster widget painting, as well as solving long-standing issues with nonrectangular widgets.

Содержание


As a custom widget or custom style writer, Qt 4.1 should make your life easier, especially if you want to draw non-rectangular widgets. When doing the transition to the backing store in preparation for the Qt 4.1 release, we discovered that we could both simplify and improve our widget and style code. The new features have also enabled us to address issues concerning the Plastique style which in its initial release did not adequately support textures, gradients, and "dark colored backgrounds".

center center

To better understand what has changed in Qt 4.1, we will start by reviewing how backgrounds work in Qt 3.x and 4.0 and how to obtain child widget transparency. Much of this is still applicable in Qt 4.1, so read on!


[править] The System's Background

A widget represents a distinct region of desktop real estate in which we can paint shapes and colors. Widgets can be stacked on top of each other, and the topmost widget covers the widget underneath it. If a child widget covers half of its parent widget, the parent widget can only draw onto its own exposed areas (available as QPaintEvent::region()). Painting operations on the child widgets are clipped away.

On all desktop platforms, a Qt widget is also an independent object known to the window system. By default, the system provides a background based on the widget's background role and palette, which is used whenever a new area of the widget is shown for the first time.

For example, the background role of a QLabel is QPalette::Background, which traditionally corresponds to a gray color in the palette; for a QLineEdit, the background role is QPalette::Base, which is usually white.

If we call update() or repaint() to repaint a widget, Qt automatically erases the widget using the background color, relieving us from painting all the widget's pixels. This is very convenient, but it comes at a price:

  • If we paint all the pixels in the paint event (for example, we draw a texture or a gradient that covers the entire background), the CPU cycles spent erasing the widget are pure waste.
  • In Qt 3, erasing the widget is a source of flicker because some pixels will be painted twice in a short time. [1]

Let's suppose we want to draw a graphing widget on a Base background. We'd start by adding this call to the constructor:

setBackgroundRole(QPalette::Base);

In paintEvent(), we could now get away with drawing only the foreground. If we don't draw anything in paintEvent(), the widget will be totally white (or whatever color or brush Base stands for). Without having to draw anything, we can alter the widget's background color by changing the palette or setting a different background role.

If paintEvent() paints all the widget's pixels, we can tell Qt not to erase the widget (or the pixmap) with the background color by setting the Qt::WNoAutoErase (Qt 3) or Qt::WA_NoBackground (Qt 4) flag. In Qt 3, this is a common anti-flicker technique; in Qt 4, this is a minor speed optimization.

As a further optimization, we can also disable the window system background by calling setBackgroundMode(Qt::NoBackground) (Qt 3) or setAttribute(Qt::NoSystemBackground) (Qt 4). Now, the widget is truly uninitialized, and if we don't paint all the pixels in paintEvent(), we can see some interesting "artwork" as we move the window around.


[править] Contents Propagation

The purpose of Qt::WA_NoSystemBackground is to speed up drawing by removing unnecessary background initialization, but it is often misinterpreted as a way to make the widget background transparent. Keep in mind that although the widgets are stacked on top of each other, the parent widget does not actually paint underneath child widgets.

We need a different approach if we want the parent widget's background to shine through. This is called "contents propagation", and Qt 4.0 supports this through its Qt::WA_ContentsPropagated widget attribute. In Qt 3, there are several ways to simulate this feature:

  • You can use QPainter::redirect() and then call the parent widget's paintEvent() to have the parent draw itself onto the widget's background directly.
  • You can set a transparency mask (QWidget::setMask()). The parent widget is aware of the child widget's mask and will paint all areas not covered by the mask.
  • If the parent doesn't paint anything underneath the child widget other than its background, you can fill the child widget's background by inheriting the parent widget's brush and applying a suitable offset by calling QWidget::setBackgroundOrigin().

Although Qt 3 doesn't support semi-transparency for widgets, we can simulate it using QImage if necessary.

Window Opacity

Qt 3.3 introduced a new widget property called windowOpacity for making top-level widgets (windows) transparent. This property can't be used to make child widgets semi-transparent, and it only works on window systems that support this feature (Mac OS

X and Windows 2000 or later). In addition, the windowOpacity property applies to the widget as a whole, not to individual shapes or pixels.

No matter which approach is taken, contents propagation takes its toll on the application's performance. Exposing a child widget will trigger a repaint for the parent widget. For complex hierarchies, the results can be unbearably slow. For every region with n overlapping widgets, the bottommost widget gets n repaints, and for every repaint we may have layouts, font metrics, clipping, and perhaps some complex operations such as an image-to-pixmap conversion or gradient generation. Contents propagation can result in nІ paint events, even for the simplest widget exposures.

If two semi-transparent widgets overlap (e.g., a semi-transparent rubber band covers a semi-transparent graph widget background), things get even worse. Because of this, Qt::WA_ContentsPropagated in Qt 4.0 does not support overlapping siblings.


[править] New in Qt 4.1: The Backing Store

Qt's paint system has taken a big step forward in Qt 4.1 with the introduction of a backing store on all platforms. The backing store uses a persistent off-screen buffer for each window, and all raster paint operations are done directly to the backing store.

The backing store results in faster drawing on Windows and faster exposes on all platforms, and makes semi-transparent child widgets possible.

center

On Mac OS X, the backing store is built into the window system; on other platforms, Qt provides its own backing store. The backing store opens up a whole new world of possibilities:

  • Because the backing store contains a complete rendering of the application's windows at all times, window system exposures don't generate any paint events. No matter how complex the widgets are and how deeply they are stacked, exposures are nearly instantaneous.
  • The backing store itself can do alpha blending and composition for all widgets, so we now have complete alpha-blending support for all widgets on all platforms. Repaints are only done for the widgets and regions that absolutely need the repaint to recompose the widget background. In the future, it will be possible for Qt to use hardware support to accelerate the composition even more.
  • Qt now has full support for composition of overlapped siblings, which wasn't supported by Qt::WA_ContentsPropagated.

How does all of this affect widget backgrounds? Here's a list of the most significant changes in 4.1:

In some very rare cases, the change might affect the semantics of existing programs. If one of your custom widgets goes transparent, calling setAutoFillBackground(true) on the widget will fix the problem.

center

The potential for performance using the backing store architecture is far beyond what we had before. What's more, our users now have the option of writing modern widgets that stand out from the competition, on all platforms, without requiring advanced graphics support on their deployed platforms (such as XRender on X11). See the Fading Effects with Qt 4.1 article for a real-world application of semi-transparent child widgets.

With Qt 4.1, you can now use QPainter to its full potential, with semi-transparent backgrounds and antialiased curves blended against the parent widget's background. And it won't just work on Mac OS X and Windows 2000 or better. It will work on all platforms, which is exactly what you'd expect from your favorite cross-platform GUI framework.

Note: More information about contents propagation and child widget transparency can be found in the Transparency and Double Buffering section of the QWidget documentation.


[1]

In Qt 4, this is not an issue because of double-buffering. When we paint on a widget, we're actually drawing on a pixmap that will be copied to the screen.