Sign in to follow this  

DirectX with Qt

This topic is 2567 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I made a class that uses DirectX and Qt

/** @file Defines the widget to display a Direct3D context */ 
#ifndef _QD3DWIDGET_H_
#define _QD3DWIDGET_H_

#include <QtGui/QWidget>
#include "ui_Main.h"

struct IDirect3D9;
struct IDirect3DDevice9;

class QD3DWidget : public QWidget
{
Q_OBJECT

public:
/** Constructor */
QD3DWidget( QWidget* pParent = NULL);

/** Destructor */
~QD3DWidget();

/** a hint to Qt to give the widget as much space as possible */
QSizePolicy sizePolicy() const { return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); }
/** a hint to Qt that we take care of the drawing for ourselves, thankyouverymuch */
QPaintEngine *paintEngine() const { return NULL; }

protected:
/** Initialized the D3D environment */
void Setup();

/** Destroys the D3D environment */
void Close();

/** paints the scene */
void paintEvent( QPaintEvent* pEvent);

private:
/** D3D stuff */
IDirect3D9* mD3D;
IDirect3DDevice9* mDevice;
Ui::Form ui;
};

#endif // _QD3DWIDGET_H_


#include "QD3DWidget.h" 

#include <QMessageBox>
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>

// Constructor
QD3DWidget::QD3DWidget( QWidget* pParent)
: QWidget( pParent)
{
ui.setupUi(this);

mD3D = NULL;
mDevice = NULL;

setMinimumSize( 400, 400);
setAttribute( Qt::WA_OpaquePaintEvent, true);
setAttribute( Qt::WA_PaintOnScreen, true);

Setup();
}

// Destructor
QD3DWidget::~QD3DWidget()
{
Close();
}

// Initialized the D3D environment
void QD3DWidget::Setup()
{
HWND windowHandle = winId();

// create Direct3D9 object
mD3D = Direct3DCreate9( D3D_SDK_VERSION);
if( NULL == mD3D)
QMessageBox::critical(this,
"ERROR",
"Failed to create D3D object",
QMessageBox::Ok);

// create D3D device
// pack hier deine eigenen PresentationParams rein
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information

ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
d3dpp.hDeviceWindow = windowHandle; // set the window to be used by Direct3D


HRESULT hr = mD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
windowHandle,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&mDevice);

if( FAILED( hr))
QMessageBox::critical(this,
"ERROR",
"Failed to create D3D device",
QMessageBox::Ok);
}

// Destroys the D3D environment
void QD3DWidget::Close()
{
if( mDevice)
mDevice->Release();
if( mD3D)
mD3D->Release();
}

// paints the scene
void QD3DWidget::paintEvent( QPaintEvent* pEvent)
{
// clear render buffer
HRESULT hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
if( FAILED( hr))
QMessageBox::critical(this,
"ERROR",
"Failed to clear backbuffer.",
QMessageBox::Ok);

mDevice->BeginScene(); // begins the 3D scene

mDevice->EndScene(); // ends the 3D scene

// and show the result
hr = mDevice->Present(NULL, NULL, NULL, NULL); // displays the created frame on the screen
if( FAILED( hr))
QMessageBox::critical(this,
"ERROR",
"Failed to Present().",
QMessageBox::Ok);

// trigger another update as soon as possible
update();
}


and got this window:


But I would leave the Direct3D rendering in just a portion of the window, something like a Viewport of 3D studio Max, how do this?

Thanks

Share this post


Link to post
Share on other sites
Put your QD3DWidget in a parent widget's layout. Off the top of my head, something like:


class Window : public QWidget
{
public:
Window() :
QWidget(0) // top-level, no parent
{
QHBoxLayout *layout = new QHBoxLayout;
setLayout(layout);
layout->addWidget(new QD3DWidget(this));
layout->addWidget(new QPushButton("hello", this));
}
};


This will create a window with your D3D widget on the left and a button on the right (if I've done everything correctly).

There are a bunch of other layouts you might wnt to use rather than a QHBoxLayout, but that's the general idea.

EDIT: or, presumably D3D has an equivalent to glViewport. You could use that if you want to split the D3D widget itself.

Share this post


Link to post
Share on other sites
the_edd, thank you very much!
now working :)

Taking this thread, I have another doubt (idiot):

I have an abstract class:
class IObserver
{
public:
virtual void handle_Event(const std::string &msg) = 0;
};





And I have my class that inherits QWidget
class server_control : public QWidget
{
Q_OBJECT

public:
server_control(Server* s, QWidget *parent = 0);
~server_control();

private:
Ui::server_control ui;

Server* server;

std::string text_map;
std::string text_server;
std::string text_type_net;
std::string text_password;
int max_players;
int port;

QTextTableFormat tableFormat;

public slots:
void Submit();
};




But when I try to make my class inherit the abstract class IObserver, it shows the following error:
[quote]1>dedicatedserver.cpp(142): error C2259: 'server_control' : cannot instantiate abstract class
1> due to following members:
1> 'void IObserver::handle_Event(const std::string &)' : is abstract
1> d:\projetos\dedicatedserver\dedicatedserver\Observer.h(15) : see declaration of 'IObserver::handle_Event'[quote]

And it points to that line when instantiate the object (the class that I'm trying to inherit)
s_control = new server_control(server);




Why? :(

[Edited by - alliedwarrior on December 4, 2010 7:25:03 AM]

Share this post


Link to post
Share on other sites
Because you haven't implemented the pure-virtual handle_Event method in your derived class. The error message is quite helpful in this case, actually.

Share this post


Link to post
Share on other sites
class server_control : public QWidget, public IObserver
{
Q_OBJECT

public:
server_control(Server* s, QWidget *parent = 0);
~server_control();

virtual void handle_Event(const std::string &msg);
private:
//....

}


Now that I have implemented the following error appears:
Quote:
server_control.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall server_control::handle_Event(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?handle_Event@server_control@@UAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)


[crying]

Share this post


Link to post
Share on other sites
The compiler turns C++ source files in to object files (typically .obj extension for Visual C++). For convenience, object files can optionally be bundled in to what's called a static library (typically a .lib extension for Visual C++). The linker then takes these object files and/or static libraries and glues them together in to an executable or dynamic library.

You are getting an error at the linking stage. Your code mentions a server_control::handle_Event function but the linker cannot find the object file/static library that contains the compiled definition of this method ("unresolved external symbol").

So, check that the source file that contains the definition of server_control::handle_Event is mentioned in your Visual C++ solution/project or your Qt .pro file.

I empathise with your desire to jump in to creating GUIs and visuals at an early stage, but I'd recommend learning a little more about the basics of C++ before continuing too much further. The last two questions are C++ 101 (and actually the first question can be answered by following any Qt tutorial, including the ones found inside Qt Assistant).

Share this post


Link to post
Share on other sites
The strange thing is that this happens even I trying something very simple and in the same header:

server_control.h
class AbstractClass {
public:
virtual void AbstractMemberFunction() = 0; //pure virtual function makes this class Abstract class
};

class server_control : public QWidget, public AbstractClass
{
Q_OBJECT

public:
server_control(Server* s, QWidget *parent = 0);
~server_control();

void AbstractMemberFunction();
private:
Ui::server_control ui;

Server* server;

std::string text_map;
std::string text_server;
std::string text_type_net;
std::string text_password;
int max_players;
int port;

QTextTableFormat tableFormat;

public slots:
void Submit();
};




Quote:
error LNK2001: unresolved external symbol "public: virtual void __thiscall server_control::AbstractMemberFunction(void)" (?AbstractMemberFunction@server_control@@UAEXXZ)


I tested in another class that does not inherit QWidget, and it worked perfectly:
class AbstractClass {
public:
virtual void AbstractMemberFunction() = 0; //pure virtual function makes this class Abstract class
};

class Test : public AbstractClass
{
public:
Test() { }
~Test() { }
void AbstractMemberFunction();
}

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
But do you actually try to *create* a Test object?



No,
I did the test now and I created the object, and received the same error [crying]

my .pro
Quote:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<QTDIR>C:\Qt\4.7.1</QTDIR>
</PropertyGroup>
<PropertyGroup />
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="QTDIR">
<Value>$(QTDIR)</Value>
<EnvironmentVariable>true</EnvironmentVariable>
</BuildMacro>
</ItemGroup>
</Project>

Share this post


Link to post
Share on other sites
Quote:
Original post by alliedwarrior
Quote:
Original post by the_edd
But do you actually try to *create* a Test object?



No,
I did the test now and I created the object, and received the same error [crying]

my .pro
Quote:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<QTDIR>C:\Qt\4.7.1</QTDIR>
</PropertyGroup>
<PropertyGroup />
<ItemDefinitionGroup />
<ItemGroup>
<BuildMacro Include="QTDIR">
<Value>$(QTDIR)</Value>
<EnvironmentVariable>true</EnvironmentVariable>
</BuildMacro>
</ItemGroup>
</Project>


Hi AlliedWarrior, here has a member called VitaliBR he know much QT, send u a PM.
:D
hugs

Share this post


Link to post
Share on other sites
for of all you should be using QString and not std::string in your server control. If you really need to convert between the two (shouldn't need to really) you can use QString::fromStdString() or QString::fromStdWString(). Also you forgot to implement the function void AbstractMemberFunction();

Share this post


Link to post
Share on other sites
I deleted the files Visual C + + solution / project and Qt. Pro file and now is working (stranger) :)

I have a doubt regarding the DirectX viewport, I'm using Qt Designer.
I created a QHBoxLayout, but when I try to access it in code and pass the QD3DWidget the viewport goes white (and it was supposed to be blue, the color that is defined in the Direct3D by me)

Share this post


Link to post
Share on other sites
Quote:
Original post by SeaBourne
for of all you should be using QString and not std::string in your server control.


Why? It's a perfectly valid decision but I wouldn't say "should". Perhaps Qt is being used as an implementation detail, in which case std::string is just fine.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
Quote:
Original post by SeaBourne
for of all you should be using QString and not std::string in your server control.


Why? It's a perfectly valid decision but I wouldn't say "should". Perhaps Qt is being used as an implementation detail, in which case std::string is just fine.


That's like using C# but not using any of the .NET classes.

Share this post


Link to post
Share on other sites
If anything, I would say the opposite. The C++ standard library is the approximate analog to the .Net framework.

Again, there's no reason in terms of soundness of engineering why QString must be used instead of std::string, necessarily. It has some nicer stuff for Unicode out the box but if std::string is used elsewhere in the application, presumably that's not an issue.

Share this post


Link to post
Share on other sites
I would like to use the QT Designer,
So I created a QHBoxLayout but I can not add in my QD3DWidget QHBoxLayout, I'm trying something like:
Window::Window(QWidget* parent)
: QWidget(0) // top-level, no parent
{
ui.setupUi(this);

ui.horizontalLayout->addWidget(new QD3DWidget(this));
}


The viewport directx does not appear, only a white window appears, and I set to be blue in directX,and when I make the code directly (without ui) it is blue

Thanks

Share this post


Link to post
Share on other sites
What do you mean you cannot add it to the layout? Code looks fine. Btw if you have a parameter in the constructor you have to pass it to the base constructor. You passing 0 is not correct. Because if you was to pass this to that parameter it would cause a memleak. Due to you not deleting the Window since passing "this" would cause the Window to be correctly deleted.

Also you do not need to pass "this" to the ctor of the QD3DWidget since it's being added to a layout. As the layout takes ownership of the widget.

Share this post


Link to post
Share on other sites
Quote:
Original post by SeaBourne
What do you mean you cannot add it to the layout? Code looks fine. Btw if you have a parameter in the constructor you have to pass it to the base constructor. You passing 0 is not correct. Because if you was to pass this to that parameter it would cause a memleak. Due to you not deleting the Window since passing "this" would cause the Window to be correctly deleted.

Also you do not need to pass "this" to the ctor of the QD3DWidget since it's being added to a layout. As the layout takes ownership of the widget.


Sorry, we did not know of these errors on Qt (I'm new in programming with Qt) :)

As the window, I am creating in QtDesigner:


Using the ui, the code looks like, and the window when run like this:
Window::Window(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);

ui.horizontalLayout->addWidget(new QD3DWidget());

}



And when I create my QHBoxLayout the code looks like this:
Window::Window(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);


QHBoxLayout *layout = new QHBoxLayout();
setLayout(layout);
layout->addWidget(new QD3DWidget());
}



A note: The blue screen means that the code of DirectX is working, I configured it to clean the screen with the color blue

and using the code (last image), so if I do (wrong):
layout->addWidget(new QD3DWidget()); //not using this

it is white
and if I do so, it turns blue (correct):
layout->addWidget(new QD3DWidget(this)); //using this


Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by SeaBourne
Btw if you have a parameter in the constructor you have to pass it to the base constructor. You passing 0 is not correct. Because if you was to pass this to that parameter it would cause a memleak. Due to you not deleting the Window since passing "this" would cause the Window to be correctly deleted.


Passing 0 is entirely correct for a top-level window. See the QWidget documentation.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
Quote:
Original post by SeaBourne
Btw if you have a parameter in the constructor you have to pass it to the base constructor. You passing 0 is not correct. Because if you was to pass this to that parameter it would cause a memleak. Due to you not deleting the Window since passing "this" would cause the Window to be correctly deleted.


Passing 0 is entirely correct for a top-level window. See the QWidget documentation.


Yes I know. I have a certification for Qt.

For instance (this is an example)


void Foo::bar()
{
QD3DWidget* newWidget = new QD3DWidget(this);
}



Now if you kept it like it currently is, newWidget would cause a memory leak due to parent not being set. "Foo::Foo(QWidget* parent) : QWidget(0)".

Now if you pass parent to QWidget like you should, then there would be no memleak but then again that object would still persist through out the life of that class due to the way Qt does it's memory management.

So you are correct but it is wrong. If you aren't going to use the parent parameter you might as well remove it and not use it at all.

Share this post


Link to post
Share on other sites
Quote:
Original post by SeaBourne
can you post the full code for your source of QD3DWidget?

Yes guy :)

/** @file Defines the widget to display a Direct3D context */ 
#ifndef _QD3DWIDGET_H_
#define _QD3DWIDGET_H_

#include <QtGui/QWidget>

struct IDirect3D9;
struct IDirect3DDevice9;

class QD3DWidget : public QWidget
{
Q_OBJECT

public:
/** Constructor */
QD3DWidget( QWidget* pParent = NULL);

/** Destructor */
~QD3DWidget();

/** a hint to Qt to give the widget as much space as possible */
QSizePolicy sizePolicy() const { return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); }
/** a hint to Qt that we take care of the drawing for ourselves, thankyouverymuch */
QPaintEngine *paintEngine() const { return NULL; }

protected:
/** Initialized the D3D environment */
void Setup();

/** Destroys the D3D environment */
void Close();

/** paints the scene */
void paintEvent( QPaintEvent* pEvent);

private:
/** D3D stuff */
IDirect3D9* mD3D;
IDirect3DDevice9* mDevice;
};

#endif // _QD3DWIDGET_H_


#include "QD3DWidget.h" 

#include <QMessageBox>
#define WIN32_LEAN_AND_MEAN
#include <d3d9.h>
#include <d3dx9.h>

// Constructor
QD3DWidget::QD3DWidget( QWidget* pParent)
: QWidget( pParent)
{
mD3D = NULL;
mDevice = NULL;

setMinimumSize( 400, 400);
setAttribute( Qt::WA_OpaquePaintEvent, true);
setAttribute( Qt::WA_PaintOnScreen, true);

Setup();
}

