现在的位置: 首页 > 综合 > 正文

QT与VTK的结合开发

2013年09月25日 ⁄ 综合 ⁄ 共 5329字 ⁄ 字号 评论关闭

最近,由于项目的需要,我打算使用VTK来开发程序,VTK全名是VisualizationToolKit,它是一套跨平台的C++库,对OpenGL作了较全面的封装,将各种三维模型的存储,运算,显示,交互等内容全都以类的方式封装起来了,并且提供比OpenGL强大得多的功能。可惜VTK最大的缺点是,没有免费的教程,它只提供免费的API手册,其中只是对各个类的功能罗列而已,而参考书籍则需要花几十美元去购买,所以学习VTK只能依靠它的大量Example了。

由于我的项目需要兼故未来跨平台的可能(目前只在Windows下),所以必须使用一套跨平台的开发库,在VTK/Examples/GUI的例子里,Windows平台下只有SDK,MFC,C++ Builder这几个例子,另外还有Motif,Python,Tcl,选择是不少,但是Motif听说编程比较麻烦,我也从来没有接触过,Tcl和Python作为脚本语言,其性能和安全性则有些令人担忧,也就是说,这里面没有一个是我能使用的。。。说起跨平台,由于单位里项目的关系,我接触得比较多的就是QT了,所以,在未选定VTK之前,其实我是打算使用QT+OpenGL的组合方式来开发这个软件的,其实,如果不考虑跨平台,我还是会选择QT,因为它的事件处理方式对于用惯Delphi的我而言,更为顺手,那么现在使用了VTK,是否还能将VTK和QT组合起来使用呢。。

作为试验,我仿照VTK/Examples/GUI/Win32/SampleMFC,制作了以下这个小程序,很顺利,结果证明了我的猜想,QT和VTK是可以很方便的结合起来的,下面就跟我来一步步制作这个程序吧:
1)从http://www.vtk.org下载VTK的最新版本,我用的是4.2。该包中只有程序文件,你还需要自己编译,为此你还需要CMake,用来生成VC的.dsw,.dsp文件。然后用VC打开生成的工程文件,并进行编译。最后将编译后生成的目录:VTK/bin/Debug加入到Windows系统环境的Path中。
2)下载QT,我目前使用的是QT334,打开VC的Tools->Options->Directories,将QT的bin,include,lib路径分别加入其中。
3)在VC中,建立一个新的Win32 Console Application工程,建立一个main.cpp,作为main函数的入口,代码如下:
#include <qapplication.h>

#include "testwindow.h"

int main(int argc, char** argv)
{
 QApplication app(argc, argv);

 TestWindow testwin;
 testwin.show();
 app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
 return app.exec();
}

其中的testwindow.h,是程序的主窗口TestWindow的头文件,一会将会建立该文件。
这段程序所做的是,初始化QApplication,并将TestWindow显示出来,并进入主程序的消息循环app.exec()。

下面实现TestWindow类,分别建立testwindow.h和testwindow.cpp
testwindow.h:
#include <qmainwindow.h>

class TestWindow: public QMainWindow
{
 Q_OBJECT

public:
 TestWindow();
 ~TestWindow();
};

testwindow.cpp:
#include "testwindow.h"
#include "moc_testwindow.h"

TestWindow::TestWindow()
{
}

TestWindow::~TestWindow()
{
}

你是否注意到了testwindow.cpp中的#include "moc_testwindow.h"一行,这个moc_testwindow.h将会建立TestWindow的RTTI信息,并且绑定消息等,它并不需要我们自己实现,而是由qt的一个名为moc的程序建立,在VC的FileView中,右键点击testwindow.h,并选择Settings,然后在打开的Project Settings对话框中选择Custom Build页,在Commands中填入:
moc -i testwindow.h -o moc_testwindow.h
意思是调用moc程序,根据testwindow.h的内容,自动生成一个名为moc_testwindow.h的moc文件。
在Outputs中填入:
moc_testwindow.h

然后,在Project Settings中选中projct,在Link页的Object/library modules中加入:qt-mt334.lib。

编译程序,如果顺利,一个简单的QT程序就写好了,它会在启动后显示一个空白的窗口。

3)加入VTK的代码,这些代码都可以参考Examples/GUI/Win32/SampleMFC程序,将testwindow.h改造成如下:
#include <qmainwindow.h>
#include "vtkRenderer.h"
#include "vtkWin32OpenGLRenderWindow.h"
#include "vtkWin32RenderWindowInteractor.h"

