知识不是单独的,一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏:Visual Studio。
文章目录
- 版本环境
- `A.ui`
- `A.h`
- `A.cpp`
- Ref.
本文主要目的是在 Qt 界面中,显示出来使用 VTK 构建的小球,并让小球能够动起来。同时为了方便对比,又添加了一个静态的小球,用来作为参考,方便对比观察动态小球的运动。
先放出来最终效果,如下:
版本环境
- Win 11
- Visual Studio 2022
- Qt 6.2.8_msvs2019_64
- VTK 9.2.6
- 工程名字:
A
工程目标为:假定已经拥有了 x,y,z
坐标,实现当坐标值更改时,就更新 VTK 的小球位置。
工程的实现为:
设定了三个函数:
void initVTK();
用来初始化 VTK 小球对象void updateSpherePosition(double x, double y, double z);
更新小球位置void checkPositionChange();
检测位置是否变化,位置变了就更新,否则不更新
void initVTK();
函数中,主要包含:
- // 创建一个球体源和对应的 mapper
- // 创建一个 actor 来表示小球
- // 创建一个 actor 来表示参照物
- // 创建一个渲染器和窗口来显示小球和参照物
- // 将小球和参照物添加到渲染器中
- // 关联 vtkGenericOpenGLRenderWindow 和 QVTKOpenGLNativeWidget
void updateSpherePosition(double x, double y, double z);
函数中,主要包含:
- // 使用
vtkActor
的SetPosition
方法更新位置 - // 重新渲染
在 VTK 中,renderWindow->Render();
是用来执行渲染过程的命令。每当场景的某个部分需要重新绘制时,例如因为数据或视图的变化,就需要调用这个方法。在本工程的情况中,每当小球的位置发生改变时,都需要重新渲染窗口来更新小球的显示位置。
void checkPositionChange();
函数中,主要包含:
- // 定义位置变量
- // TODO: 从你的数据源获取新的 x, y, z 坐标值,并存储在 newX, newY, newZ 中
- // 这里使用了一个
QElapsedTimer
类的elapsedTimer
变量来记录程序运行时间 - // 判断位置是否变化,如果变化就调用
updateSpherePosition(double x, double y, double z);
函数更新小球位置
最后,工程的关键,也就是触发的方式,采用的是计时器触发。计时器 timer
每过 50ms,就触发一次 checkPositionChange();
函数,然后间接调用位置更新函数 updateSpherePosition(double x, double y, double z);
来实现小球位置的更新。
关于工程的配置和具体的代码如下:
A.ui
ui 界面配置如下,一个 Widget 配置成 QVTKOpenGLNativeWidget
。
不知道如和配置可以参考我的这个配置文章:【Visual Studio】在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK。
A.h
// A.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_A.h"
#include <vtkActor.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>
#include <qtimer.h>
#include <QElapsedTimer>
class A : public QMainWindow
{
Q_OBJECT
public:
A(QWidget* parent = nullptr);
~A();
// 将该函数添加为 public,以便在需要时更新小球位置
void updateSpherePosition(double x, double y, double z);
private slots:
void checkPositionChange(); // 添加一个新的槽函数,用于检查坐标变化
private:
Ui::AClass ui;
void initVTK(); // 将创建小球的过程抽象为一个单独的函数
vtkSmartPointer<vtkActor> sphereActor;
vtkSmartPointer<vtkActor> referenceActor;
vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow;
QTimer* timer;
QElapsedTimer elapsedTimer; // 定义一个变量来跟踪经过的时间,并使用这个时间来计算圆形路径上的点的坐标。
double lastX, lastY, lastZ;
};
A.cpp
// A.cpp
#include "A.h"
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
A::A(QWidget* parent)
: QMainWindow(parent),
lastX(0), lastY(0), lastZ(0)
{
ui.setupUi(this);
// 配置 VTK 的初始设置
initVTK();
// 定时器,50ms 更新触发一次 checkPositionChange()
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(checkPositionChange()));
timer->start(50);
// 开始记录经过的时间,并使用这个时间来计算圆形路径上的点的坐标
elapsedTimer.start();
}
A::~A()
{
}
void A::initVTK()
{
// 创建一个球体源和对应的 mapper
vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();
vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
sphereMapper->SetInputConnection(sphereSource->GetOutputPort());
// 创建一个 actor 来表示小球
sphereActor = vtkSmartPointer<vtkActor>::New();
sphereActor->SetMapper(sphereMapper);
// 创建一个 actor 来表示参照物
referenceActor = vtkSmartPointer<vtkActor>::New();
referenceActor->SetMapper(sphereMapper);
referenceActor->SetPosition(0, 0, 0); // 参照物的位置固定在 (0, 0, 0)
// 创建一个渲染器和窗口来显示小球和参照物
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
renderWindow->AddRenderer(renderer);
// 将小球和参照物添加到渲染器中
renderer->AddActor(sphereActor);
renderer->AddActor(referenceActor);
renderer->ResetCamera();
// 关联 vtkGenericOpenGLRenderWindow 和 QVTKOpenGLNativeWidget
ui.qvtkWidget->setRenderWindow(renderWindow);
}
void A::updateSpherePosition(double x, double y, double z) {
sphereActor->SetPosition(x, y, z);
renderWindow->Render();
}
void A::checkPositionChange() {
double newX, newY, newZ;
// TODO: 从你的数据源获取新的 x, y, z 坐标值,并存储在 newX, newY, newZ 中
double t = elapsedTimer.elapsed() / 1000.0; // convert ms to s
newX = 1 * cos(t);
newY = 1 * sin(t);
newZ = 0;
if (newX != lastX || newY != lastY || newZ != lastZ)
{
updateSpherePosition(newX, newY, newZ);
}
lastX = newX;
lastY = newY;
lastZ = newZ;
}
如果出现这个错误:有未经处理的异常:请求了严重的程序退出。
有可能是 VTK 配置的问题,回想下自己配置 VTK 时选择的时 Release 还是 Debug。如果还不知道,可以参考我的这个配置文章:【Visual Studio】在 Windows 上使用 Visual Studio 配合 Qt 构建 VTK。
Ref.
- VTK实时变化刷新,动态点显示
- 【VTK】VTK+QT打开dicom图像并实时显示鼠标座标位置和像素值