使用DirectX 9 在QtWidget中作图,绘制在自定义的Widget中。
通过继承QWidget,并且重写paintEngine函数,返回0,表示不使用QT默认的绘制引擎,使用自定义的绘制引擎。
通过设置属性WA_PaintOnScreen,表明直接绘制到屏幕上,
通过设置属性WA_OpaquePaintEvent,表明绘制时,重绘控件区域的所有像素
通过设置属性WA_NoSystemBackground,表明不需要QT默认的控件背景。
使用QTimer,定时重绘控件,即可实现帧更新效果,
自定义控件GDXWidget继承自QWidget,头文件代码如下:
#ifndef _GDXWIDGET_H_ #define _GDXWIDGET_H_ #include <QWidget> #include <d3d9.h> #include <d3dx9.h> struct SCustomVertex { float x, y, z; DWORD color; }; #define D3DFVF_SCUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE) class GDXWidget: public QWidget { Q_OBJECT public: GDXWidget(QWidget *parent = 0, Qt::WindowFlags f = 0); ~GDXWidget(); //不使用Qt默认的绘制引擎 virtual QPaintEngine* paintEngine() const { return 0; } //初始化Direct3D bool InitD3D(); //创建简单三角形 bool CreateTriangle(); //更新三角形 void Frame(); public slots: //渲染 void Render(); protected: virtual void paintEvent(QPaintEvent *event); virtual void resizeEvent(QResizeEvent *event); private: LPDIRECT3D9 m_pD3D; LPDIRECT3DDEVICE9 m_pDevice; LPDIRECT3DVERTEXBUFFER9 m_pVB; }; #endif //_GDXWIDGET_H_
CPP文件代码如下:
#include "GDXWidget.h" #include "strsafe.h" #include <QResizeEvent> #include <QTimer> GDXWidget::GDXWidget(QWidget *parent, Qt::WindowFlags f): QWidget(parent, f), m_pD3D(0), m_pDevice(0), m_pVB(0) { //如果使用用户自定义绘制,则需要设置WA_PaintOnScreen setAttribute(Qt::WA_PaintOnScreen, true); //不需要默认的Qt背景 setAttribute(Qt::WA_NoSystemBackground, true); //重绘时,绘制所有像素 setAttribute(Qt::WA_OpaquePaintEvent, true); QTimer *pTimer = new QTimer(this); connect(pTimer, SIGNAL(timeout()), this, SLOT(repaint())); pTimer->start(16); //约60FPS } GDXWidget::~GDXWidget() { if(0 != m_pVB) m_pVB->Release(); if(0 != m_pDevice) m_pDevice->Release(); if(0 != m_pD3D) m_pD3D->Release(); } void GDXWidget::paintEvent(QPaintEvent *event) { Render(); } void GDXWidget::resizeEvent(QResizeEvent *event) {} bool GDXWidget::InitD3D() { if(0 == (m_pD3D = Direct3DCreate9(D3D_SDK_VERSION))) return false; D3DPRESENT_PARAMETERS d3dpp; ZeroMemory(&d3dpp, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; if(FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, winId(), D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &m_pDevice))) return false; m_pDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); m_pDevice->SetRenderState( D3DRS_LIGHTING, FALSE ); return true; } bool GDXWidget::CreateTriangle() { SCustomVertex vertices[] = { { -1.0f,-1.0f, 0.0f, 0xffff0000, }, { 1.0f,-1.0f, 0.0f, 0xff0000ff, }, { 0.0f, 1.0f, 0.0f, 0xffffffff, }, }; if(FAILED(m_pDevice->CreateVertexBuffer(3 * sizeof(SCustomVertex), 0, D3DFVF_SCUSTOMVERTEX, D3DPOOL_DEFAULT, &m_pVB, 0))) return false; void* pVertices; if(FAILED(m_pVB->Lock(0, sizeof(vertices), (void**)&pVertices, 0))) return false; memcpy(pVertices, vertices, sizeof(vertices)); m_pVB->Unlock(); return true; } void GDXWidget::Render() { m_pDevice->Clear(0, 0, D3DCLEAR_TARGET , D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); if(SUCCEEDED(m_pDevice->BeginScene())) { Frame(); m_pDevice->SetStreamSource(0, m_pVB, 0, sizeof(SCustomVertex)); m_pDevice->SetFVF(D3DFVF_SCUSTOMVERTEX); m_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1); m_pDevice->EndScene(); } m_pDevice->Present(0, 0, 0, 0); } void GDXWidget::Frame() { D3DXMATRIXA16 matWorld; UINT iTime = timeGetTime() % 1000; FLOAT fAngle = iTime * ( 2.0f * D3DX_PI ) / 1000.0f; D3DXMatrixRotationY( &matWorld, fAngle ); m_pDevice->SetTransform( D3DTS_WORLD, &matWorld ); D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f ); D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f ); D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f ); D3DXMATRIXA16 matView; D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec ); m_pDevice->SetTransform( D3DTS_VIEW, &matView ); D3DXMATRIXA16 matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f ); m_pDevice->SetTransform( D3DTS_PROJECTION, &matProj ); } 然后通过Qt设计师,拉一个窗口框GQtDX9Dialog,将GDXWidget的一个实例放入该窗口即可。
CPP代码如下:
#include "GQtDX9Dialog.h" #include "GDXWidget.h" GQtDX9Dialog::GQtDX9Dialog(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { ui.setupUi(this); resize(850, 650); GDXWidget *pDXWidget = new GDXWidget(this); pDXWidget->resize(800, 600); pDXWidget->InitD3D(); pDXWidget->CreateTriangle(); pDXWidget->move(30, 30); } GQtDX9Dialog::~GQtDX9Dialog() {}
而main函数很简单:
#include "GQtDX9Dialog.h" #include <QtGui/QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); GQtDX9Dialog w; w.show(); return a.exec(); }
运行效果如下: