Ubuntu20.04下QT5.15.2配置QVTKOpenGLNativeWidget控件并在QT中显示VTK窗口

Ubuntu 20.04 + QT5.15.2:配置VTK 9.0.1的QVTKOpenGLNativeWidget详解

操作系统:Ubuntu 20.04
QT: 5.15.2
VTK : 9.0.1

一、QT5.15.2配置QVTKOpenGLNativeWidget控件

1.1 下载安装VTK9.0.1

具体方法和配置按照我之前的文章进行,使用CMKE进行编译VTK,且要编译release版本,否则不会生成QVTKOpenGLNativeWidget所需要的动态库libQVTKWidgetPlugin.so

1.2 在QT中显示VTK渲染窗口

网上有很多方法很多案例使用qt+vtk的时候用QVTKWidget、QVTKWidget2、QVTKOpenGLWidget、QVTKOpenGLNativeWidget,容易把人弄混。我也是看了这篇文章之后才弄清楚https://blog.youkuaiyun.com/a15005784320/article/details/99460999

QVTKWidget、QVTKOpenGLWidget、QVTKOpenGLNativeWidget、QVTKWidget2 区别

这几个控件名指的都是VTK在QT中的控件类型
在这里插入图片描述

这几个widget怎么使用:
每个widget都提供了不同的功能以及不同的API,但是widget的创建以及使用基本一样。
    1)实例化widget
    2)指定渲染窗口交互器
    3)创建回调函数(qt里就直接绑定信号和槽)
    4)创建模型,并与widget关联
    5)激活widget
    6)反激活widget

这几个widget的关系:
在这里插入图片描述
到底应该用那个widget:

放弃使用QVTKWidget。
  包含QVTKOpenGLWidget的VTK的第一个版本是VTK 8.0.0!
  如果你是Qt5.4以前,请使用QVTKWidget2。
  如果你是Qt5.4以后,vtk8.1X及以前 请使用QVTKOpenGLWidget。
  如果你是Qt5.4以后,vtk8.2X 请使用QVTKOpenGLNativeWidget。

比如你有QVTKWidget的程序,直接替换成QVTKWidget2(根据版本定),以此向后类推。

为什么自己用时候还要保留vtk8.1X:

为什么自己用时候还要保留vtk8.1X,因为vmtk官方说明仅支持vtk8.1X及以前,vtk8.2X不确定。虽然vtk8.2X+vmtk可以使用,但可能有隐藏bug。
————————————————
原文链接:https://blog.youkuaiyun.com/a15005784320/article/details/99460999

1.3 在QT中配置VTK控件

安裝完VTK之后使用sudo find / -name libQVTKWidgetPlugin.so找到动态链接库的路径;

把ibQVTKWidgetPlugin.so复制到QT的安装目录下:

/home/username/Qt/5.15.2/gcc_64/plugins/designer
/home/username/Qt/Tools/QtCreator/lib/Qt/plugins/designer

在这里插入图片描述
在这里插入图片描述

然后独立的QT Designer和QT creator 中包含的Designer左侧栏目下方就有了QVTKWidget,这里叫是叫QVTKWidget,后面需要根据自己使用的VTK版本和QT版本来修改为QVTKWidget、QVTKOpenGLWidget、QVTKOpenGLNativeWidget、QVTKWidget2 ,不然的话直接拖入到designer界面中后会报错;
在这里插入图片描述

1.4 配置VTK控件

1.4.1 创建一个新的项目
在这里插入图片描述

构建系统选择CMake;
在这里插入图片描述在这里插入图片描述

然后一直点点点直到完成,打开widget.ui文件;

从左侧栏目中拖入QVTKWidget到widget.ui 的界面中,即设置用于渲染VTK模型的窗口;
在这里插入图片描述

此时可以看到该控件类的类类型为QVTKWidget;
在这里插入图片描述

保存,回到左侧的的编辑代码界面,此时widget.cpp文件中会出现报错;
在这里插入图片描述
error :'QVTKWidget.h' file ot found 因为我的vtk版本是VTK9.0.1,是找不到QVTKWidget.h这个文件的;

