ARGB-Widgets
From QtCentreWiki
| This article is obsolete since version 4.5. Semi-transparent widgets can be obtained through use of Qt::WA_TranslucentBackground |
Here you can learn how to build ARGB-Widgets under Windows.
Under Linux this is easy done by compositing, but under Windows at first there is no solution. If you search longer in WinAPI, you'll find a window class, called WS_LAYERED_EX. With this window class and some help of Qt4 you can realize a ARGB-Widget:
To make a layered window from a normal QWidget, you have to do two steps:
1. Include windows.h. Some functions can't be used by Qt normally, but with these defines it becomes possible:
#define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h>
2. replace WindowLong.
setWindowFlags(Qt::FramelessWindowHint | Qt::Widget); SetWindowLong(winId(), GWL_EXSTYLE, GetWindowLong(winId(), GWL_EXSTYLE) | WS_EX_LAYERED);
Normal layered windows can't have control elements, like pushbuttons or lineedits. Because of this we render all child widgets into a pixmap. This pixmap is the picture we want to render on our ARGB-Window. All this we do in the paintEvent:
void QAlphaWidget::paintEvent(QPaintEvent *event) { QPixmap widgetMask = QPixmap("bg.png"); QPainter p(&widgetMask); QObjectList ol = children(); foreach(QObject *o, ol) { if (o->isWidgetType() && !o->objectName().isEmpty()) { QWidget* child = qobject_cast<QWidget*>(o); p.drawPixmap(child->geometry(),drawCtrl(child )); } } p.end(); updateAlpha(widgetMask); } QPixmap QAlphaWidget::drawCtrl(QWidget * widget) { if (!widget) { return QPixmap(); } QRect r(widget->rect()); QPixmap res(r.size()); widget->render(&res, -r.topLeft(), r, QWidget::DrawWindowBackground | QWidget::DrawChildren | QWidget::IgnoreMask); return res; }
So now we have a pixmap with all control elements and a nice semi-transparent background. The thing we have to do next, is to bring up this pixmap to our widget. This we do in updateAlpha(const QPixmap&):
void QAlphaWidget::updateAlpha(const QPixmap &background) { HBITMAP oldBitmap; HBITMAP hBitmap; SIZE size; size.cx = background.width(); size.cy = background.height(); HDC screenDc = GetDC(NULL); POINT pointSource; pointSource.x = 0; pointSource.y = 0; POINT topPos; topPos.x = x(); topPos.y = y(); HDC memDc = CreateCompatibleDC(screenDc); BLENDFUNCTION blend; blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = alpha; blend.AlphaFormat = AC_SRC_ALPHA; hBitmap = background.toWinHBITMAP(QPixmap::PremultipliedAlpha); oldBitmap = (HBITMAP)SelectObject(memDc, hBitmap); UpdateLayeredWindow(winId(), screenDc, &topPos, &size, memDc, &pointSource, 0, &blend, ULW_ALPHA); ReleaseDC( NULL, screenDc); if (hBitmap!=NULL) { SelectObject(memDc, oldBitmap); DeleteObject(hBitmap); } DeleteDC(memDc); }
This is all we need to make nice ARGB-Widgets under Windows
Here the complete code:
QAlphaWidget.h
/********************************************************************************************************
* PROGRAM : QAlphaWidget
* DATE - TIME : Samstag 11 Augus 2007
* AUTHOR : (Markus Künkler )
* FILENAME : QAlphaWidget.h
* LICENSE :
* COMMENTARY :
********************************************************************************************************/
#ifndef QAlphaWidget_H
#define QAlphaWidget_H
#include <QtGui>
#define _WIN32_WINNT 0x0500
#define WINVER 0x0500
#include <windows.h>
class QAlphaWidget : public QWidget
{
Q_OBJECT
public:
QAlphaWidget(QWidget* wgtParent = 0);
~QAlphaWidget() {};
QSize sizeHint() const;
public slots:
void updateAlpha();
void setLayered();
protected:
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent *event);
QPixmap drawCtrl(QWidget * widget);
QRegion childRegion;
private:
QPoint dragPosition;
QPixmap widgetMask;
BYTE alpha;
};
#endif
QAlphaWidget.cpp
/********************************************************************************************************
* PROGRAM : QAlphaWidget
* DATE - TIME : Samstag 11 Augus 2007
* AUTHOR : (Markus Künkler )
* FILENAME : QAlphaWidget.cpp
* LICENSE :
* COMMENTARY :
********************************************************************************************************/
#include <QtGui>
#include "QAlphaWidget.h"
QAlphaWidget::QAlphaWidget( QWidget* wgtParent)
: QWidget(wgtParent)
{
setWindowFlags(Qt::FramelessWindowHint | Qt::Widget);
setWindowTitle("AlphaWidget");
widgetMask = QPixmap("bg.png");
alpha = 255;
resize(widgetMask.width(), widgetMask.height());
setMouseTracking(true);
SetWindowLong(winId(),
GWL_EXSTYLE,
GetWindowLong(winId(), GWL_EXSTYLE) | WS_EX_LAYERED));
}
void QAlphaWidget::setLayered()
{
SetWindowLong(winId(),
GWL_EXSTYLE,
GetWindowLong(winId(), GWL_EXSTYLE) | WS_EX_LAYERED);
}
void QAlphaWidget::mousePressEvent(QMouseEvent *event)
{
childRegion = childrenRegion();
if (!childRegion.contains(event->pos())) {
if (event->button() == Qt::LeftButton) {
dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept();
}
}
}
void QAlphaWidget::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
move(event->globalPos() - dragPosition);
event->accept();
}
}
QSize QAlphaWidget::sizeHint() const
{
return QSize(widgetMask.width(), widgetMask.height());
}
void QAlphaWidget::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
void QAlphaWidget::updateAlpha()
{
HBITMAP oldBitmap;
HBITMAP hBitmap;
SIZE size;
size.cx = widgetMask.width();
size.cy = widgetMask.height();
HDC screenDc = GetDC(NULL);
POINT pointSource;
pointSource.x = 0;
pointSource.y = 0;
POINT topPos;
topPos.x = x();
topPos.y = y();
HDC memDc = CreateCompatibleDC(screenDc);
BLENDFUNCTION blend;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = alpha;
blend.AlphaFormat = AC_SRC_ALPHA;
hBitmap = widgetMask.toWinHBITMAP(QPixmap::PremultipliedAlpha);
oldBitmap = (HBITMAP)SelectObject(memDc, hBitmap);
UpdateLayeredWindow(winId(), screenDc, &topPos, &size, memDc, &pointSource, 0, &blend, ULW_ALPHA);
ReleaseDC( NULL, screenDc);
if (hBitmap!=NULL) {
SelectObject(memDc, oldBitmap);
DeleteObject(hBitmap);
DeleteObject(hBitmap);
}
DeleteDC(memDc);
}
void QAlphaWidget::paintEvent(QPaintEvent *event)
{
QPainter p(&widgetMask);
QObjectList ol = children();
foreach(QObject *o, ol) {
if (o->isWidgetType()) {
QWidget* child = qobject_cast<QWidget*>(o);
p.drawPixmap(child->geometry(),drawCtrl(child ));
}
}
p.end();
updateAlpha();
}
QPixmap QAlphaWidget::drawCtrl(QWidget * widget)
{
if (!widget) {
return QPixmap();
}
QRect r(widget->rect());
QPixmap res(r.size());
widget->render(&res,
-r.topLeft(),
r,
QWidget::DrawWindowBackground | QWidget::DrawChildren | QWidget::IgnoreMask);
return res;
}
Kernel_Panic 21:27, 13 August 2007 (CEST)


