I want to make a transparent frame-less QWidget which looks like it is being rendered on top of another QWidget.
My intention is to create a HUD on top of a 3D-game using DirectX and Qt.
In my efforts so far my QMainWindow contains a custom made DirectX-Widget, which is created by handing the HWND of an ordinary QWidget to DirectX when creating the swap chain in DirectX, and then creating a custom render loop by using a QTimer (see code below).
I then try to render a new Overlay-widget (my intended HUD) on top of the QMainWindow and make it appear like it is part of the main window.
By using the following flags on the Overlay I can make it behave similarly to what I want, but I still can't get rid off the frame.
setWindowFlags(Qt::WindowStaysOnBottomHint);
setAttribute(Qt::WA_TranslucentBackground, true);
setAttribute(Qt::WA_TransparentForMouseEvents);
The left image shows what it really looks like, and by the magic of MS Paint the right image is how I would like it to be.
As you can see from the picture the transparency does not work on top of the DirectX-widget, but it appears to be working on top of ordinary Widgets such as the toolbar, and the same appears to be true when I experimented using something like QPainter instead of DirectX.
Does anyone know why this is happening? Any suggestions on how to get rid of the frame in DirectX or to achieve something similar?
Source code
You can download the full Visual Studio 2010 project from here.
Probably requires Visual Studio Add-in 1.1.11 for Qt4 and June 2010 DirectX SDK if you want to compile it yourself.
Most of the source code is also shown below. I tried to make it as short as possible.
#pragma once
#include <QtGui/QMainWindow>
#include <QtCore/QTimer>
#include "ui_mainwindow.h"
#include "ui_overlay.h"
class DXWidget : public QWidget
{
Q_OBJECT
private:
QTimer* timer;
public:
DXWidget(QWidget* parent) : QWidget(parent){}
~DXWidget()
{
// dx cleanup
};
void init(HWND windowHandle)
{
// init DirectX using our HWND as render target
initDX(windowHandle);
// start render loop
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(render()));
timer->start(0);
}
private:
void initDX(HWND windowHandle)
{
// inits DirectX stuff
}
private slots:
void render()
{
// renders a frame to the Widget using DirectX
}
};
class Overlay : public QMainWindow
{
Q_OBJECT
private:
Ui::Overlay ui;
public:
Overlay(QWidget* parent) : QMainWindow(parent)
{
ui.setupUi(this);
QWidget::setWindowFlags(Qt::WindowStaysOnBottomHint);
QWidget::setAttribute(Qt::WA_TranslucentBackground, true);
show();
move(6, 50); // move window so we can see it overlapping our toolbar
};
~Overlay()
{
};
};
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
Ui::MainWindowClass ui;
DXWidget* widget;
public:
MainWindow()
{
// setup window
ui.setupUi(this);
// create DirectX-widget
widget = new DXWidget(this);
MainWindow::setCentralWidget(widget);
// hand HWND to DirectXs swap chain so
// we can draw to that window
widget->init(widget->winId());
// create overlay
new Overlay(this);
};
};