class TestWindow: public QMainWindow
{
 Q_OBJECT

public:
 TestWindow();
 ~TestWindow();

protected:
 virtual void paintEvent(QPaintEvent *);
 virtual bool winEvent(MSG *);

private:
 vtkRenderer *Renderer;
 vtkWin32OpenGLRenderWindow *RenderWindow;
 vtkWin32RenderWindowInteractor *Interactor;
};

testwindow.cpp改造成如下:
#include "testwindow.h"
#include "moc_testwindow.h"

#include "vtkActor2D.h"
#include "vtkTextMapper.h"
#include "vtkTextProperty.h"
#include "vtkDataSetReader.h"
#include "vtkDataSetMapper.h"

#include "vtkCommand.h"
#include "vtkCamera.h"
#include "vtkWin32RenderWindowInteractor.h"
#include "vtkInteractorStyleTrackballCamera.h"

TestWindow::TestWindow()
{
 this->Renderer = vtkRenderer::New();
 this->Renderer->SetBackground(0.3, 0.5, 0.1);
 this->RenderWindow = vtkWin32OpenGLRenderWindow::New();
 this->RenderWindow->AddRenderer(this->Renderer);
 this->Interactor = vtkWin32RenderWindowInteractor::New();

 vtkActor2D *actor2d = vtkActor2D::New();
 vtkTextMapper *txt = vtkTextMapper::New();
 actor2d->SetMapper(txt);
 txt->SetInput("Hello World");
 txt->GetTextProperty()->SetFontSize(24);
 this->Renderer->AddProp(actor2d);
 txt->Delete();
 actor2d->Delete();

 vtkActor *actor = vtkActor::New();
 vtkDataSetReader *reader = vtkDataSetReader::New();
 reader->SetFileName("weldedSpheres.vtk");
 vtkDataSetMapper *mapper = vtkDataSetMapper::New();
 mapper->SetInput(reader->GetOutput());
 actor->SetMapper(mapper);
 this->Renderer->AddProp(actor);
 mapper->Delete();
 reader->Delete();
 actor->Delete();
}

TestWindow::~TestWindow()
{
 if (this->Interactor) {
  this->Interactor->Delete();
 }
 if (this->Renderer) {
  this->Renderer->SetRenderWindow(NULL);
 }
 if (this->RenderWindow) {
  this->RenderWindow->Delete();
 }
 if (this->Renderer) {
  this->Renderer->Delete();
 }
}

void TestWindow::paintEvent(QPaintEvent *e)
{
 if (! this->Interactor->GetInitialized()) {
  this->RenderWindow->SetWindowId(this->winId());
  this->RenderWindow->WindowInitialize();
  this->Interactor->SetRenderWindow(this->RenderWindow);
  this->Interactor->Initialize();
 }
 this->RenderWindow->Render();
}

bool TestWindow::winEvent(MSG *msg)
{
 switch (msg->message) {
  case WM_LBUTTONDOWN:
  case WM_LBUTTONUP:
  case WM_MBUTTONDOWN:
  case WM_MBUTTONUP:
  case WM_RBUTTONDOWN:
  case WM_RBUTTONUP:
  case WM_MOUSEMOVE:
  case WM_CHAR:
  case WM_TIMER:
   if (this->Interactor->GetInitialized()) {
    vtkHandleMessage2(msg->hwnd, msg->message, msg->lParam, msg->wParam, this->Interactor);
   }
 }
 return false;
}

其中用到了一个模型文件weldedSpheres.vtk,可以在VTK中找到。可能你需要修改它的路径。

然后,再次打开Proect Settings对话框,在C/C++页中,选择Category:Preprocessor,在Additional include directories:中加入:
D:/VTK,D:/VTK/Parallel,D:/VTK/Hybrid,D:/VTK/Patented,D:/VTK/Rendering,D:/VTK/IO,D:/VTK/Imaging,D:/VTK/Graphics,D:/VTK/Filtering,D:/VTK/Common

选择Link页,选择Category:Input,在Object/library modules:中加入:
vtkRendering.lib vtkGraphics.lib vtkImaging.lib vtkIO.lib vtkFiltering.lib vtkCommon.lib vtkftgl.lib glu32.lib opengl32.lib glu32.lib opengl32.lib vtkfreetype.lib vtkpng.lib vtktiff.lib vtkzlib.lib vtkjpeg.lib vtkexpat.lib
在Addtional library path中加入:
D:/VTK/bin/debug

以上都假设VTK安装在D盘下,如果你安装在其它目录,请修改以上的路径。

好了,重新编译程序,运行,你将看到如下所示的VTK界面。

以上程序只是VTK和QT结合的简单应用,你完全可以将VTK的显示窗封装在一个QTWidget中,然后将其显示在整个程序中的一个区域中。

抱歉!评论已关闭.