我想制作一个透明的无框 QWidget,它看起来像是在另一个 QWidget 之上呈现的。
我的意图是使用DirectX和Qt在 3D 游戏之上创建一个HUD。
到目前为止,在我的努力中,我的 QMainWindow 包含一个定制的 DirectX-Widget,它是通过在 DirectX 中创建交换链时将普通 QWidget 的 HWND 交给 DirectX 创建的,然后使用 QTimer 创建自定义渲染循环(参见代码下面)。
然后我尝试在 QMainWindow 顶部渲染一个新的Overlay -widget(我的预期 HUD),并使其看起来像是主窗口的一部分。
通过在叠加层上使用以下标志,我可以使其行为与我想要的相似,但我仍然无法摆脱框架。
setWindowFlags(Qt::WindowStaysOnBottomHint);
setAttribute(Qt::WA_TranslucentBackground, true);
setAttribute(Qt::WA_TransparentForMouseEvents);
左图显示了它的真实外观,通过 MS Paint 的魔力,右图是我想要的样子。
正如您从图片中看到的那样,透明度在 DirectX 小部件之上不起作用,但它似乎在普通小部件(如工具栏)之上工作,当我尝试使用 QPainter 之类的东西时似乎也是如此而不是 DirectX。
有谁知道为什么会这样?有关如何摆脱 DirectX 中的框架或实现类似功能的任何建议?
源代码
您可以从此处下载完整的Visual Studio 2010项目。
如果您想自己编译,可能需要用于 Qt4 的 Visual Studio 插件 1.1.11和2010 年 6 月的 DirectX SDK 。
大部分源代码也如下所示。我试图让它尽可能短。
#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);
};
};