// Destructor
QD3DWidget::~QD3DWidget()
{
Close();
}

// Initialized the D3D environment
void QD3DWidget::Setup()
{
HWND windowHandle = winId();

// create Direct3D9 object
mD3D = Direct3DCreate9( D3D_SDK_VERSION);
if( NULL == mD3D)
QMessageBox::critical(this,
"ERROR",
"Failed to create D3D object",
QMessageBox::Ok);

// create D3D device
// pack hier deine eigenen PresentationParams rein
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information

ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
d3dpp.hDeviceWindow = windowHandle; // set the window to be used by Direct3D


HRESULT hr = mD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
windowHandle,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&mDevice);

if( FAILED( hr))
QMessageBox::critical(this,
"ERROR",
"Failed to create D3D device",
QMessageBox::Ok);
}

// Destroys the D3D environment
void QD3DWidget::Close()
{
if( mDevice)
mDevice->Release();
if( mD3D)
mD3D->Release();
}

// paints the scene
void QD3DWidget::paintEvent( QPaintEvent* pEvent)
{
// clear render buffer
HRESULT hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
if( FAILED( hr))
QMessageBox::critical(this,
"ERROR",
"Failed to clear backbuffer.",
QMessageBox::Ok);

mDevice->BeginScene(); // begins the 3D scene

mDevice->EndScene(); // ends the 3D scene

// and show the result
hr = mDevice->Present(NULL, NULL, NULL, NULL); // displays the created frame on the screen
if( FAILED( hr))
QMessageBox::critical(this,
"ERROR",
"Failed to Present().",
QMessageBox::Ok);

// trigger another update as soon as possible
update();
}


Thanks :)

Share this post


Link to post
Share on other sites

This topic is 2567 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this