1.4.2 修改CMakeLists.txt 配置VTK相关头文件 以及 动态链接库篇;

cmake_minimum_required(VERSION 3.5)

project(LastTest LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check https://doc.qt.io/qt/deployment-android.html for more information.
# They need to be set before the find_package( ...) calls below.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
FIND_PACKAGE(VTK REQUIRED)
set(PROJECT_SOURCES
        main.cpp
        widget.cpp
        widget.h
        widget.ui
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(LastTest
        ${PROJECT_SOURCES}
    )
else()
    if(ANDROID)
        add_library(LastTest SHARED
            ${PROJECT_SOURCES}
        )
    else()
        add_executable(LastTest
            ${PROJECT_SOURCES}
        )
    endif()
endif()

target_link_libraries(LastTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${VTK_LIBRARIES})

实际上就改了两个地方:

FIND_PACKAGE(VTK REQUIRED)

target_link_libraries(LastTest PRIVATE Qt${QT_VERSION_MAJOR}::Widgets ${VTK_LIBRARIES})

1.4.3 点击左侧的widget.ui,然后右键选择用文本编辑器打开;此时可以直接修改widget.ui的内容;
widget.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QVTKWidget" name="qvtkWidget">
   <property name="geometry">
    <rect>
     <x>210</x>
     <y>110</y>
     <width>401</width>
     <height>341</height>
    </rect>
   </property>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QVTKWidget</class>
   <extends>QWidget</extends>
   <header>QVTKWidget.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

把其中的QVTKWidget修改为QVTKOpenGLNativeWidget

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <widget class="QVTKOpenGLNativeWidget" name="qvtkWidget">
   <property name="geometry">
    <rect>
     <x>210</x>
     <y>110</y>
     <width>401</width>
     <height>341</height>
    </rect>
   </property>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QVTKOpenGLNativeWidget</class>
   <extends>QWidget</extends>
   <header>QVTKOpenGLNativeWidget.h</header>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

此时界面中的VTK控件类型就变成了QVTKOpenGLNativeWidget;
在这里插入图片描述

保存;
此时再点击左下角的运行,即可
在这里插入图片描述

二、在QT UI界面中使用VTK窗口进行渲染

2.1 使用pushButton控制VTK窗口的显示

在widget.ui 中拖入左侧的PushButton;
在这里插入图片描述
点击PushButton右键选择转到槽 ,选择clicked() ,即点击之后显示画面;
然后widget.h中便会出现槽函数的函数声明;

private slots:
    void on_pushButton_clicked();

widget.cpp 中生成槽函数的定义;

void Widget::on_pushButton_clicked()
{

}

继续沿用一中的代码:
其中:
widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <QWidget>
#include <vtkSmartPointer.h>
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkConeSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include <vtkNew.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    vtkSmartPointer<vtkRenderer> renderer;//这个渲染器其实也可以放在OnOpenSlot()中
    void OnOpenSlot();//负责生成模型和添加渲染窗口画面
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "./ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    renderer = vtkSmartPointer<vtkRenderer>::New();//在构造函数中进行初始化
}

Widget::~Widget()
{
    delete ui;
}

void Widget::OnOpenSlot()
{
    vtkSmartPointer<vtkConeSource> cone=vtkSmartPointer<vtkConeSource>::New();//生成一个圆锥,用于展示
    cone->SetHeight(3.0);
    cone->SetRadius(1);
    cone->SetResolution(10);

    vtkSmartPointer<vtkPolyDataMapper> coneMapper=vtkSmartPointer<vtkPolyDataMapper>::New();
    coneMapper->SetInputConnection(cone->GetOutputPort());
    vtkSmartPointer<vtkActor> coneActor=vtkSmartPointer<vtkActor>::New();
    coneActor->SetMapper(coneMapper);
    renderer->AddActor(coneActor);
    vtkNew<vtkGenericOpenGLRenderWindow> renwindow;
    renwindow->AddRenderer(renderer);
    renwindow->Render();
    ui->qvtkWidget->SetRenderWindow(renwindow.Get());
    ui->qvtkWidget->update();
}

void Widget::on_pushButton_clicked()
{
    qDebug()<<"Show Renderer Windows!!\n";
    OnOpenSlot();
}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    qDebug()<<"RUN MAIN";
    return a.exec();
}

2.2 运行

点击左下角的运行;
在这里插入图片描述
点击PushButton, VTK控件窗口中显示模型渲染画面;
在这里插入图片描述

2.3 不使用PushButton

OnOpenSlot() 函数直接放在Widget的构造函数中,在QT界面初始化之后就可以显示VTK的模型渲染界面;

### QVTKWidget 使用方法及常见问题 #### 创建和初始化 QVTKWidget 实例 为了在 Qt 应用程序中嵌入 VTK 渲染窗口,通常会使用 `QVTKWidget` 组件。创建一个简单的应用程序框架如下所示: ```cpp #include <QApplication> #include <QWidget> #include <QVBoxLayout> // 导入 VTK 和 QVTK 的头文件 #include <vtkSmartPointer.h> #include <vtkRenderWindowInteractor.h> #include <QVTKOpenGLNativeWidget.h> // 或者 QVTKWidget 如果不是 OpenGL 版本 int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; QVBoxLayout layout(&window); auto qvtkWidget = new QVTKOpenGLNativeWidget(&window); // 初始化 QVTKWidget // 设置布局控件添加进去 layout.addWidget(qvtkWidget); window.setLayout(&layout); window.show(); return app.exec(); } ``` 此代码片段展示了如何设置基础环境[^2]。 #### 配置渲染器和相机视角 一旦有了 `QVTKWidget` 对象实例之后,则需配置其内部的 `vtkRenderer` 来管理场景中的对象,设定合适的摄像机位置以便于观察整个三维空间内的物体。 ```cpp auto renderer = vtkSmartPointer<vtkRenderer>::New(); // 新建渲染器 qvtkWidget->GetRenderWindow()->AddRenderer(renderer); // 将渲染器加入到 RenderWindow 中 // 调整相机角度和其他属性... renderer->ResetCamera(); ``` 上述操作确保了当用户启动应用时能看到完整的视图。 #### 添加交互功能 对于希望提供给用户的互动体验来说,在 VTK 场景内引入 Widget 是非常重要的一步。这允许开发者捕捉鼠标的点击拖拽动作或者其他输入源的数据变化来动态调整可视化效果[^3]。 例如,如果想要让用户能够旋转模型,可以通过下面的方式注册相应的事件处理器: ```cpp auto interactorStyle = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New(); qvtkWidget->GetInteractor()->SetInteractorStyle(interactorStyle); ``` 这段脚本启用了类似于球体表面平滑移动的效果,使得探索复杂结构变得更加直观友好。 #### 处理错误消息输出重定向 有时开发过程中难免遇到一些警告或是异常情况的发生,这时可以考虑修改默认的日志记录机制,让所有的提示信息都被保存至指定路径下的文本档之中而不是直接打印出来干扰正常流程[^4]。 ```cpp auto fileOutputWindow = vtkSmartPointer<vtkFileOutputWindow>::New(); fileOutputWindow->SetFileName("error_log.txt"); vtkOutputWindow::SetInstance(fileOutputWindow); ``` 这样做的好处在于既不影响当前界面美观度又能方便后续排查问题所在之处。 #### 常见问题解答 - **关闭含有两个 VTK 控制台的应用后报 wglMakeCurrent 错误** 这种现象可能是因为资源释放顺序不当所引起的图形上下文切换失败所致。建议尝试显式调用 `Finalize()` 方法清理残留状态再退出程序[^1]。 - **多线程环境下更新 UI 抛出未捕获异常** 若涉及到跨线程访问共享变量的情况务必小心谨慎处理同步锁等问题以免造成竞态条件引发崩溃。Actor 模型或许是一个不错的选择因为它天然支持异步通信特性有助于简化发逻辑的设计思路[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值