PDA

View Full Version : ARGB windows on Windows?



ber_44
4th August 2007, 11:19
It's a pity that
QApplication::QApplication ( Display * display, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0 )
is X11 only. I wonder if there is any way on Windows and OS X to create a window which can be drawn to using transparent brush and will in turn be transparent (like with the above constructor for X11 as shown here: svn://labs.trolltech.com/svn/graphics/dojo/argb).

wysota
8th August 2007, 22:48
It should work fine without any special tricks on systems that support that (Windows 2000+ and appropriate graphics card driver that supports ARGB visuals).

marcel
8th August 2007, 22:55
It should work fine without any special tricks on systems that support that (Windows 2000+ and appropriate graphics card driver that supports ARGB visuals).
There have been a few attempts to display transparent pngs on top level widgets, even here on QtCentre.
As far as I know, it won't work on XP and 2000. Only on Mac and X11(with the composite extension enabled), and on Vista with the help of platform API(that might have been changed since Qt 4.3 ).

Regards

kernel_panic
9th August 2007, 11:24
it's possible on windows xp and 2000 too. The problem is that you can't use control elements anymore.
you just have to set your windowLong to EX_LAYERED and call UpdateLayeredWindow with an image you want to display semi-transparent on the desktop.
search google for UpdateLayeredWindow. There are many examples.

I ask me, how the Yahoo Widget Engine does the ARGB-Widgets.... They can use control-elements and it runs on windows xp/2000....

marcel
9th August 2007, 13:11
it's possible on windows xp and 2000 too. The problem is that you can't use control elements anymore.
you just have to set your windowLong to EX_LAYERED and call UpdateLayeredWindow with an image you want to display semi-transparent on the desktop.
search google for UpdateLayeredWindow. There are many examples.

I ask me, how the Yahoo Widget Engine does the ARGB-Widgets.... They can use control-elements and it runs on windows xp/2000....

I think the original post talked about the ARGB windows example at trolltech labs.
That is more than a simple image layered on a window.

That you can't do on XP.

Take a look.

kernel_panic
9th August 2007, 13:14
I know that the trolltech example doesn't work...
Therefore i postet how sth like this works on windows.
But ARGB window is ARGB window, if you do this with the solution of trolltech or with UpdateLayeredWindow, or?
please read the first pos again:


I wonder if there is any way on Windows
He ask for ANY WAY!!!!!!!

marcel
9th August 2007, 20:39
OK, ok, it can be done, but it is not easy.
Take a look at what this guy did: http://www.codeproject.com/useritems/VisitaLookingDialog.asp.

It offers real time backdrop composition, although it keeps the processor at 100%.



ask me, how the Yahoo Widget Engine does the ARGB-Widgets.... They can use control-elements and it runs on windows xp/2000....

They probably built an entire framework on top of the Windows composition/translucency API.
Anyway, in the example above, there are a few non-transparent controls.
They did by using an opaque area as background for the controls.
From what I have seen in the code even the control are stored in a backbuffer and painted on the image passed to UpdateLayeredWindow.

Regards

kernel_panic
10th August 2007, 07:20
hey! sry for flaming.... had a bad day....
but this example is great. i'll try to port this to qt and build some classes, mkay?
is it possible to draw qt-controls into a pixmap instead on the widget? this would help much.

wysota
10th August 2007, 09:05
Yes, it's possible. You can redirect a paint event into another paint device, but it's quite tedious not to lose control.

marcel
10th August 2007, 14:03
Yes, it's possible. You can redirect a paint event into another paint device, but it's quite tedious not to lose control.
You always have QPixmap::grabWidget().

It also grabs the children so if you have a container widget you can make things easy and grab all the widgets you want in one step.

EDIT: ok, forget that :). QPainter::setRedirected is better.
QPixmap::grabWidget requires the widget to be visible.

Regards

kernel_panic
10th August 2007, 16:15
i call this in my paintEvent, but nothing is paintet in the pixmap, why?


QObjectList ol = children();
foreach(QObject *o, ol)
{
if(o->isWidgetType())
{

QWidget* child = qobject_cast<QWidget*>(o);


QPainter::setRedirected(child->paintEngine()->paintDevice(), &widgetMask);


}

}


and than i update the pixmap onto my layered Window



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::PremultipliedAlph a); // grab a GDI handle from this GDI+ bitmap
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); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win32 GDI and it's working fine without any resource leak.
DeleteObject(hBitmap);
}
DeleteDC(memDc);

marcel
10th August 2007, 16:23
QPainter::setRedirected is not meant to be used inside a paintEvent.
You just do it once, for every widget, somewhere else, and just use the pixmap.

However, a better solution is this:


QPixmap QPixmap::grabWidget(QWidget * widget, const QRect &rect)
{
if (!widget)
return QPixmap();

if (widget->testAttribute(Qt::WA_PendingResizeEvent) || !widget->testAttribute(Qt::WA_WState_Created))
sendResizeEvents(widget);

QRect r(rect);
if (r.width() < 0)
r.setWidth(widget->width() - rect.x());
if (r.height() < 0)
r.setHeight(widget->height() - rect.y());

if (!r.intersects(widget->rect()))
return QPixmap();

QPixmap res(r.size());
widget->render(&res, -r.topLeft(), r,
QWidget::DrawWindowBackground | QWidget::DrawChildren | QWidget::IgnoreMask);
return res;
}
As you can see, this is the grabWidget function from QPixmap.
I think it is better to just call QWidget::render. In fact, I think you can use most of the code in this function.

QPainter::setRedirected is too hard to use.

But I wonder, if you use a pixmap top show the actual widgets, how do you handle widget interaction? For example when a button is pressed... Do you plan to update the pixmap?

EDIT: if you use QPainter::setRedirected you have to send paint events to the widget(s) in question to make them paint themselves.

EDIT2: I guess you'll have to try many solutions and many methods until you find something that works well. I never tried something like this, so at most I can give you some suggestions which are not guaranteed to work( but the logical conclusion is that they do ).
Anyway, it would be nice to show us a demo after you finish it.

Regards

kernel_panic
10th August 2007, 16:28
button presses and everything else works fine. you just don't see the controls.
and for resizing and moving i've the solution from my skin-classes.

marcel
10th August 2007, 16:32
Here's a sample on how to call setRedirected(still from the Qt sources):


// Redirect all paint commands from the widget to the paint device and
// tell the widget to repaint itself.
QPainter::setRedirected(widget, result, rect.topLeft() - offset);
QPaintEvent paintEvent(rect & widget->rect());
QApplication::sendEvent(widget, &paintEvent);
QPainter::restoreRedirected(widget); // you won't need this however



Regards

kernel_panic
10th August 2007, 16:40
i've done it!!!!!!!!!!
IT WORKS!

and less work than the example on codeproject.

marcel
10th August 2007, 16:43
I think I better build the example since your exe is linked agains mingwm10.dll, and I don't have mingw.

Regards

marcel
10th August 2007, 16:47
OK. Really nice!!
And it doesn't kill the processor either, like the original example.

EDIT:


setWindowFlags(Qt::FramelessWindowHint | Qt::Widget);

I used this instead of subwindow, since I cannot spot it in the task bar.

Regards

kernel_panic
10th August 2007, 17:47
i hope this will make the windows-qt world much better.
grins

kernel_panic
11th August 2007, 12:35
i've setup my skin-classes with the argb support. look into the Software section.:cool: