VTK與MFC聯合編程實現的單文檔實例vtkSDI詳解

1. 實例的編譯運行

新建工程時,可以直接通過cmake生成,但如果工程沒有編譯完全或者安裝成功的話,在安裝目錄沒法找到GUISupport/MFC/VTKMFCSettings.cmake,從而無法正常新建工程。這裏主要講解手動新建工程的過程,以方便大家的學習

和進一步理解。

a.新建工程,然後將vtkSDI文件夾直接覆蓋工程裏面的文件,res文件可以不復制。

b.設置頭文件


b.添加lib路徑和文件


c.修改property裏面的general選項裏的character set的設置。


d.編譯運行


e.選擇vtkdata中的vtk文件,然後進行查看處理




值得注意的是,要運用vtk和MFC聯合編程,編譯VTK源代碼的時候一定要選擇vtk gui support裏的MFC.


2.實例源碼詳解

學過MFC的基本都知道,MFC中view類主要處理顯示視圖,doc類處理文檔,mainframe主要爲整個窗口的和工程的設置管理。由此,VTK與MFC聯合編程時,需要主要的是數據操作,以及顯示要很好的與MFC中的結構結合,做到MVC分離的要求和規範,視圖-模型和控制一定要處理開來,尤其是大工程的處理時,才能不混亂。


a.view類設置

頭文件

// vtkSDIView.h : interface of the CvtkSDIView class
//


#pragma once

//添加MFC顯示窗口的頭文件
#include "vtkMFCWindow.h"  

class CvtkSDIView : public CView
{
public:
  virtual ~CvtkSDIView();
#ifdef _DEBUG
  virtual void AssertValid() const;
  virtual void Dump(CDumpContext& dc) const;
#endif

  CvtkSDIDoc* GetDocument() const;
 //獲得vtkRender的指針
  vtkRenderer* GetRenderer() { ASSERT(pvtkRenderer); return pvtkRenderer; }

  virtual void OnDraw(CDC* pDC);  // overridden to draw this view

  afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  afx_msg void OnDestroy();
  afx_msg BOOL OnEraseBkgnd(CDC* pDC);
  afx_msg void OnSize(UINT nType, int cx, int cy);

private:
//顯示的變量,vtkrender和vtkMFCWindow
  vtkRenderer            *pvtkRenderer;
  vtkMFCWindow          *pvtkMFCWindow;

protected:
  DECLARE_DYNCREATE(CvtkSDIView)
  CvtkSDIView();

  virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
  virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
  virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

  DECLARE_MESSAGE_MAP()
public:
  virtual void OnInitialUpdate();
};

#ifndef _DEBUG  // debug version in vtkSDIView.cpp
inline CvtkSDIDoc* CvtkSDIView::GetDocument() const
   { return reinterpret_cast<CvtkSDIDoc*>(m_pDocument); }
#endif


實現文件

// vtkSDIView.cpp : implementation of the CvtkSDIView class
//

#include "stdafx.h"
#include "vtkSDI.h"

#include "vtkSDIDoc.h"
#include "vtkSDIView.h"

#include "vtkCallbackCommand.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CvtkSDIView

IMPLEMENT_DYNCREATE(CvtkSDIView, CView)

BEGIN_MESSAGE_MAP(CvtkSDIView, CView)
  // Standard printing commands
  ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
  ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
  ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
  ON_WM_CREATE()
  ON_WM_DESTROY()
  ON_WM_ERASEBKGND()
  ON_WM_SIZE()
END_MESSAGE_MAP()

// CvtkSDIView construction/destruction

CvtkSDIView::CvtkSDIView()
{
  this->pvtkMFCWindow     = NULL;

 //新建視圖類對象
  this->pvtkRenderer    = vtkRenderer::New();
}

CvtkSDIView::~CvtkSDIView()
{
  // delete generic vtk window
  if (this->pvtkMFCWindow) delete this->pvtkMFCWindow;
}

void CvtkSDIView::OnDraw(CDC* pDC)
{
  CvtkSDIDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);

  if (this->pvtkMFCWindow)
  {
    if (pDC->IsPrinting())
      this->pvtkMFCWindow->DrawDC(pDC);
  }
}


// CvtkSDIView printing

BOOL CvtkSDIView::OnPreparePrinting(CPrintInfo* pInfo)
{
  // default preparation
  return DoPreparePrinting(pInfo);
}

void CvtkSDIView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
  // TODO: add extra initialization before printing
}

void CvtkSDIView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
  // TODO: add cleanup after printing
}


// CvtkSDIView diagnostics

#ifdef _DEBUG
void CvtkSDIView::AssertValid() const
{
  CView::AssertValid();
}

void CvtkSDIView::Dump(CDumpContext& dc) const
{
  CView::Dump(dc);
}

CvtkSDIDoc* CvtkSDIView::GetDocument() const // non-debug version is inline
{
  ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CvtkSDIDoc)));
  return (CvtkSDIDoc*)m_pDocument;
}
#endif //_DEBUG


// CvtkSDIView message handlers

int CvtkSDIView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  if (CView::OnCreate(lpCreateStruct) == -1)
    return -1;

  return 0;
}

void CvtkSDIView::OnDestroy()
{
  // Delete the the renderer, window and interactor objects.
  if (this->pvtkRenderer)      this->pvtkRenderer->Delete();

  // destroy base
  CView::OnDestroy();
}

BOOL CvtkSDIView::OnEraseBkgnd(CDC* pDC)
{
  return TRUE;
}

void CvtkSDIView::OnSize(UINT nType, int cx, int cy)
{
  CView::OnSize(nType, cx, cy);

  if (this->pvtkMFCWindow)
    this->pvtkMFCWindow->MoveWindow(0, 0, cx, cy);
}

static void handle_double_click(vtkObject* obj, unsigned long,
                                void*, void*)
{
//交互響應回調函數,輸出提示信息
  vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj);
  if(iren && iren->GetRepeatCount())
    {
    AfxMessageBox("Double Click");
    }
}

void CvtkSDIView::OnInitialUpdate()
{
  CView::OnInitialUpdate();

//初始化的時候創建vtkMFCwindow對象
  if (this->pvtkMFCWindow) delete this->pvtkMFCWindow;
  this->pvtkMFCWindow = new vtkMFCWindow(this);

//將render對象添加到實現窗口vtkMFCwindow中
  this->pvtkMFCWindow->GetRenderWindow()->AddRenderer(this->pvtkRenderer);
  
 //添加交互中鼠標左鍵響應回調函數
  vtkCallbackCommand* callback = vtkCallbackCommand::New();
  callback->SetCallback(handle_double_click);
  this->pvtkMFCWindow->GetInteractor()->AddObserver(vtkCommand::LeftButtonPressEvent, callback, 1.0);
  callback->Delete();

}



a.Doc類設置

頭文件

// vtkSDIDoc.h : interface of the CvtkSDIDoc class
//


#pragma once

class CvtkSDIDoc : public CDocument
{
protected: // create from serialization only
  CvtkSDIDoc();
  DECLARE_DYNCREATE(CvtkSDIDoc)

// Attributes
private:
  vtkDataSetReader *pvtkDataSetReader;

// Operations
public:

// Overrides
  public:
  virtual BOOL OnNewDocument();
  virtual void Serialize(CArchive& ar);

// Implementation
public:
  virtual ~CvtkSDIDoc();
#ifdef _DEBUG
  virtual void AssertValid() const;
  virtual void Dump(CDumpContext& dc) const;
#endif

private:
  void ExecutePipeline();
  void RemoveActors();

//數據處理和顯示的mapper和actor對象
  vtkDataSetMapper  *pvtkDataSetMapper;
  vtkActor      *pvtkActor;

  vtkActor2D      *pvtkActor2D;
  vtkTextMapper    *pvtkTextMapper;

// Generated message map functions
protected:
  DECLARE_MESSAGE_MAP()
public:
  virtual void OnCloseDocument();
  virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
};


實現文件

// vtkSDIDoc.cpp : implementation of the CvtkSDIDoc class
//

#include "stdafx.h"
#include "vtkSDI.h"

#include "vtkSDIDoc.h"
#include "vtkSDIView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CvtkSDIDoc

IMPLEMENT_DYNCREATE(CvtkSDIDoc, CDocument)

BEGIN_MESSAGE_MAP(CvtkSDIDoc, CDocument)
END_MESSAGE_MAP()


// CvtkSDIDoc construction/destruction

CvtkSDIDoc::CvtkSDIDoc()
{
  this->pvtkDataSetReader  = NULL;

 // 創建對象,從而可以顯示
  this->pvtkDataSetMapper  = vtkDataSetMapper::New();
  this->pvtkActor      = vtkActor::New();
  this->pvtkActor2D    = vtkActor2D::New();
  this->pvtkTextMapper  = vtkTextMapper::New();
}

CvtkSDIDoc::~CvtkSDIDoc()
{
}

BOOL CvtkSDIDoc::OnNewDocument()
{
  if (!CDocument::OnNewDocument())
    return FALSE;

//移除原有actor對象
  RemoveActors();

  //執行數據處理流程
  ExecutePipeline();

  return TRUE;
}




// CvtkSDIDoc serialization

void CvtkSDIDoc::Serialize(CArchive& ar)
{
  if (ar.IsStoring())
  {
    // TODO: add storing code here
  }
  else
  {
    // TODO: add loading code here
  }
}


// CvtkSDIDoc diagnostics

#ifdef _DEBUG
void CvtkSDIDoc::AssertValid() const
{
  CDocument::AssertValid();
}

void CvtkSDIDoc::Dump(CDumpContext& dc) const
{
  CDocument::Dump(dc);
}
#endif //_DEBUG


// CvtkSDIDoc commands

void CvtkSDIDoc::RemoveActors()
{
  //活的view類對象
  POSITION pos = this->GetFirstViewPosition();
  CvtkSDIView *pcvtkSDIView = NULL;

  if (pos)
  {
    pcvtkSDIView = (CvtkSDIView *)GetNextView(pos);
  }
  else  // return
  {
    ASSERT(FALSE);
    return;
  }

  //移除actor對象
  pcvtkSDIView->GetRenderer()->RemoveActor(this->pvtkActor);
  pcvtkSDIView->GetRenderer()->RemoveActor(this->pvtkActor2D);
}

//openfile 打開數據文件,將數據導入
BOOL CvtkSDIDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
  if (!CDocument::OnOpenDocument(lpszPathName))
    return FALSE;

  //移除對象
  RemoveActors();

  //讀入數據
  this->pvtkDataSetReader = vtkDataSetReader::New();
  this->pvtkDataSetReader->SetFileName(lpszPathName);

  //運行數據導入流程,導入數據
  ExecutePipeline();

  return TRUE;
}
//釋放創建的內存
void CvtkSDIDoc::OnCloseDocument()
{
  // delete data
  if (this->pvtkDataSetReader)  this->pvtkDataSetReader->Delete();

  // Delete the the objects used to form the visualisation.
  if (this->pvtkDataSetMapper)  this->pvtkDataSetMapper->Delete();
  if (this->pvtkActor)      this->pvtkActor->Delete();
  if (this->pvtkActor2D)      this->pvtkActor2D->Delete();
  if (this->pvtkTextMapper)    this->pvtkTextMapper->Delete();

  CDocument::OnCloseDocument();
}

//數據處理流程
void CvtkSDIDoc::ExecutePipeline()
{
  // 獲得視圖類對象
  POSITION pos = this->GetFirstViewPosition();
  CvtkSDIView *pcvtkSDIView = NULL;

  if (pos)
  {
    pcvtkSDIView = (CvtkSDIView *)GetNextView(pos);
  }
  else  // return
  {
    ASSERT(FALSE);
    return;
  }

  if (pvtkDataSetReader)  // 有數據,將數據添加到render中顯示
  {
    this->pvtkDataSetMapper->SetInput(this->pvtkDataSetReader->GetOutput());
    this->pvtkActor->SetMapper(this->pvtkDataSetMapper);

    this->pvtkTextMapper->SetInput(this->pvtkDataSetReader->GetFileName());
    this->pvtkTextMapper->GetTextProperty()->SetFontSize(12);
    this->pvtkActor2D->SetMapper(this->pvtkTextMapper);

    pcvtkSDIView->GetRenderer()->SetBackground(0.0,0.0,0.4);
    pcvtkSDIView->GetRenderer()->AddActor(this->pvtkActor);
    pcvtkSDIView->GetRenderer()->AddActor(this->pvtkActor2D);
    pcvtkSDIView->GetRenderer()->ResetCamera();
    pvtkDataSetReader->Delete();
    pvtkDataSetReader = NULL;
  }
  else  //無導入數據,顯示textmapper, hello world
  {
    this->pvtkTextMapper->SetInput("Hello World");
    this->pvtkTextMapper->GetTextProperty()->SetFontSize(24);
    this->pvtkActor2D->SetMapper(this->pvtkTextMapper);

    pcvtkSDIView->GetRenderer()->SetBackground(0.0,0.0,0.4);
    pcvtkSDIView->GetRenderer()->AddActor(this->pvtkActor2D);
    pcvtkSDIView->GetRenderer()->ResetCamera();
  }
}

好了,到這裏,基本對MFC和vtk聯合編程就有了個詳細的瞭解了,這樣也就可以自己用VTK結合MFC構建自己的工程了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章