暂时未有相关云产品技术能力~
文章目录Qt&Vtk第一个VtkQt程序1 程序运行效果2 配置2.1 配置环境变量3 新建Qt工程3.1 建立Qt Widgets Application工程3.2 完成 Pro文件基本配置3.3 写测试代码3.4 运行测试4 源码Qt&Vtk第一个VtkQt程序本文将是Qt与Vtk结合的第一个程序,主要就是将Vtk与Qt结合,但是呢,也不完全算是Qt与Vtk结合的程序,这里并没有用到QVTKOpenglWidget,仅仅是用了Qt编译器,还可以说是纯C++的项目,只是没有用CMake来管理代码。不过一步一步来吧。1 程序运行效果先看下程序运行起来的效果吧,如下图所示。2 配置2.1 配置环境变量关于配置环境变量问题,好多人都提到配置完成环境变量需要重新启动电脑,这里其实还是要有区分的,不是所有内容都需要重新启动电脑的,可以看下这里http://www.winwin7.com/jc/18842.html,防止链接失效,这里引用下知识讲解:1、修改环境变量之后,如果受影响的是应用程序,那么只要简单地重新启动此应用程序,环境变量的修改就会反映到该程序中,而不必重新启动电脑;2、如果受影响的是系统服务,就必须重新启动才能将环境变量的修改反映到系统服务中(因为没有办法在不重启计算机的情况下重新启动系统服务管理器)。知识总结:所以在设置环境变量的时,上面的是某个用户的环境变量,下面是系统的环境变量如果设置的是某个用户的环境变量,就得重启,而系统的环境变量就不用重启你的电脑!还是说会配置,这里我们需要把上篇中编译好的Bin文件夹中的bin文件路径添加到环境变量。如下图所示3.2 完成 Pro文件基本配置这里其实也没有什么,就是配置一下包含头文件路径和链接一下lib库。由于这个库文件比较多,所以在连接的时候最好使用点方法,不然自己一个一个链接就要崩溃了150多个lib呢。使用CMD指令也好,还是还是Qt的多行编辑也可以,我看还有人使用excel的,大家自己搞吧,总之就是把头文件包含了,包lib添加了,就可以了。这里提供一下lib库代码,LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkChartsCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonColor-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonComputationalGeometry-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonDataModel-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonExecutionModel-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonMath-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonMisc-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonSystem-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkCommonTransforms-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkDICOMParser-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkDomainsChemistry-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkDomainsChemistryOpenGL2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkdoubleconversion-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkexodusII-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkexpat-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersAMR-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersExtraction-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersFlowPaths-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersGeneral-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersGeneric-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersGeometry-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersHybrid-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersHyperTree-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersImaging-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersModeling-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersParallel-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersParallelImaging-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersPoints-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersProgrammable-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersSelection-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersSMP-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersSources-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersStatistics-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersTexture-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersTopology-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkFiltersVerdict-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkfreetype-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkGeovisCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkgl2ps-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkglew-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkGUISupportQt-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkGUISupportQtSQL-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkhdf5_hl-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkhdf5-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingColor-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingFourier-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingGeneral-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingHybrid-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingMath-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingMorphological-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingSources-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingStatistics-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkImagingStencil-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkInfovisCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkInfovisLayout-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkInteractionImage-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkInteractionStyle-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkInteractionWidgets-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOAMR-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOAsynchronous-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOCityGML-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOEnSight-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOExodus-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOExport-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOExportOpenGL2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOExportPDF-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOGeometry-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOImage-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOImport-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOInfovis-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOLegacy-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOLSDyna-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOMINC-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOMovie-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIONetCDF-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOParallel-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOParallelXML-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOPLY-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOSegY-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOSQL-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOTecplotTable-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOVeraOut-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOVideo-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOXML-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkIOXMLParser-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkjpeg-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkjsoncpp-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtklibharu-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtklibxml2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkLocalExample-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtklz4-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtklzma-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkmetaio-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkNetCDF-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkogg-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkParallelCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkpng-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkproj-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkpugixml-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingAnnotation-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingContext2D-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingContextOpenGL2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingFreeType-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingGL2PSOpenGL2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingImage-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingLabel-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingLOD-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingOpenGL2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingQt-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingVolume-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkRenderingVolumeOpenGL2-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtksqlite-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtksys-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtktheora-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtktiff-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkverdict-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkViewsContext2D-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkViewsCore-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkViewsInfovis-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkViewsQt-8.2 LIBS += -LC:/Dev/VTK/Bin/lib/ -lvtkzlib-8.2 其实是应该先包含头文件的,这里就一行代码INCLUDEPATH += C:\Dev\VTK\Bin\include\vtk-8.2 3.3 写测试代码下面就开始写代码了,先不要看具体啥作用,现在我也不知道啥作用,网上当下来,先搞起来。直接在main.cpp中添加代码。#include <QApplication> #include <vtkSphereSource.h> #include <vtkPolyData.h> #include <vtkSmartPointer.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderWindow.h> #include <vtkRenderer.h> #include <vtkRenderWindowInteractor.h> #include "vtkAutoInit.h" VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); int main(int argc, char *argv[]) { vtkSmartPointer<vtkSphereSource> sphereSource =vtkSmartPointer<vtkSphereSource>::New(); sphereSource->SetCenter(0.0, 0.0, 0.0); sphereSource->SetRadius(5.0); vtkSmartPointer<vtkPolyDataMapper> mapper =vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(sphereSource->GetOutputPort()); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); vtkSmartPointer<vtkRenderer> renderer =vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderWindow> renderWindow =vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =vtkSmartPointer<vtkRenderWindowInteractor>::New(); renderWindowInteractor->SetRenderWindow(renderWindow); renderer->AddActor(actor); renderer->SetBackground(.3, .6, .3); // Background color green renderWindow->Render(); renderWindowInteractor->Start(); return EXIT_SUCCESS; } 其实这么写下来,基本上都不算是用到了Qt的内容了,仅仅是在Qt开发环境下可以跑起来,不过目前来说也知足了。3.4 运行测试程序运行效果如下4 源码这里就要有人问了呀,这么优秀的代码,能不能分享下呀,当然可以呀,我不生产代码,我只是代码的搬运工,链接如下:自取:https://github.com/DreamLife-Jianwei/Qt-Vtk
今天主要核心是在几年前,尝试过Qt在隐藏标题栏情况下实现可自由缩放的效果,原来的坑在这里:https://blog.csdn.net/z609932088/article/details/53929904今天这坑终于天上了,看下演示效果 参考链接忘记了,浏览记录里面没有找到,如有侵权,联系我大致就是这样的,剩下的看下代码//头文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QPushButton> #include <QMouseEvent> #include <QApplication> #include <QDebug> enum windowEdge{ TOPLEFT = 11, TOP = 12, TOPRIGHT = 13, LEFT = 21, CENTER = 22, RIGHT = 23, BUTTOMLEFT = 31, BUTTOM = 32, BUTTOMRIGHT = 33 }; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); signals: protected: /** * @brief mousePressEvent * @param event * 鼠标按下事件 */ void mousePressEvent(QMouseEvent *event); /** * @brief mouseMoveEvent * @param event * 鼠标移动事件 */ void mouseMoveEvent(QMouseEvent *event); /** * @brief mouseReleaseEvent * @param event * 鼠标松开事件 */ void mouseReleaseEvent(QMouseEvent *event); /** * @brief mouseDoubleClickEvent * @param event * 鼠标双击事件 */ void mouseDoubleClickEvent(QMouseEvent *event); /** * @brief setCursorShape * @param mPos * 设置鼠标形状 */ void setCursorShape(int mPos); /** * @brief calCursorCol * @param pt * @return * 计算鼠标X的位置 */ int calCursorCol(QPoint pt); /** * @brief calCursorPos * @param pt * @param colPos * @return * 计算鼠标的位置 */ int calCursorPos(QPoint pt,int colPos); private: QPoint m_mousePoint; //用于存储鼠标位置 bool m_moveFlag = false; //窗口移动标志位 bool m_resizeFlag = false; //窗口大小重置标志 const int m_titleHight = 30; //用于标记标题栏高度 const int m_frameShape = 2; //用于鼠标区域判断 int m_iCalCursorPos; QRect m_rtPreGeometry; QPoint m_ptViewMousePos; QPushButton *m_pushbuttonClose = nullptr; }; #endif // MAINWINDOW_H//源文件 #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { this->resize(800,600); this->setWindowFlags(Qt::FramelessWindowHint); this->setMouseTracking(true); m_pushbuttonClose = new QPushButton(this); m_pushbuttonClose->setGeometry(100,100,100,80); m_pushbuttonClose->setText("关闭"); // m_pushbuttonClose->setStyleSheet(); connect(m_pushbuttonClose,&QPushButton::clicked,this,[=](){this->close();}); } void MainWindow::mousePressEvent(QMouseEvent *event) { if(event->y() < m_titleHight && event->y()> m_frameShape) { m_mousePoint = event->globalPos(); m_moveFlag = true; } else { m_iCalCursorPos = calCursorPos(event->pos(),calCursorCol(event->pos())); if (event->button() == Qt::LeftButton) { if(m_iCalCursorPos != CENTER) { m_resizeFlag = true; } } m_rtPreGeometry = geometry(); m_ptViewMousePos = event->globalPos(); } } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if((event->y() < m_titleHight) && event->y()> m_frameShape && m_moveFlag) { int dx = event->globalX() - m_mousePoint.x(); int dy = event->globalY() - m_mousePoint.y(); m_mousePoint = event->globalPos(); this->move(this->x()+dx,this->y()+dy); } else { if(Qt::WindowMaximized != windowState()) { setCursorShape(calCursorPos(event->pos(),calCursorCol(event->pos()))); } QPoint ptCurrentPos = QCursor::pos(); //获取当前的点,这个点是全局的 QPoint ptMoveSize = ptCurrentPos - m_ptViewMousePos; //计算出移动的位置,当前点 - 鼠标左键按下的点 QRect rtTempGeometry = m_rtPreGeometry; if(m_resizeFlag) { switch(m_iCalCursorPos) { case windowEdge::TOPLEFT: rtTempGeometry.setTopLeft(m_rtPreGeometry.topLeft()+ptMoveSize); break; case windowEdge::TOP: rtTempGeometry.setTop(m_rtPreGeometry.top()+ptMoveSize.y()); break; case windowEdge::TOPRIGHT: rtTempGeometry.setTopRight(m_rtPreGeometry.topRight()+ptMoveSize); break; case windowEdge::LEFT: rtTempGeometry.setLeft(m_rtPreGeometry.left()+ptMoveSize.x()); break; case windowEdge::RIGHT: rtTempGeometry.setRight(m_rtPreGeometry.right()+ptMoveSize.x()); break; case windowEdge::BUTTOMLEFT: rtTempGeometry.setBottomLeft(m_rtPreGeometry.bottomLeft()+ptMoveSize); break; case windowEdge::BUTTOM: rtTempGeometry.setBottom(m_rtPreGeometry.bottom()+ptMoveSize.y()); break; case windowEdge::BUTTOMRIGHT: rtTempGeometry.setBottomRight(m_rtPreGeometry.bottomRight()+ptMoveSize); break; default: break; } this->setGeometry(rtTempGeometry); } } } void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if(event->y() < m_titleHight && event->y()> m_frameShape && m_moveFlag) { int dx = event->globalX() - m_mousePoint.x(); int dy = event->globalY() - m_mousePoint.y(); m_mousePoint = event->globalPos(); this->move(this->x()+dx,this->y()+dy); m_moveFlag = !m_moveFlag; } else { m_resizeFlag = !m_resizeFlag; QApplication::restoreOverrideCursor(); } } void MainWindow::mouseDoubleClickEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) //鼠标双击最大化/正常 { if(event->y() < m_titleHight) { if(windowState() != Qt::WindowMaximized) { this->showMaximized(); } else { this->showNormal(); } } } } void MainWindow::setCursorShape(int mPos) { Qt::CursorShape mCursor; switch (mPos) { case windowEdge::TOPLEFT: case windowEdge::BUTTOMRIGHT: mCursor = Qt::SizeFDiagCursor; break; case windowEdge::TOPRIGHT: case windowEdge::BUTTOMLEFT: mCursor = Qt::SizeBDiagCursor; break; case windowEdge::TOP: case windowEdge::BUTTOM: mCursor = Qt::SizeVerCursor; break; case windowEdge::LEFT: case windowEdge::RIGHT: mCursor = Qt::SizeHorCursor; break; default: mCursor = Qt::ArrowCursor; break; } this->setCursor(mCursor); } int MainWindow::calCursorCol(QPoint pt) { return (pt.x() < m_frameShape ? 1 : ((pt.x() > this->width() - m_frameShape) ? 3 : 2)); } int MainWindow::calCursorPos(QPoint pt, int colPos) { return ((pt.y() < m_frameShape ? 10 : ((pt.y() > this->height() - m_frameShape) ? 30 : 20)) + colPos); }
BestMPRBaseVtk 给测试程序增加3D体渲染 上一篇不是把图像的显示方向问题解决了吗,后面博士让我搞一下鼠标事件,最近有点神烦的,不想搞,正好我的测试程序准备完善一点,把原来vtkImageViewer2的位置给他换了,换成一个3D的。文章目录BestMPRBaseVtk 给测试程序增加3D体渲染增加3D体渲染演示效果☞ 源码关键字: vtkContourFilter、vtkPolyDataNormals、vtkPolyDataMapper、vtkActor、vtkRenderer增加3D体渲染其实3D渲染整体还是vtk的标准流水线原则数据->过滤器->映射器->Actor ->渲染器->Window+交互器,理解起来简答,搞起来难。那么久直接上代码 //读取Dicom文件 vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName(url); reader->SetDataSpacing(3.2, 1.5, 1.5); reader->Update(); //这是一个过滤器,官方翻译如下 //vtkContourFilter是一个过滤器,它将任何数据集作为输入,并在输出等值面和/或等值线上生成。 //输出的确切形式取决于输入数据的维数。 由3D单元格组成的数据将生成等值面,由2D单元格组成的数据将生成等值线, //由1D或0D单元格组成的数据将生成等点。 如果输入维度是混合的,输出类型的组合是可能的。 //若要使用此筛选器,必须指定一个或多个轮廓值。 您可以使用SetValue()方法来指定每个轮廓值,也可以使用GenerateValues()来生成一系列均匀间隔的轮廓。 //还可以通过使用vtkScalarTree来加速这个过滤器的操作(以额外的内存为代价)。 标量树用于快速定位包含轮廓曲面的单元。 这是特别有效的,如果多个轮廓被提取。 //如果您想要使用标量树,请调用方法UseScalarTreeOn()。 vtkSmartPointer<vtkContourFilter> skinExtractor = vtkSmartPointer<vtkContourFilter>::New(); skinExtractor->SetInputConnection(reader->GetOutputPort()); skinExtractor->SetValue(0, 500); //vtkPolyDataNormals是一个为多边形网格计算点和/或单元法线的过滤器。 //用户通过设置ComputeCellNormals和ComputePointNormals标志来指定他们是否希望计算点和/或单元格法线。 vtkSmartPointer<vtkPolyDataNormals> skinNormals = vtkSmartPointer<vtkPolyDataNormals>::New(); skinNormals->SetInputConnection(skinExtractor->GetOutputPort()); skinNormals->SetFeatureAngle(60.0); vtkSmartPointer<vtkPolyDataMapper> skinMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); skinMapper->SetInputConnection(skinNormals->GetOutputPort()); skinMapper->ScalarVisibilityOff(); vtkSmartPointer<vtkActor> skin = vtkSmartPointer<vtkActor>::New(); skin->SetMapper(skinMapper); vtkSmartPointer<vtkRenderer> aRenderer = vtkSmartPointer<vtkRenderer>::New(); aRenderer->SetBackground(0, 0, 0); aRenderer->ResetCameraClippingRange(); ui->openGLWidget->renderWindow()->AddRenderer(aRenderer); aRenderer->AddActor(skin); ui->openGLWidget->renderWindow()->Render();
使用注册表关闭Windows 10 Defender 在上一篇文章彻底关闭Windows 10 Defender病毒防护中,使用本地策略组来尝试关闭烦人的Windows Defender,但是呢,失败了,系统重启就会重置。 今天这个就尝试使用注册表来搞它。文章目录使用注册表关闭Windows 10 Defender1 步骤说明2 图文说明3 重启电脑关键字: regedit、注册表、Defender、防病毒、Windows1 步骤说明Win+R打开运行窗口在窗口中输入regedit打开注册表编辑器找到计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SecurityHealthService下的Start项将其值改为42 图文说明
冒号初始化与构造函数内赋值 今天优势神奇的一天,昨天和老婆说我把我梦到张扁扁的事情写进的我博文里面了,谈说他不高兴了,那我就在写一遍,哈哈哈。 说正事,今天在公司假装努力的时候,发现一个神奇的问题,就是在构造函数后面用:初始化可以正常使用,在构造函数内使用,就不可以了,MLGB的,大学老师也没有教呀,还是我忘记了,今天正好在水一篇博客。 能力有限,先抄为敬!地址:https://blog.csdn.net/zj510/article/details/8135556文章目录冒号初始化与构造函数内赋值对类成员进行初始化的方式关键字: C/C++、构造函数、初始化、冒号、函数内对类成员进行初始化的方式 通常,我们对类成员函数进行初始化有两种方式,1 构造函数后面跟冒号2 构造函数里面对成员进行赋值我更喜欢第二种。但是呢,说实话,我是真的就是博主提到的那样根本就不知道这两者的区别。今天看了以后才是真的明白了,就是两句话跟括号初始化就是通过初始化列表初始化,是系统创建成员变量并初始化,也就是系统为成员变量分配了一块内存并把相应的数据给填进去;而构造函数里面调用等于号的方法,是分配好以后再进行赋值。参考链接https://www.cnblogs.com/xkfz007/archive/2012/05/11/2496447.htmlhttps://blog.csdn.net/zj510/article/details/8135556
修改工程,搬运官方代码并尝试理解-2 接着上篇,今天接着搞官方的源码,太难了,真想回家卖红薯去,你们说靠卖红薯可以养家糊口吗?文章目录修改工程,搬运官方代码并尝试理解-21 setRenderWindow1.1vtkRenderWindow1.2 vtkGenericOpenGLRenderWindow1.3 QVTKRenderWindowAdapter2 OpenGL相关2.1 上下文3 QSurfaceFormat4 event5 initializeGL5.1 Q_ASSERT6 paintGL6.1makeCurrent☞ 源码关键字: Qt 插件、context、renderwindow、QSurfaceFormat、双缓冲1 setRenderWindow 今天就搞这个 setRenderWindow在官方的代码里面, 大致就是设置一个用来渲染的窗口,并完成所有的初始化工作。 setRenderWindow有两个setRenderWindow函数,但是最终都会汇到一个上面,其中一个感觉就是做了个类型转换。先看一个简单的,代码如下void BPPMPRWidget::setRenderWindow(vtkRenderWindow *win) { //做类型转换 auto gwin = vtkGenericOpenGLRenderWindow::SafeDownCast(win); if(win != nullptr && gwin == nullptr) { qDebug() << "QVTKOpenGLNativeWidget requires a `vtkGenericOpenGLRenderWindow`. `" << win->GetClassName() << "` is not supported."; } this->setRenderWindow(gwin); } 是不是,这个就是做了一个类型转换呢,就是把一个vtkRenderWindow类型的指针转换成一个vtkGenericOpenGLRenderWindow类型的指针,完了在传给另一个setRenderWindow就是下面的这个void BPPMPRWidget::setRenderWindow(vtkGenericOpenGLRenderWindow *win) { if(this->RenderWindow == win) //判断当前窗口是不是传进来的,是就返回不是继续 { return; } if(this->RenderWindowAdapter) // 这将释放所有与旧窗口相关的OpenGL资源 { this->makeCurrent(); this->RenderWindowAdapter.reset(nullptr); } this->RenderWindow = win; if(this->RenderWindow) { this->RenderWindow->SetReadyForRendering(false); //如果没有提供交互器,我们默认将创建一个 if(!this->RenderWindow->GetInteractor()) { vtkNew<QVTKInteractor> iren; //创建一个默认交互器 this->RenderWindow->SetInteractor(iren); //为RenderWindow添加交互器 iren->Initialize(); //交互器初始化 //设置交互器默认样式 vtkNew<vtkInteractorStyleTrackballCamera> style; iren->SetInteractorStyle(style); } if(this->isValid()) { this->makeCurrent(); this->initializeGL(); this->updateSize(); } } } 1.1vtkRenderWindow 为渲染器创建一个渲染窗口。1.2 vtkGenericOpenGLRenderWindow 一个与平台无关的渲染窗口。vtkGenericOpenGLRenderWindow提供了一个框架来实现一个渲染窗口使用自己的OPenGL上下文和绘制。1.3 QVTKRenderWindowAdapter 帮助管理Qt上下文和其他OpenGL组件。 QVTKRenderWindowAdapter是一个内部类,被QVTKOpenGLNativeWidget和QVTKOpenGLWindow用来管理渲染使用vtkGenericOpenGLRenderWindow通过Qt创建OpenGL上下文。2 OpenGL相关2.1 上下文 OpenGL Context,中文解释就是OpenGL的上下文,OpenGL只是图形API,他没有窗口的支持,我们一般使用glut或glfw来创建窗口,然后在这个窗口中绘制。所以上下文的意思就是OpenGL的作用范围,在这里可以先简单的理解为就是这个窗口,也就是说,如果我们要使用OpenGL,需要先为它创建一个窗口,当然OpenGL 的Context不只是这个窗口,这个窗口我们可以可以理解为OpenGL的default framebuffer,所以Context还包含关于这个framebuffer的一些参数设置信息,具体内容可以查看OpenGL的Context的结构体。参考链接:https://www.cnblogs.com/xin-lover/p/9453760.htmlhttps://blog.csdn.net/csxiaoshui/article/details/790324643 QSurfaceFormat 代码如下,这里可以看一下,官方代码中有一个返回一个QSurfaceFormat类型的值,这里重点研究一下这个东西QSurfaceFormat BPPMPRWidget::defaultFormat(bool stereo_capable) { return QVTKRenderWindowAdapter::defaultFormat(stereo_capable); } QSurfaceFormat代表QSurface的一种格式,包括颜色缓冲(RGBA缓冲)、深度缓冲、多重采样数量等。而QSurface是一个可渲染的抽象类,继承自QOffscreenSurface 和QWindow · size():设置接口大小 · format():设置渲染的特殊属性。参考资料https://www.cnblogs.com/myboat/p/11183704.htmlhttps://blog.csdn.net/zchl159/article/details/510054674 event 这个我的理解就是获取Qt事件,把Qt时间传给vtk,完了又调用了父类的eventbool BPPMPRWidget::event(QEvent *evt) { if(this->RenderWindowAdapter) { this->RenderWindowAdapter->handleEvent(evt); } return this->Superclass::event(evt); } 5 initializeGL这个重写了父类的initializeGL,函数开始还是先调用了父类的initializeGLvoid BPPMPRWidget::initializeGL() { this->Superclass::initializeGL(); if(this->RenderWindow) { Q_ASSERT(this->RenderWindowAdapter.data() == nullptr); //测试代码 this->RenderWindowAdapter.reset(new QVTKRenderWindowAdapter(this->context(),this->RenderWindow,this)); //重置 this->RenderWindowAdapter->setDefaultCursor(this->defaultCursor()); //设置默认光标 this->RenderWindowAdapter->setEnableHiDPI(this->EnableHiDPI); //设置HiDPI this->RenderWindowAdapter->setUnscaledDPI(this->UnscaledDPI); //设置默认DPI } this->connect(this->context(),&QOpenGLContext::aboutToBeDestroyed,this,&BPPMPRWidget::cleanupContext,static_cast<Qt::ConnectionType>(Qt::UniqueConnection | Qt::DirectConnection)); //连接信号槽 } 5.1 Q_ASSERTPrints a warning message containing the source code file name and line number if test is false.Q_ASSERT() is useful for testing pre- and post-conditions during development. It does nothing if QT_NO_DEBUG was defined during compilation.如果test为假,则打印包含源代码文件名和行号的警告消息。Q_ASSERT()对于在开发期间测试前置和后置条件非常有用。 如果QT_NO_DEBUG是在编译期间定义的,那么它什么也不做。6 paintGL paintGL函数在运行时调用了父类的paintGL。完了调用了自己的paint函数。和面完成了OpenGL的设置。void BPPMPRWidget::paintGL() { this->Superclass::paintGL(); if(this->RenderWindow) { Q_ASSERT(this->RenderWindowAdapter); this->RenderWindowAdapter->paint(); this->makeCurrent(); //在大多数情况下,没有必要调用这个函数,因为在调用paintGL()之前会自动调用它。 QOpenGLFunctions_3_2_Core* f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); if(f) { const QSize deviceSize = this->size() * this->devicePixelRatioF(); this->RenderWindowAdapter->blit(this->defaultFramebufferObject(),GL_COLOR_ATTACHMENT0,QRect(QPoint(0,0),deviceSize)); } } else { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glClearColor(1.0f,1.0f,1.0f,1.0f); f->glClear(GL_COLOR_BUFFER_BIT); } } 6.1makeCurrentPrepares for rendering OpenGL content for this widget by making the corresponding context current and binding the framebuffer object in that context.It is not necessary to call this function in most cases, because it is called automatically before invoking paintGL().通过将相应的上下文设置为当前并在该上下文中绑定framebuffer对象,为这个小部件呈现OpenGL内容做准备。在大多数情况下,没有必要调用这个函数,因为在调用paintGL()之前会自动调用它。☞ 源码源码链接:GitHub仓库自取使用方法:☟☟☟
QtApplets-实时读取配置文件 今天测试小姐姐跑过来,弱弱的问我为什么程序修改了配置文件没有生效,必须重新启动程序才可以,经过我们一番友好的沟通后,测试小姐姐表示要修复一下这个BUG那么就开始搞起来。文章目录QtApplets-实时读取配置文件1 读取配置文件2 实现'实时'读取3 效果演示☞ 源码关键字: QTimer、QSetting、ini文件、实时读取、Qt1 读取配置文件 这里不做深层的内容,仅仅研究读取的问题,这个很简单。直接上代码,只有一句是有用的,下面那一句是用来在界面显示的。void Widget::readConfig() { QSettings *config = new QSettings("./config.ini",QSettings::IniFormat); config->beginGroup("TestNode"); ui->textBrowser->append(config->value("TEST").toString()); config->endGroup(); } 2 实现’实时’读取 其实说是实时读取,还不如说是定时读取呢,这里我使用了定时器实现,不知道是不是我没有仔细学习QSettings类,是不是应该有部分代码实时可以实时检测配置文件是否发生改变呢,这里贴上完整代码#include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QVariant> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); this->setWindowTitle("QSettingTimer"); mTimer = new QTimer; connect(mTimer,&QTimer::timeout,this,&Widget::readConfig); } Widget::~Widget() { mTimer->stop(); delete mTimer; mTimer = nullptr; delete ui; } void Widget::on_pushButton_clicked() { readConfig(); } void Widget::readConfig() { QSettings *config = new QSettings("./config.ini",QSettings::IniFormat); config->beginGroup("TestNode"); ui->textBrowser->append(config->value("TEST").toString()); config->endGroup(); } void Widget::on_checkBox_stateChanged(int arg1) { if(arg1 != 0) { mTimer->start(1000); } else { if(mTimer->isActive()) mTimer->stop(); } }
函数声明与定义之参数 今天在抄代码的时候发现一个问题,那就是函数声明中的参数与定义中的参数是不一样的。这个是可以的吗?答案是可以的。文章目录函数声明与定义之参数第一种 声明与定义参数名称一致第二种 声明与定义参数名称不一致第三种 声明省略参数名问题搬运链接关键字: 函数、声明、定义、参数、C语言第一种 声明与定义参数名称一致 第一种就是我们最用到的,也是一般编译器自动生成时默认的,那就是函数在声明是参数是什么名字,那在定义时,参数就是什么名字。如下:/** * @brief sub * @param a * @param b * @return * 声明与定义参数名相同 */ int sub(int a,int b); int sub(int a,int b) { return a - b; } 第二种 声明与定义参数名称不一致 第二种就是声明与定义参数名称不一致,这样也是可以的,这还是第一次预见,看来编码经验还是太少或者是大学时代没有好好学习基础。/** * @brief printName * @param string * 声明与定义参数名不同 */ void printName(char* string); void printName(char* name) { std::cout << name; } 第三种 声明省略参数名 这种也是正确的,不过在函数定义的时候就不能省略了,不然你咋传参呢/** * @brief sub * @return * 声明省略参数 */ int sub(int ,int ); int sub(int a,int b) { return a - b; } 问题 其实在我们日常使用使用中,最常见的还是第一种,那么像第二种和第三种这么做的意义又有什么用呢,欢迎大神们给出答案。搬运链接https://blog.csdn.net/qq_43351159/article/details/107585508
本文将实现每个窗口中的三个按钮在鼠标滑入时显示,在鼠标离开时隐藏,同时完成了十字线联动的开关。电梯1 演示效果2 实现按钮显示与隐藏2.1 头文件声明2.2 实现3 十字线显隐☞ 源码1 演示效果 /** * @brief enterEvent * 鼠标进入事件 * @param event */ void enterEvent(QEvent *event); /** * @brief leaveEvent * 鼠标离开事件 * @param event */ void leaveEvent(QEvent *event); 2.2 实现void VTKRenderWidget::enterEvent(QEvent *event) { Q_UNUSED(event) ui->pushButton_1->show(); ui->pushButton_2->show(); ui->pushButton_3->show(); } void VTKRenderWidget::leaveEvent(QEvent *event) { Q_UNUSED(event) ui->pushButton_1->hide(); ui->pushButton_2->hide(); ui->pushButton_3->hide(); } 3 十字线显隐 这个暂时还未理解,仅仅是指实现。这里还有点小BUG,不过不印象使用了void ImageManage::SetResliceMode() { if(riw[0]->GetResliceMode()) { for (int i = 0; i < 3; i++) { riw[i]->SetResliceMode(0); riw[i]->GetRenderer()->ResetCamera(); riw[i]->Render(); } } else { for (int i = 0; i < 3; i++) { riw[i]->SetResliceMode(1); riw[i]->GetRenderer()->ResetCamera(); riw[i]->Render(); } } }
本文将记录实现给每个视图增加按钮和文字提示。文章目录1 增加按钮、增打开文档提示2 自定义模块"VTKRenderWidget"2.1 vtkrenderwidget.h2.2 vtkrenderwidget.cpp3 重写模块“QVTKOpenGLNativeWidget”3.1 myqvtkopenglnativewidget.h3.2 myqvtkopenglnativewidget.cpp☞ 源码源码1 增加按钮、增打开文档提示 今天又来更新文档了,今天这个四视图中又增加了点东西,今天这篇是添上上篇的坑的。三个按钮终于实现了。在实现三个按钮的情况下,还给他增加了一个打开文件夹的提示,不过这英文用的好像是不咋对,凑乎看吧,如下图: 还记得在上上片文中中增加按钮失败那,哪里使用了QVTKOpenGLWidget,死活都没法实现,我个人感觉应该是因为布局的问题。这次再升级VTK9.0.3后,使用了QVTKOpenGLNativeWidget 实现了这个功能。2 自定义模块"VTKRenderWidget" 这里我自己定义了模块VTKRenderWidget,包含一个QVTKOpenGLNativeWidget 和三个QPushbutton ,如下图所示#ifndef VTKRENDERWIDGET_H #define VTKRENDERWIDGET_H /***********Qt*******************/ #include <QWidget> #include <QMouseEvent> #include <QPainter> #include <QPaintEvent> #include <QPen> #include <QColor> #include <QMenu> #include <QAction> #include <QLabel> #include <QResizeEvent> /***********VTK*******************/ #include "vtkRenderWindow.h" #include "QVTKInteractor.h" #include "myqvtkopenglnativewidget.h" namespace Ui { class VTKRenderWidget; } class VTKRenderWidget : public QWidget { Q_OBJECT public: explicit VTKRenderWidget(QWidget *parent = nullptr); ~VTKRenderWidget(); /** * @brief set_BackGroundColor * 设置背景颜色 RGBA * @param r * @param g * @param b * @param a */ void set_BackGroundColor(int r=0,int g=0,int b = 0,int a = 255); void set_OpenFolderEnable(bool enable = false); //------------------------------------------------------------------------------------ vtkRenderWindow* renderWindow() const; QVTKInteractor* interactor() const; void setRenderWindow(vtkGenericOpenGLRenderWindow* win); void setRenderWindow(vtkRenderWindow* win); signals: void signal_mouseDoubleClicked(); private: void paintEvent(QPaintEvent *event); void resizeEvent(QResizeEvent *event); private: Ui::VTKRenderWidget *ui; QColor m_BackGroundColor = QColor(255,255,0,255); //背景颜色 QLabel *m_OpenFolderText = nullptr; //打开文件夹提示 QMenu *m_Menu_1 = nullptr; QAction *test = nullptr; QAction *test1 = nullptr; }; #endif // VTKRENDERWIDGET_H 2.2 vtkrenderwidget.cpp#include "vtkrenderwidget.h" #include "ui_vtkrenderwidget.h" VTKRenderWidget::VTKRenderWidget(QWidget *parent) : QWidget(parent), ui(new Ui::VTKRenderWidget) { ui->setupUi(this); connect(ui->openGLWidget,&MyQVTKOpenGLNativeWidget::signal_mouseDoubleClicked,this,[=](){emit signal_mouseDoubleClicked();}); m_OpenFolderText = new QLabel(this); m_OpenFolderText->setText("Open Folder!"); m_OpenFolderText->setStyleSheet("QLabel{color: rgb(136, 136, 136);}QLabel{font: 24pt '黑体';}"); m_OpenFolderText->raise(); m_Menu_1 = new QMenu(this); test = new QAction(m_Menu_1); test->setText("ABC"); test->setCheckable(true); test1 = new QAction(m_Menu_1); test1->setText("EFG"); test1->setCheckable(true); m_Menu_1->addAction(test); m_Menu_1->addAction(test1); ui->pushButton_1->setMenu(m_Menu_1); ui->pushButton_2->setMenu(m_Menu_1); ui->pushButton_3->setMenu(m_Menu_1); ui->pushButton_1->setStyleSheet("QPushButton::menu-indicator{image:none;}" //不显示下拉图标 "QPushButton{border-image:url(:/ImageManage/Images/ImageManage/btn_n_1.png);}" "QPushButton:hover{border-image:url(:/ImageManage/Images/ImageManage/btn_p_1.png);}" "QPushButton:pressed{border-image:url(:/ImageManage/Images/ImageManage/btn_n_1.png);}"); ui->pushButton_2->setStyleSheet("QPushButton::menu-indicator{image:none;}" //不显示下拉图标 "QPushButton{border-image:url(:/ImageManage/Images/ImageManage/btn_n_2.png);}" "QPushButton:hover{border-image:url(:/ImageManage/Images/ImageManage/btn_p_2.png);}" "QPushButton:pressed{border-image:url(:/ImageManage/Images/ImageManage/btn_n_2.png);}"); ui->pushButton_3->setStyleSheet("QPushButton::menu-indicator{image:none;}" //不显示下拉图标 "QPushButton{border-image:url(:/ImageManage/Images/ImageManage/btn_n_3.png);}" "QPushButton:hover{border-image:url(:/ImageManage/Images/ImageManage/btn_p_3.png);}" "QPushButton:pressed{border-image:url(:/ImageManage/Images/ImageManage/btn_n_3.png);}"); } VTKRenderWidget::~VTKRenderWidget() { delete ui; } void VTKRenderWidget::set_BackGroundColor(int r, int g, int b, int a) { m_BackGroundColor.setRgb(r,g,b,a); this->update(); } void VTKRenderWidget::set_OpenFolderEnable(bool enable) { if(enable) m_OpenFolderText->show(); else m_OpenFolderText->hide(); } vtkRenderWindow *VTKRenderWidget::renderWindow() const { if(ui->openGLWidget) return ui->openGLWidget->renderWindow(); return nullptr; } QVTKInteractor *VTKRenderWidget::interactor() const { if(ui->openGLWidget) return ui->openGLWidget->interactor(); else return nullptr; } void VTKRenderWidget::setRenderWindow(vtkGenericOpenGLRenderWindow *win) { if(ui->openGLWidget) ui->openGLWidget->setRenderWindow(win); } void VTKRenderWidget::setRenderWindow(vtkRenderWindow *win) { if(ui->openGLWidget) ui->openGLWidget->setRenderWindow(win); } void VTKRenderWidget::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); p.setPen(Qt::NoPen); p.setBrush(m_BackGroundColor); p.drawRect(rect()); } void VTKRenderWidget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event) ui->openGLWidget->move(2,2); ui->openGLWidget->resize(this->width()-4,this->height()-4); ui->pushButton_1->move(this->width()-ui->pushButton_1->width()-7,7); ui->pushButton_2->move(this->width()-ui->pushButton_1->width()*2-12,7); ui->pushButton_3->move(this->width()-ui->pushButton_1->width()*3-17,7); m_OpenFolderText->move((this->width()-m_OpenFolderText->width())/2,(this->height()-m_OpenFolderText->height())/2); m_OpenFolderText->raise(); } 在我的这自定义模块中,还使用了自己定义的QVTKOpenGLNativeWidget名字为MyQVTKOpenGLNativeWidget.3 重写模块“QVTKOpenGLNativeWidget” 其实目前来看,这个类和原生基础的QVTKOpenGLNativeWidget没有太多区别。目前只是增加了鼠标双击事件。3.1 myqvtkopenglnativewidget.h#ifndef MYQVTKOPENGLNATIVEWIDGET_H #define MYQVTKOPENGLNATIVEWIDGET_H #include <QObject> #include <QOpenGLWidget> #include <QScopedPointer> // for QScopedPointer. #include <QMouseEvent> #include "QVTKInteractor.h" // needed for QVTKInteractor #include "vtkGUISupportQtModule.h" // for export macro #include "vtkNew.h" // needed for vtkNew #include "vtkSmartPointer.h" // needed for vtkSmartPointer class QVTKInteractor; class QVTKInteractorAdapter; class QVTKRenderWindowAdapter; class vtkGenericOpenGLRenderWindow; class MyQVTKOpenGLNativeWidget : public QOpenGLWidget { Q_OBJECT typedef QOpenGLWidget Superclass; public: MyQVTKOpenGLNativeWidget(QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); MyQVTKOpenGLNativeWidget(vtkGenericOpenGLRenderWindow* window, QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); ~MyQVTKOpenGLNativeWidget() override; void setRenderWindow(vtkGenericOpenGLRenderWindow* win); void setRenderWindow(vtkRenderWindow* win); vtkRenderWindow* renderWindow() const; QVTKInteractor* interactor() const; static QSurfaceFormat defaultFormat(bool stereo_capable = false); void setEnableHiDPI(bool enable); bool enableHiDPI() const { return this->EnableHiDPI; } void setUnscaledDPI(int dpi); int unscaledDPI() const { return this->UnscaledDPI; } void setDefaultCursor(const QCursor& cursor); const QCursor& defaultCursor() const { return this->DefaultCursor; } VTK_LEGACY(void SetRenderWindow(vtkGenericOpenGLRenderWindow* win)); VTK_LEGACY(void SetRenderWindow(vtkRenderWindow* win)); VTK_LEGACY(vtkRenderWindow* GetRenderWindow()); VTK_LEGACY(QVTKInteractor* GetInteractor()); VTK_LEGACY(QVTKInteractorAdapter* GetInteractorAdapter()); VTK_LEGACY(void setQVTKCursor(const QCursor& cursor)); VTK_LEGACY(void setDefaultQVTKCursor(const QCursor& cursor)); signals: void signal_mouseDoubleClicked(); protected slots: virtual void cleanupContext(); void updateSize(); protected: bool event(QEvent* evt) override; void initializeGL() override; void paintGL() override; void mouseDoubleClickEvent(QMouseEvent *event)override; protected: vtkSmartPointer<vtkGenericOpenGLRenderWindow> RenderWindow; QScopedPointer<QVTKRenderWindowAdapter> RenderWindowAdapter; private: Q_DISABLE_COPY(MyQVTKOpenGLNativeWidget); bool EnableHiDPI; int UnscaledDPI; QCursor DefaultCursor; }; #endif // MYQVTKOPENGLNATIVEWIDGET_H 3.2 myqvtkopenglnativewidget.cpp#include "myqvtkopenglnativewidget.h" #include <QApplication> #include <QDesktopWidget> #include <QOpenGLContext> #include <QOpenGLFramebufferObject> #include <QOpenGLFunctions> #include <QOpenGLFunctions_3_2_Core> #include <QOpenGLTexture> #include <QPointer> #include <QScopedValueRollback> #include <QSize> #include <QtDebug> #include "QVTKInteractor.h" #include "QVTKInteractorAdapter.h" #include "QVTKRenderWindowAdapter.h" #include "vtkCommand.h" #include "vtkGenericOpenGLRenderWindow.h" #include "vtkInteractorStyleTrackballCamera.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkOpenGLState.h" MyQVTKOpenGLNativeWidget::MyQVTKOpenGLNativeWidget(QWidget* parentWdg, Qt::WindowFlags f) : MyQVTKOpenGLNativeWidget(vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New().GetPointer(), parentWdg, f) { } MyQVTKOpenGLNativeWidget::MyQVTKOpenGLNativeWidget(vtkGenericOpenGLRenderWindow* renderWin, QWidget* parentWdg, Qt::WindowFlags f): Superclass(parentWdg, f) , RenderWindow(nullptr) , RenderWindowAdapter(nullptr) , EnableHiDPI(true) , UnscaledDPI(72) , DefaultCursor(QCursor(Qt::ArrowCursor)) { this->setFocusPolicy(Qt::StrongFocus); this->setUpdateBehavior(QOpenGLWidget::NoPartialUpdate); this->setMouseTracking(true); this->connect(this, SIGNAL(resized()), SLOT(updateSize())); this->setRenderWindow(renderWin); this->grabGesture(Qt::PinchGesture); this->grabGesture(Qt::PanGesture); this->grabGesture(Qt::TapGesture); this->grabGesture(Qt::TapAndHoldGesture); this->grabGesture(Qt::SwipeGesture); } MyQVTKOpenGLNativeWidget::~MyQVTKOpenGLNativeWidget() { this->makeCurrent(); this->cleanupContext(); } void MyQVTKOpenGLNativeWidget::setRenderWindow(vtkGenericOpenGLRenderWindow *win) { if (this->RenderWindow == win) { return; } if (this->RenderWindowAdapter) { this->makeCurrent(); this->RenderWindowAdapter.reset(nullptr); } this->RenderWindow = win; if (this->RenderWindow) { this->RenderWindow->SetReadyForRendering(false); if (!this->RenderWindow->GetInteractor()) { vtkNew<QVTKInteractor> iren; this->RenderWindow->SetInteractor(iren); iren->Initialize(); vtkNew<vtkInteractorStyleTrackballCamera> style; iren->SetInteractorStyle(style); } if (this->isValid()) { this->makeCurrent(); this->initializeGL(); this->updateSize(); } } } void MyQVTKOpenGLNativeWidget::setRenderWindow(vtkRenderWindow *win) { auto gwin = vtkGenericOpenGLRenderWindow::SafeDownCast(win); if (win != nullptr && gwin == nullptr) { qDebug() << "QVTKOpenGLNativeWidget requires a `vtkGenericOpenGLRenderWindow`. `" << win->GetClassName() << "` is not supported."; } this->setRenderWindow(gwin); } vtkRenderWindow *MyQVTKOpenGLNativeWidget::renderWindow() const { return this->RenderWindow; } QVTKInteractor *MyQVTKOpenGLNativeWidget::interactor() const { return this->RenderWindow ? QVTKInteractor::SafeDownCast(this->RenderWindow->GetInteractor()) : nullptr; } QSurfaceFormat MyQVTKOpenGLNativeWidget::defaultFormat(bool stereo_capable) { return QVTKRenderWindowAdapter::defaultFormat(stereo_capable); } void MyQVTKOpenGLNativeWidget::setEnableHiDPI(bool enable) { this->EnableHiDPI = enable; if (this->RenderWindowAdapter) { this->RenderWindowAdapter->setEnableHiDPI(enable); } } void MyQVTKOpenGLNativeWidget::setUnscaledDPI(int dpi) { this->UnscaledDPI = dpi; if (this->RenderWindowAdapter) { this->RenderWindowAdapter->setUnscaledDPI(dpi); } } void MyQVTKOpenGLNativeWidget::setDefaultCursor(const QCursor &cursor) { this->DefaultCursor = cursor; if (this->RenderWindowAdapter) { this->RenderWindowAdapter->setDefaultCursor(cursor); } } void MyQVTKOpenGLNativeWidget::cleanupContext() { this->RenderWindowAdapter.reset(nullptr); } void MyQVTKOpenGLNativeWidget::updateSize() { if (this->RenderWindowAdapter) { this->RenderWindowAdapter->resize(this->width(), this->height()); } } bool MyQVTKOpenGLNativeWidget::event(QEvent *evt) { if (this->RenderWindowAdapter) { this->RenderWindowAdapter->handleEvent(evt); } return this->Superclass::event(evt); } void MyQVTKOpenGLNativeWidget::initializeGL() { this->Superclass::initializeGL(); if (this->RenderWindow) { Q_ASSERT(this->RenderWindowAdapter.data() == nullptr); this->RenderWindowAdapter.reset(new QVTKRenderWindowAdapter(this->context(), this->RenderWindow, this)); this->RenderWindowAdapter->setDefaultCursor(this->defaultCursor()); this->RenderWindowAdapter->setEnableHiDPI(this->EnableHiDPI); this->RenderWindowAdapter->setUnscaledDPI(this->UnscaledDPI); } this->connect(this->context(), SIGNAL(aboutToBeDestroyed()), SLOT(cleanupContext()),static_cast<Qt::ConnectionType>(Qt::UniqueConnection | Qt::DirectConnection)); } void MyQVTKOpenGLNativeWidget::paintGL() { this->Superclass::paintGL(); if (this->RenderWindow) { Q_ASSERT(this->RenderWindowAdapter); this->RenderWindowAdapter->paint(); this->makeCurrent(); QOpenGLFunctions_3_2_Core* f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); if (f) { const QSize deviceSize = this->size() * this->devicePixelRatioF(); this->RenderWindowAdapter->blit(this->defaultFramebufferObject(), GL_COLOR_ATTACHMENT0, QRect(QPoint(0, 0), deviceSize)); } } else { QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions(); f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f); f->glClear(GL_COLOR_BUFFER_BIT); } } void MyQVTKOpenGLNativeWidget::mouseDoubleClickEvent(QMouseEvent *event) { Q_UNUSED(event); emit signal_mouseDoubleClicked(); } //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) void MyQVTKOpenGLNativeWidget::SetRenderWindow(vtkRenderWindow* win) { VTK_LEGACY_REPLACED_BODY( QVTKOpenGLNativeWidget::SetRenderWindow, "VTK 9.0", QVTKOpenGLNativeWidget::setRenderWindow); vtkGenericOpenGLRenderWindow* gwin = vtkGenericOpenGLRenderWindow::SafeDownCast(win); if (gwin == nullptr && win != nullptr) { qDebug() << "QVTKOpenGLNativeWidget requires a `vtkGenericOpenGLRenderWindow`. `" << win->GetClassName() << "` is not supported."; } this->setRenderWindow(gwin); } #endif //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) void MyQVTKOpenGLNativeWidget::SetRenderWindow(vtkGenericOpenGLRenderWindow* win) { VTK_LEGACY_REPLACED_BODY( QVTKOpenGLNativeWidget::SetRenderWindow, "VTK 9.0", QVTKOpenGLNativeWidget::setRenderWindow); this->setRenderWindow(win); } #endif //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) vtkRenderWindow* MyQVTKOpenGLNativeWidget::GetRenderWindow() { VTK_LEGACY_REPLACED_BODY( QVTKOpenGLNativeWidget::GetRenderWindow, "VTK 9.0", QVTKOpenGLNativeWidget::renderWindow); return this->renderWindow(); } #endif //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) QVTKInteractorAdapter* MyQVTKOpenGLNativeWidget::GetInteractorAdapter() { VTK_LEGACY_BODY(QVTKOpenGLNativeWidget::GetInteractorAdapter, "VTK 9.0"); return nullptr; } #endif //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) QVTKInteractor* MyQVTKOpenGLNativeWidget::GetInteractor() { VTK_LEGACY_REPLACED_BODY( QVTKOpenGLNativeWidget::GetInteractor, "VTK 9.0", QVTKOpenGLNativeWidget::interactor); return this->interactor(); } #endif //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) void MyQVTKOpenGLNativeWidget::setQVTKCursor(const QCursor& cursor) { VTK_LEGACY_REPLACED_BODY( QVTKOpenGLNativeWidget::setQVTKCursor, "VTK 9.0", QVTKOpenGLNativeWidget::setCursor); this->setCursor(cursor); } #endif //----------------------------------------------------------------------------- #if !defined(VTK_LEGACY_REMOVE) void MyQVTKOpenGLNativeWidget::setDefaultQVTKCursor(const QCursor& cursor) { VTK_LEGACY_REPLACED_BODY(QVTKOpenGLNativeWidget::setDefaultQVTKCursor, "VTK 9.0", QVTKOpenGLNativeWidget::setDefaultCursor); this->setDefaultCursor(cursor); } #endif
本文主要记录了项目中从VTK8.2.0升级至9.0.3过程中遇到的问题。电梯1 升级Vtk版本至9.0.32 升级内容2.1 更改QVTKOpenGLWidget2.2 修改部分内部函数☞ 源码源码1 升级Vtk版本至9.0.3 为什么要把VTK从8.2.0版本升级至9.0.3呢,一切原因都是CEO的问话,就是问怎么把一个Dicom图像给水平镜像了,但是呢,我是真的不会,原理倒是知道一点点,但是对VTK以及图形相关的知识都不熟悉,无从下手,搞了DCMTK,但是呢,不会和VTK融合,群里问大佬们怎么搞,才知道VTK已经集成了一部分DCMTK的东西和GDCM的内容了。开始准备是重新配置8.2.0 的CMake文件,整了半天都不行,百度了好久找个一个网站说好像8.2 有BUG,所以我就直接换了最新的9.0.3.这就是由来了。编译的话基本和8.2.0差不多,这里就不高了。2 升级内容2.1 更改QVTKOpenGLWidget 本次更改内容为把原来的QVTKOpenGLWidget更换为QVTKOpenglNativeWisget。2.2 修改部分内部函数 本次修改部分内容函数,主要涉及部分函数在9.0之后将会弃用,所以做了部分更改,有GetInteractor更换为interactor;SetRenderWindow更换为setRenderWindow;GetRenderWindow更换为renderWindow等。
先说结果,没有成功,如下图所示:要看成功的,需要再看我下下篇文章**《增加按钮、增加文字显示》**的那篇。电梯1 效果展示2 QWidget::createWindowContainer()☞ 源码1 效果展示 先说结果,没有成功,如下图所示:要看成功的,需要再看我下下篇文章**《增加按钮、增加文字显示》的那篇,那边里面更换的VTK版本,同时也更换了Qt控件,最终是实现了三个按钮。这次不成功的原因,我感觉还是我对布局以及QWidget::createWindowContainer()**的理解不到位。不然这个应该也是可以成功的[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SKQ80axc-1631244273719)(https://raw.githubusercontent.com/DreamLife-Jianwei/CSDNResources/master/20210729090630.png)]2 QWidget::createWindowContainer() 目前结果就是怎么也没法把按钮放到上面了。尝试了lower()、raise(),还有一个函数,给忘了,也没有找到,都没有效果。这是我发现了一个不一样的函数QWidget::createWindowContainer(),如下:参考链接如下:https://blog.csdn.net/lengyuezuixue/article/details/81711795https://www.cnblogs.com/luoxiang/p/14392650.htmlhttps://www.cnblogs.com/tingtaishou/p/14763935.htmlhttps://zhuanlan.zhihu.com/p/370340673引用下别人的翻译暴力翻译:创建一个QWidget,使将窗口嵌入到基于QWidget的应用程序成为可能。窗口容器作为父容器的子容器创建,并带有窗口标志。一旦窗口被嵌入到容器中,容器将控制窗口的几何形状和可见性。不推荐在嵌入式窗口上显式调用QWindow::setGeometry(), QWindow::show()或QWindow::hide()。容器接管窗口的所有权。可以通过调用QWindow::setParent()从窗口容器中移除窗口。☞ 源码源码链接:https://github.com/DreamLife-Jianwei/Qt-Vtk使用方法:☟☟☟
这篇文章中就要给我的四视图增加文字显示了,这个东西就是在我摄像机上面的,不会随着图像变化而变化,感觉这个是不是就是在3D中的那种HUD呢。电梯1 效果展示2 vtkTextActor3 实现代码3.1 头文件3.2 源文件实现3.2.1 新建变量,赋值,设置属性3.2.2 加入到渲染器中☞ 源码1 效果展示 如下图所示,在每个图的左上角和左下角有文字显示,左上角显示的病人的基本信息,左下角显示的是当前切面。2 vtkTextActor 实现文字显示,主要将用到vtkTextActor,这里还是把参考链接附上https://vtk.org/doc/nightly/html/classvtkTextActor.htmlfor (auto i=0;i<4;i++) { textActor[i] = vtkSmartPointer<vtkTextActor>::New(); textActor[i]->SetDisplayPosition(5, 5); textActor[i]->GetTextProperty()->SetFontSize(14); textActor[i]->GetTextProperty()->SetFontFamily(VTK_FONT_FILE); textActor[i]->GetTextProperty()->SetFontFile(QString("./Fonts/simhei.ttf").toUtf8()); } textActor[0]->SetInput(QString::fromUtf8("矢状").toUtf8()); textActor[0]->GetTextProperty()->SetColor(0, 1, 0); textActor[1]->SetInput(QString::fromUtf8("冠状").toUtf8()); textActor[1]->GetTextProperty()->SetColor(0, 0, 1); textActor[2]->SetInput(QString::fromUtf8("轴向").toUtf8()); textActor[2]->GetTextProperty()->SetColor(1, 0, 0); textActor[3]->SetInput(QString::fromUtf8("3D").toUtf8()); textActor[3]->GetTextProperty()->SetColor(1, 1, 0); for (auto i=0;i<4;i++) { peopleInforTextActor[i] = vtkSmartPointer<vtkTextActor>::New(); peopleInforTextActor[i]->GetTextProperty()->SetFontSize(14); peopleInforTextActor[i]->GetTextProperty()->SetFontFamily(VTK_FONT_FILE); peopleInforTextActor[i]->GetTextProperty()->SetFontFile(QString("./Fonts/simhei.ttf").toUtf8()); peopleInforTextActor[i]->SetInput(reader->GetPatientName()); } peopleInforTextActor[0]->GetTextProperty()->SetColor(0, 1, 0); peopleInforTextActor[0]->SetDisplayPosition(5,ui->widget_1->height()-20); peopleInforTextActor[1]->GetTextProperty()->SetColor(0, 0, 1); peopleInforTextActor[1]->SetDisplayPosition(5,ui->widget_2->height()-20); peopleInforTextActor[2]->GetTextProperty()->SetColor(1, 0, 0); peopleInforTextActor[2]->SetDisplayPosition(5,ui->widget_3->height()-20); peopleInforTextActor[3]->GetTextProperty()->SetColor(1, 1, 0); peopleInforTextActor[3]->SetDisplayPosition(5,ui->widget_4->height()-20);
先说结论,本文最终也没有解决图像反转问题,仅仅是过程记录。咨询了老大,老大说以我的能力,暂时还搞不定,所以就暂时先搁置。电梯1 都是演示的错2 编译MITK2.21.23 找问题原因3.1vtkResliceCursorLineRepresentation3.1.1GetRepresentation3.1.2SetSliceOrientation☞ 源码1 都是演示的错 哎呀,今天可是丢人大方了,今天博士来公司了,我兴匆匆的去嘚瑟下,告诉博士我实现了四视图了,博士说那就给我演示下呗,我这就麻溜的打开我的工程,演示起来,结果,呵呵哒。2 编译MITK2.21.2 其实编译MITK完全是吃饱了撑的,因为不用编译,就可以看到源码,我还是编译了,并且折腾了好久,链接在这里,当你掌握了,就简单了,真的简单,曾经也在多个夜晚骂MITK团队,搞得啥破玩意,最后发现小丑竟是自己哈哈。其实编译MITK是想看看人家是怎么实现的。https://blog.csdn.net/z609932088/article/details/118831590?spm=1001.2014.3001.55023 找问题原因 在读取DICOM文件的时候,我使用的是vtkDICOMImageReader,而且用法也很简单,代码如下,这里不是出问题的地方,而且我也通过另外一个例子证明了。 到了怀疑的地方了,这里rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i);,如果把这句话注释掉的话,那就会报错误Resetting view-up since view plane normal is parallel,这个错误里面有一个关键字view-up,通过有道翻译出来的也不咋懂,重置视图,因为视图平面法线是平行的 for (int i = 0; i < 3; i++) { vtkResliceCursorLineRepresentation *rep = vtkResliceCursorLineRepresentation::SafeDownCast(riw[i]->GetResliceCursorWidget()->GetRepresentation()); riw[i]->SetResliceCursor(riw[0]->GetResliceCursor()); rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i); riw[i]->SetInputData(reader->GetOutput()); riw[i]->SetSliceOrientation(i); // riw[i]->SetResliceModeToAxisAligned(); riw[i]->SetResliceModeToOblique(); } 3.1.2SetSliceOrientation 后面我又开始研究SetSliceOrientation,源码如下: 测试这个接口是有影响,但是呢,运行就死机,好尴尬。 /** * Set/get the slice orientation */ enum { SLICE_ORIENTATION_YZ = 0, SLICE_ORIENTATION_XZ = 1, SLICE_ORIENTATION_XY = 2 }; vtkGetMacro(SliceOrientation, int); virtual void SetSliceOrientation(int orientation); virtual void SetSliceOrientationToXY() { this->SetSliceOrientation(vtkImageViewer2::SLICE_ORIENTATION_XY); }; virtual void SetSliceOrientationToYZ() { this->SetSliceOrientation(vtkImageViewer2::SLICE_ORIENTATION_YZ); }; virtual void SetSliceOrientationToXZ() { this->SetSliceOrientation(vtkImageViewer2::SLICE_ORIENTATION_XZ); }; 在使用原生Demo测试时候,也是会出现错误,VS报告如下:这个Qt就得出来背锅了,不明白的就是为什么设置按照顺序012可以,倒过来就不可以呢,费解,发生这个问题后面找到了解决方法,就是换Qt版本,目前我虽然使用了5.14.2 的壳子,但是内核还是5.7.1 这个版本的的问题还真是多,也不知道算不算是BUG。
本篇文章将参考大神们的足迹,模仿这实现四视图。电梯1 参考资料2 参考代码3 自己的代码4 运行效果☞ 源码1 参考资料 其实说四视图是不是很不专业,是不是应该叫多平面重建及三维切片显示呀。参考资料如下:参考:https://blog.csdn.net/hit1524468/article/details/113446783https://www.cnblogs.com/fuzhuoxin/p/12513872.htmlhttps://blog.csdn.net/weixin_38500110/article/details/788071962 参考代码#ifndef QtVTKRenderWindows_H #define QtVTKRenderWindows_H #include "vtkSmartPointer.h" #include "vtkResliceImageViewer.h" #include "vtkImagePlaneWidget.h" #include "vtkDistanceWidget.h" #include "vtkResliceImageViewerMeasurements.h" #include <QMainWindow> #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL2) VTK_MODULE_INIT(vtkInteractionStyle) VTK_MODULE_INIT(vtkRenderingFreeType) // Forward Qt class declarations class Ui_QtVTKRenderWindows; class QtVTKRenderWindows : public QMainWindow { Q_OBJECT public: // Constructor/Destructor QtVTKRenderWindows(int argc, char *argv[]); ~QtVTKRenderWindows() override {} public slots: virtual void slotExit(); virtual void resliceMode(int); virtual void thickMode(int); virtual void SetBlendModeToMaxIP(); virtual void SetBlendModeToMinIP(); virtual void SetBlendModeToMeanIP(); virtual void SetBlendMode(int); virtual void ResetViews(); virtual void Render(); virtual void AddDistanceMeasurementToView1(); virtual void AddDistanceMeasurementToView( int ); protected: vtkSmartPointer< vtkResliceImageViewer > riw[3]; vtkSmartPointer< vtkImagePlaneWidget > planeWidget[3]; vtkSmartPointer< vtkDistanceWidget > DistanceWidget[3]; vtkSmartPointer< vtkResliceImageViewerMeasurements > ResliceMeasurements; protected slots: private: // Designer form Ui_QtVTKRenderWindows *ui; }; #endif // QtVTKRenderWindows_H #include "ui_QtVTKRenderWindows.h" #include "QtVTKRenderWindows.h" #include "vtkBoundedPlanePointPlacer.h" #include "vtkCellPicker.h" #include "vtkCommand.h" #include "vtkDICOMImageReader.h" #include "vtkDistanceRepresentation.h" #include "vtkDistanceRepresentation2D.h" #include "vtkDistanceWidget.h" #include <vtkGenericOpenGLRenderWindow.h> #include "vtkHandleRepresentation.h" #include "vtkImageData.h" #include "vtkImageMapToWindowLevelColors.h" #include "vtkImageSlabReslice.h" #include "vtkInteractorStyleImage.h" #include "vtkLookupTable.h" #include "vtkPlane.h" #include "vtkPlaneSource.h" #include "vtkPointHandleRepresentation2D.h" #include "vtkPointHandleRepresentation3D.h" #include "vtkProperty.h" #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include "vtkRenderWindowInteractor.h" #include "vtkResliceImageViewer.h" #include "vtkResliceCursorLineRepresentation.h" #include "vtkResliceCursorThickLineRepresentation.h" #include "vtkResliceCursorWidget.h" #include "vtkResliceCursorActor.h" #include "vtkResliceCursorPolyDataAlgorithm.h" #include "vtkResliceCursor.h" #include "vtkMetaImageReader.h" #include "vtkResliceImageViewerMeasurements.h" //---------------------------------------------------------------------------- class vtkResliceCursorCallback : public vtkCommand { public: static vtkResliceCursorCallback *New() { return new vtkResliceCursorCallback; } void Execute( vtkObject *caller, unsigned long ev, void *callData ) override { if (ev == vtkResliceCursorWidget::WindowLevelEvent || ev == vtkCommand::WindowLevelEvent || ev == vtkResliceCursorWidget::ResliceThicknessChangedEvent) { // Render everything for (int i = 0; i < 3; i++) { this->RCW[i]->Render(); } this->IPW[0]->GetInteractor()->GetRenderWindow()->Render(); return; } vtkImagePlaneWidget* ipw = dynamic_cast< vtkImagePlaneWidget* >( caller ); if (ipw) { double* wl = static_cast<double*>( callData ); if ( ipw == this->IPW[0] ) { this->IPW[1]->SetWindowLevel(wl[0],wl[1],1); this->IPW[2]->SetWindowLevel(wl[0],wl[1],1); } else if( ipw == this->IPW[1] ) { this->IPW[0]->SetWindowLevel(wl[0],wl[1],1); this->IPW[2]->SetWindowLevel(wl[0],wl[1],1); } else if (ipw == this->IPW[2]) { this->IPW[0]->SetWindowLevel(wl[0],wl[1],1); this->IPW[1]->SetWindowLevel(wl[0],wl[1],1); } } vtkResliceCursorWidget *rcw = dynamic_cast< vtkResliceCursorWidget * >(caller); if (rcw) { vtkResliceCursorLineRepresentation *rep = dynamic_cast< vtkResliceCursorLineRepresentation * >(rcw->GetRepresentation()); // Although the return value is not used, we keep the get calls // in case they had side-effects rep->GetResliceCursorActor()->GetCursorAlgorithm()->GetResliceCursor(); for (int i = 0; i < 3; i++) { vtkPlaneSource *ps = static_cast< vtkPlaneSource * >( this->IPW[i]->GetPolyDataAlgorithm()); ps->SetOrigin(this->RCW[i]->GetResliceCursorRepresentation()-> GetPlaneSource()->GetOrigin()); ps->SetPoint1(this->RCW[i]->GetResliceCursorRepresentation()-> GetPlaneSource()->GetPoint1()); ps->SetPoint2(this->RCW[i]->GetResliceCursorRepresentation()-> GetPlaneSource()->GetPoint2()); // If the reslice plane has modified, update it on the 3D widget this->IPW[i]->UpdatePlacement(); } } // Render everything for (int i = 0; i < 3; i++) { this->RCW[i]->Render(); } this->IPW[0]->GetInteractor()->GetRenderWindow()->Render(); } vtkResliceCursorCallback() {} vtkImagePlaneWidget* IPW[3]; vtkResliceCursorWidget *RCW[3]; }; QtVTKRenderWindows::QtVTKRenderWindows( int vtkNotUsed(argc), char *argv[]) { this->ui = new Ui_QtVTKRenderWindows; this->ui->setupUi(this); #if 0 vtkSmartPointer< vtkDICOMImageReader > reader = vtkSmartPointer<vtkDICOMImageReader >::New(); // reader->SetDirectoryName(argv[1]); reader->SetDirectoryName("/home/hsw/Qt_workSpace/build-RSVtkLearn_FourPaneViewer-Desktop_Qt_5_12_2_GCC_64bit-Debug/DCM/"); #else vtkSmartPointer<vtkMetaImageReader> reader = vtkSmartPointer<vtkMetaImageReader>::New(); reader->SetFileName("/home/hsw/Downloads/brain/brain.mhd"); #endif reader->Update(); int imageDims[3]; reader->GetOutput()->GetDimensions(imageDims); for (int i = 0; i < 3; i++) { riw[i] = vtkSmartPointer< vtkResliceImageViewer >::New(); vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; riw[i]->SetRenderWindow(renderWindow); } this->ui->view1->SetRenderWindow(riw[0]->GetRenderWindow()); riw[0]->SetupInteractor(this->ui->view1->GetRenderWindow()->GetInteractor()); this->ui->view2->SetRenderWindow(riw[1]->GetRenderWindow()); riw[1]->SetupInteractor(this->ui->view2->GetRenderWindow()->GetInteractor()); this->ui->view3->SetRenderWindow(riw[2]->GetRenderWindow()); riw[2]->SetupInteractor(this->ui->view3->GetRenderWindow()->GetInteractor()); for (int i = 0; i < 3; i++) { // make them all share the same reslice cursor object. vtkResliceCursorLineRepresentation *rep = vtkResliceCursorLineRepresentation::SafeDownCast(riw[i]->GetResliceCursorWidget()->GetRepresentation()); riw[i]->SetResliceCursor(riw[0]->GetResliceCursor()); rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i); riw[i]->SetInputData(reader->GetOutput()); riw[i]->SetSliceOrientation(i); riw[i]->SetResliceModeToAxisAligned(); } vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New(); picker->SetTolerance(0.005); vtkSmartPointer<vtkProperty> ipwProp = vtkSmartPointer<vtkProperty>::New(); vtkSmartPointer< vtkRenderer > ren = vtkSmartPointer< vtkRenderer >::New(); vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; this->ui->view4->SetRenderWindow(renderWindow); this->ui->view4->GetRenderWindow()->AddRenderer(ren); vtkRenderWindowInteractor *iren = this->ui->view4->GetInteractor(); for (int i = 0; i < 3; i++) { planeWidget[i] = vtkSmartPointer<vtkImagePlaneWidget>::New(); planeWidget[i]->SetInteractor( iren ); planeWidget[i]->SetPicker(picker); planeWidget[i]->RestrictPlaneToVolumeOn(); double color[3] = {0, 0, 0}; color[i] = 1; planeWidget[i]->GetPlaneProperty()->SetColor(color); color[0] /= 4.0; color[1] /= 4.0; color[2] /= 4.0; riw[i]->GetRenderer()->SetBackground( color ); planeWidget[i]->SetTexturePlaneProperty(ipwProp); planeWidget[i]->TextureInterpolateOff(); planeWidget[i]->SetResliceInterpolateToLinear(); planeWidget[i]->SetInputConnection(reader->GetOutputPort()); planeWidget[i]->SetPlaneOrientation(i); planeWidget[i]->SetSliceIndex(imageDims[i]/2); planeWidget[i]->DisplayTextOn(); planeWidget[i]->SetDefaultRenderer(ren); planeWidget[i]->SetWindowLevel(1358, -27); planeWidget[i]->On(); planeWidget[i]->InteractionOn(); } vtkSmartPointer<vtkResliceCursorCallback> cbk = vtkSmartPointer<vtkResliceCursorCallback>::New(); for (int i = 0; i < 3; i++) { cbk->IPW[i] = planeWidget[i]; cbk->RCW[i] = riw[i]->GetResliceCursorWidget(); riw[i]->GetResliceCursorWidget()->AddObserver( vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk ); riw[i]->GetResliceCursorWidget()->AddObserver( vtkResliceCursorWidget::WindowLevelEvent, cbk ); riw[i]->GetResliceCursorWidget()->AddObserver( vtkResliceCursorWidget::ResliceThicknessChangedEvent, cbk ); riw[i]->GetResliceCursorWidget()->AddObserver( vtkResliceCursorWidget::ResetCursorEvent, cbk ); riw[i]->GetInteractorStyle()->AddObserver( vtkCommand::WindowLevelEvent, cbk ); // Make them all share the same color map. riw[i]->SetLookupTable(riw[0]->GetLookupTable()); planeWidget[i]->GetColorMap()->SetLookupTable(riw[0]->GetLookupTable()); //planeWidget[i]->GetColorMap()->SetInput(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()->GetInput()); planeWidget[i]->SetColorMap(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()); } this->ui->view1->show(); this->ui->view2->show(); this->ui->view3->show(); // Set up action signals and slots connect(this->ui->actionExit, SIGNAL(triggered()), this, SLOT(slotExit())); connect(this->ui->resliceModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(resliceMode(int))); connect(this->ui->thickModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(thickMode(int))); this->ui->thickModeCheckBox->setEnabled(0); connect(this->ui->radioButton_Max, SIGNAL(pressed()), this, SLOT(SetBlendModeToMaxIP())); connect(this->ui->radioButton_Min, SIGNAL(pressed()), this, SLOT(SetBlendModeToMinIP())); connect(this->ui->radioButton_Mean, SIGNAL(pressed()), this, SLOT(SetBlendModeToMeanIP())); this->ui->blendModeGroupBox->setEnabled(0); connect(this->ui->resetButton, SIGNAL(pressed()), this, SLOT(ResetViews())); connect(this->ui->AddDistance1Button, SIGNAL(pressed()), this, SLOT(AddDistanceMeasurementToView1())); }; void QtVTKRenderWindows::slotExit() { qApp->exit(); } void QtVTKRenderWindows::resliceMode(int mode) { this->ui->thickModeCheckBox->setEnabled(mode ? 1 : 0); this->ui->blendModeGroupBox->setEnabled(mode ? 1 : 0); for (int i = 0; i < 3; i++) { riw[i]->SetResliceMode(mode ? 1 : 0); riw[i]->GetRenderer()->ResetCamera(); riw[i]->Render(); } } void QtVTKRenderWindows::thickMode(int mode) { for (int i = 0; i < 3; i++) { riw[i]->SetThickMode(mode ? 1 : 0); riw[i]->Render(); } } void QtVTKRenderWindows::SetBlendMode(int m) { for (int i = 0; i < 3; i++) { vtkImageSlabReslice *thickSlabReslice = vtkImageSlabReslice::SafeDownCast( vtkResliceCursorThickLineRepresentation::SafeDownCast( riw[i]->GetResliceCursorWidget()->GetRepresentation())->GetReslice()); thickSlabReslice->SetBlendMode(m); riw[i]->Render(); } } void QtVTKRenderWindows::SetBlendModeToMaxIP() { this->SetBlendMode(VTK_IMAGE_SLAB_MAX); } void QtVTKRenderWindows::SetBlendModeToMinIP() { this->SetBlendMode(VTK_IMAGE_SLAB_MIN); } void QtVTKRenderWindows::SetBlendModeToMeanIP() { this->SetBlendMode(VTK_IMAGE_SLAB_MEAN); } void QtVTKRenderWindows::ResetViews() { // Reset the reslice image views for (int i = 0; i < 3; i++) { riw[i]->Reset(); } // Also sync the Image plane widget on the 3D top right view with any // changes to the reslice cursor. for (int i = 0; i < 3; i++) { vtkPlaneSource *ps = static_cast< vtkPlaneSource * >( planeWidget[i]->GetPolyDataAlgorithm()); ps->SetNormal(riw[0]->GetResliceCursor()->GetPlane(i)->GetNormal()); ps->SetCenter(riw[0]->GetResliceCursor()->GetPlane(i)->GetOrigin()); // If the reslice plane has modified, update it on the 3D widget this->planeWidget[i]->UpdatePlacement(); } // Render in response to changes. this->Render(); } void QtVTKRenderWindows::Render() { for (int i = 0; i < 3; i++) { riw[i]->Render(); } this->ui->view3->GetRenderWindow()->Render(); } void QtVTKRenderWindows::AddDistanceMeasurementToView1() { this->AddDistanceMeasurementToView(1); } void QtVTKRenderWindows::AddDistanceMeasurementToView(int i) { // remove existing widgets. if (this->DistanceWidget[i]) { this->DistanceWidget[i]->SetEnabled(0); this->DistanceWidget[i] = nullptr; } // add new widget this->DistanceWidget[i] = vtkSmartPointer< vtkDistanceWidget >::New(); this->DistanceWidget[i]->SetInteractor( this->riw[i]->GetResliceCursorWidget()->GetInteractor()); // Set a priority higher than our reslice cursor widget this->DistanceWidget[i]->SetPriority( this->riw[i]->GetResliceCursorWidget()->GetPriority() + 0.01); vtkSmartPointer< vtkPointHandleRepresentation2D > handleRep = vtkSmartPointer< vtkPointHandleRepresentation2D >::New(); vtkSmartPointer< vtkDistanceRepresentation2D > distanceRep = vtkSmartPointer< vtkDistanceRepresentation2D >::New(); distanceRep->SetHandleRepresentation(handleRep); this->DistanceWidget[i]->SetRepresentation(distanceRep); distanceRep->InstantiateHandleRepresentation(); distanceRep->GetPoint1Representation()->SetPointPlacer(riw[i]->GetPointPlacer()); distanceRep->GetPoint2Representation()->SetPointPlacer(riw[i]->GetPointPlacer()); // Add the distance to the list of widgets whose visibility is managed based // on the reslice plane by the ResliceImageViewerMeasurements class this->riw[i]->GetMeasurements()->AddItem(this->DistanceWidget[i]); this->DistanceWidget[i]->CreateDefaultRepresentation(); this->DistanceWidget[i]->EnabledOn(); } 3 自己的代码#ifndef IMAGEMANAGE_H #define IMAGEMANAGE_H #include <QWidget> #include <QSplitter> #include <QHBoxLayout> #include <QVBoxLayout> #include <QGridLayout> #include <QResizeEvent> #include <QtDebug> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkSmartPointer.h" #include "vtkResliceImageViewer.h" #include "vtkImagePlaneWidget.h" #include "vtkDistanceWidget.h" #include "vtkResliceImageViewerMeasurements.h" #include "vtkBoundedPlanePointPlacer.h" #include "vtkCellPicker.h" #include "vtkCommand.h" #include "vtkDICOMImageReader.h" #include "vtkDistanceRepresentation.h" #include "vtkDistanceRepresentation2D.h" #include "vtkDistanceWidget.h" #include <vtkGenericOpenGLRenderWindow.h> #include "vtkHandleRepresentation.h" #include "vtkImageData.h" #include "vtkImageMapToWindowLevelColors.h" #include "vtkImageSlabReslice.h" #include "vtkInteractorStyleImage.h" #include "vtkLookupTable.h" #include "vtkPlane.h" #include "vtkPlaneSource.h" #include "vtkPointHandleRepresentation2D.h" #include "vtkPointHandleRepresentation3D.h" #include "vtkProperty.h" #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include "vtkRenderWindowInteractor.h" #include "vtkResliceImageViewer.h" #include "vtkResliceCursorLineRepresentation.h" #include "vtkResliceCursorThickLineRepresentation.h" #include "vtkResliceCursorWidget.h" #include "vtkResliceCursorActor.h" #include "vtkResliceCursorPolyDataAlgorithm.h" #include "vtkResliceCursor.h" #include "vtkResliceImageViewerMeasurements.h" class vtkResliceCursorCallback; namespace Ui { class ImageManage; } class ImageManage : public QWidget { Q_OBJECT public: explicit ImageManage(QWidget *parent = nullptr); ~ImageManage(); void setCurrentTab(int temp =0); public slots: /** * @brief slot_ReaderDICOMImage * @param fn * 读取DICOM文件 */ void slot_ReaderDICOMImage(const char* fn); protected: void resizeEvent(QResizeEvent *event) override; private: Ui::ImageManage *ui; QSplitter *mSplitterMain = nullptr; QSplitter *mSplitterVertical = nullptr; QSplitter *mSplitterUp = nullptr; QSplitter *mSplitterDown = nullptr; double color[3] = {0,0,0}; //颜色 vtkSmartPointer<vtkDICOMImageReader> reader = nullptr; //读取DICOM文件 int imageDims[3] = {0}; //暂时不理解 vtkSmartPointer< vtkResliceImageViewer > riw[3]; //三个二维视图 vtkSmartPointer< vtkImagePlaneWidget > planeWidget[3]; vtkSmartPointer< vtkDistanceWidget > DistanceWidget[3]; //测试距离的,暂时没有移植,无用 vtkSmartPointer< vtkResliceImageViewerMeasurements > ResliceMeasurements; //不知道干啥,没有用到 vtkSmartPointer<vtkProperty> ipwProp; //属性 vtkSmartPointer<vtkCellPicker> picker; //拾取器 vtkSmartPointer< vtkRenderer > ren; //3D渲染器 vtkSmartPointer<vtkResliceCursorCallback> cbk; //回调类 }; #endif // IMAGEMANAGE_H #include "imagemanage.h" #include "ui_imagemanage.h" class vtkResliceCursorCallback : public vtkCommand { public: static vtkResliceCursorCallback *New() { return new vtkResliceCursorCallback; } void Execute( vtkObject *caller, unsigned long ev, void *callData ) override { if (ev == vtkResliceCursorWidget::WindowLevelEvent || ev == vtkCommand::WindowLevelEvent || ev == vtkResliceCursorWidget::ResliceThicknessChangedEvent) { // Render everything for (int i = 0; i < 3; i++) { this->RCW[i]->Render(); } this->IPW[0]->GetInteractor()->GetRenderWindow()->Render(); // return; //这里需要注释掉,不然呵呵呵,返回了,还搞个毛线 } vtkImagePlaneWidget* ipw = dynamic_cast< vtkImagePlaneWidget* >( caller ); // qDebug() << "11" << caller << ipw; if (ipw) { double* wl = static_cast<double*>( callData ); if ( ipw == this->IPW[0] ) { this->IPW[1]->SetWindowLevel(wl[0],wl[1],1); this->IPW[2]->SetWindowLevel(wl[0],wl[1],1); } else if( ipw == this->IPW[1] ) { this->IPW[0]->SetWindowLevel(wl[0],wl[1],1); this->IPW[2]->SetWindowLevel(wl[0],wl[1],1); } else if (ipw == this->IPW[2]) { this->IPW[0]->SetWindowLevel(wl[0],wl[1],1); this->IPW[1]->SetWindowLevel(wl[0],wl[1],1); } } vtkResliceCursorWidget *rcw = dynamic_cast<vtkResliceCursorWidget * >(caller); // qDebug() << "22" << caller << rcw; if (rcw) { vtkResliceCursorLineRepresentation *rep = dynamic_cast< vtkResliceCursorLineRepresentation * >(rcw->GetRepresentation()); // Although the return value is not used, we keep the get calls // in case they had side-effects rep->GetResliceCursorActor()->GetCursorAlgorithm()->GetResliceCursor(); for (int i = 0; i < 3; i++) { vtkPlaneSource *ps = static_cast< vtkPlaneSource * >(this->IPW[i]->GetPolyDataAlgorithm()); ps->SetOrigin(this->RCW[i]->GetResliceCursorRepresentation()->GetPlaneSource()->GetOrigin()); ps->SetPoint1(this->RCW[i]->GetResliceCursorRepresentation()-> GetPlaneSource()->GetPoint1()); ps->SetPoint2(this->RCW[i]->GetResliceCursorRepresentation()->GetPlaneSource()->GetPoint2()); // If the reslice plane has modified, update it on the 3D widget this->IPW[i]->UpdatePlacement(); } } // Render everything for (int i = 0; i < 3; i++) { this->RCW[i]->Render(); } this->IPW[0]->GetInteractor()->GetRenderWindow()->Render(); } vtkResliceCursorCallback() {} vtkImagePlaneWidget* IPW[3]; vtkResliceCursorWidget *RCW[3]; }; static QPoint lastPos; ImageManage::ImageManage(QWidget *parent) :QWidget(parent),ui(new Ui::ImageManage) { ui->setupUi(this); /******************窗口大小分割*************************/ mSplitterMain = new QSplitter(Qt::Horizontal,this); mSplitterVertical = new QSplitter(Qt::Vertical,mSplitterMain); mSplitterUp = new QSplitter(Qt::Horizontal,mSplitterVertical); mSplitterUp->addWidget(ui->widget_1); mSplitterUp->addWidget(ui->widget_2); mSplitterUp->setStretchFactor(0,1); mSplitterUp->setStretchFactor(1,1); mSplitterDown = new QSplitter(Qt::Horizontal,mSplitterVertical); mSplitterDown->addWidget(ui->widget_3); mSplitterDown->addWidget(ui->widget_4); mSplitterDown->setStretchFactor(0,1); mSplitterDown->setStretchFactor(1,1); mSplitterMain->insertWidget(0,mSplitterVertical); mSplitterMain->insertWidget(1,ui->widget_5); mSplitterMain->setStretchFactor(0,1); //很魔性啊 } ImageManage::~ImageManage() { delete ui; } void ImageManage::setCurrentTab(int temp) { Q_UNUSED(temp); } void ImageManage::slot_ReaderDICOMImage(const char *fn) { if(!reader) { reader = vtkSmartPointer<vtkDICOMImageReader>::New(); } reader->SetDirectoryName(fn); //这里主要,是文件夹哈,不是文件名 reader->Update(); //得更新呀,惰性渲染 reader->GetOutput()->GetDimensions(imageDims); //还不理解,翻译为获取维度,注释掉以后三维中有影响 for (auto i = 0; i < 3; i++) { riw[i] = vtkSmartPointer< vtkResliceImageViewer >::New(); vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; riw[i]->SetRenderWindow(renderWindow); } // ui->widget_1->SetRenderWindow(riw[0]->GetRenderWindow()); riw[0]->SetupInteractor(ui->widget_1->GetRenderWindow()->GetInteractor()); riw[0]->SetRenderWindow(ui->widget_1->GetRenderWindow()); // ui->widget_2->SetRenderWindow(riw[1]->GetRenderWindow()); riw[1]->SetupInteractor(ui->widget_2->GetRenderWindow()->GetInteractor()); riw[1]->SetRenderWindow(ui->widget_2->GetRenderWindow()); // ui->widget_3->SetRenderWindow(riw[2]->GetRenderWindow()); riw[2]->SetRenderWindow(ui->widget_3->GetRenderWindow()); riw[2]->SetupInteractor(ui->widget_3->GetRenderWindow()->GetInteractor()); for (int i = 0; i < 3; i++) { // make them all share the same reslice cursor object. vtkResliceCursorLineRepresentation *rep =vtkResliceCursorLineRepresentation::SafeDownCast(riw[i]->GetResliceCursorWidget()->GetRepresentation()); riw[i]->SetResliceCursor(riw[0]->GetResliceCursor()); rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i); riw[i]->SetInputData(reader->GetOutput()); riw[i]->SetSliceOrientation(i); riw[i]->SetResliceModeToAxisAligned(); } picker = vtkSmartPointer<vtkCellPicker>::New(); picker->SetTolerance(0.005); ipwProp = vtkSmartPointer<vtkProperty>::New(); ren = vtkSmartPointer< vtkRenderer >::New(); ui->widget_4->GetRenderWindow()->AddRenderer(ren); for (int i = 0; i < 3; i++) { planeWidget[i] = vtkSmartPointer<vtkImagePlaneWidget>::New(); planeWidget[i]->SetInteractor( ui->widget_4->GetInteractor() ); planeWidget[i]->SetPicker(picker); planeWidget[i]->RestrictPlaneToVolumeOn(); color[0] = 0; color[1] = 0; color[2] = 0; color[i] = 1; planeWidget[i]->GetPlaneProperty()->SetColor(color); color[0] = 0; color[1] = 0; color[2] = 0; riw[i]->GetRenderer()->SetBackground( color ); planeWidget[i]->SetTexturePlaneProperty(ipwProp); planeWidget[i]->TextureInterpolateOff(); planeWidget[i]->SetResliceInterpolateToLinear(); planeWidget[i]->SetInputConnection(reader->GetOutputPort()); planeWidget[i]->SetPlaneOrientation(i); planeWidget[i]->SetSliceIndex(imageDims[i]/2); planeWidget[i]->DisplayTextOn(); planeWidget[i]->SetDefaultRenderer(ren); planeWidget[i]->SetWindowLevel(1358, -27); planeWidget[i]->On(); planeWidget[i]->InteractionOn(); } cbk = vtkSmartPointer<vtkResliceCursorCallback>::New(); for (int i = 0; i < 3; i++) { cbk->IPW[i] = planeWidget[i]; cbk->RCW[i] = riw[i]->GetResliceCursorWidget(); riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk ); riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::WindowLevelEvent, cbk ); riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceThicknessChangedEvent, cbk ); riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResetCursorEvent, cbk ); riw[i]->GetInteractorStyle()->AddObserver(vtkCommand::WindowLevelEvent, cbk ); // Make them all share the same color map. riw[i]->SetLookupTable(riw[0]->GetLookupTable()); planeWidget[i]->GetColorMap()->SetLookupTable(riw[0]->GetLookupTable()); //planeWidget[i]->GetColorMap()->SetInput(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()->GetInput()); planeWidget[i]->SetColorMap(riw[i]->GetResliceCursorWidget()->GetResliceCursorRepresentation()->GetColorMap()); } // ui->widget_1->GetRenderWindow()->Render(); // ui->widget_2->GetRenderWindow()->Render(); // ui->widget_3->GetRenderWindow()->Render(); // ui->widget_4->GetRenderWindow()->Render(); //十字线 for (int i = 0; i < 3; i++) { riw[i]->SetResliceMode(1); riw[i]->GetRenderer()->ResetCamera(); riw[i]->Render(); } // 还不知道干啥 // for (int i = 0; i < 3; i++) // { // riw[i]->SetThickMode(1); // riw[i]->Render(); // } // for (int i = 0; i < 3; i++) // { // vtkImageSlabReslice *thickSlabReslice = vtkImageSlabReslice::SafeDownCast( // vtkResliceCursorThickLineRepresentation::SafeDownCast( // riw[i]->GetResliceCursorWidget()->GetRepresentation())->GetReslice()); // thickSlabReslice->SetBlendMode(1); // riw[i]->Render(); // } } void ImageManage::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); mSplitterMain->resize(this->size()); }
欢迎来到我的博客,希望这篇文章对你有所帮助,如果觉得不错,请点赞搜藏哈。文章目录HUD_Qt_for_Python开发之路41 搞定时器HUD_Qt_for_Python开发之路4生活就是TM这么麻烦,嘴上说不高,最终还是得搞,接着研究研究。1 搞定时器今天开搞定时器,为了更好的演示程序,这里使用一个定时器,通过一定逻辑手段来控制UI界面上的控件,已达到模拟显示的目的,将来等数据连入进来,就可以关闭,或者搞成一个演示接口。但是呢,这里又是问题,也是醉了,今天是不是不是适合搞代码呀。 def initTimer(self): self.mTimer = QTimer() self.mTimer.timeout.connect(self.mTimerOut()) self.mTimer.start(10) def mTimerOut(self): print("dasdasdasdsadsa") 先看我的测试代码,按理说没有问题呀,新建一个timer,给他关联一个槽函数,启动定时器,在它的帮助文档中也是以毫秒为单位的,问题是咋就不给动呢?
欢迎来到我的博客,希望这篇文章对你有所帮助,如果觉得不错,请点赞搜藏哈。文章目录HUD_Qt_for_Python开发之路31 UI文件与Python结合1.1 将UI文件编译为一个Python类(静态加载)1.2 问题2 直接加载UI文件(动态加载)2.1 加载UI文件2.2 问题3 交互问题总结HUD_Qt_for_Python开发之路31 UI文件与Python结合这小节将研究下UI文件怎么与Python结合,还是老样子,先找帮助文档,看看有没有帮助。通过查看帮助文档得知,UI文件与Python结合有两种方式将UI文件编译为一个Python类使用直接在Python中加载UI文件1.1 将UI文件编译为一个Python类(静态加载)此时加入我们的UI文件名称为mainwindow.ui文件,那么需要执行以下指令,来将我们的UI文件转化为类1.2 问题用这种方法使用到时没有问题,应该是适用于那种前后端分离的情况,前端UI已经全部制作完成,后端拿到现成的UI文件来实现逻辑逻辑控制即可,要是UI文件和开发是同时进行,那么这种方法就不咋合适了,总不能没更新一个UI就执行一次pyside6-uic 吧 。所以我还是要用第二种了,直接加载的方式。2 直接加载UI文件(动态加载)直接加载UI文件可以很好的规避掉第一种方式中每次更新UI文件都需要重新编译的一次的问题。使用这种加载UI文件的方式,需要用到QUiLoader模块,只需要引入即可from PySide6.QtUiTools import QUiLoader2.1 加载UI文件帮助文档中加载UI文件代码如下import sys from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication from PySide6.QtCore import QFile, QIODevice if __name__ == "__main__": app = QApplication(sys.argv) ui_file_name = "mainwindow.ui" ui_file = QFile(ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print(f"Cannot open {ui_file_name}: {ui_file.errorString()}") sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.show() sys.exit(app.exec_()) 阿西吧,简直就是灾难现场,这几天就是一天研究一句话,这进度,都没法和蜗牛比。要崩溃了,不搞了。总结其实动态加载和静态加载都有各自的优缺点,这将像是你你和你女朋友在一起的时间一样,可以短了刺激,长了就是陪伴,这个也是要结合着使用,可以先在动态里面吧界面搞定了,完了在转成静态的,配合Python进行高级开发。
欢迎来到我的博客,希望这篇文章对你有所帮助,如果觉得不错,请点赞搜藏哈。文章目录HUD_Qt_for_Python开发之路21 设置程序名称2 隐藏窗口标题栏3 设置窗口透明裁剪4 修改下窗口大小,重新加载5 搞定网络模块5.1 包含网络模块5.2 初始化UDP SocketHUD_Qt_for_Python开发之路21 设置程序名称本片我们将正式开始我们HUD仪表的开发工作。这一篇首先要给我们的窗口重新命名为HUD使用代码如下:widget.setWindowTitle("HUD"),代码位置如下图所示。2 隐藏窗口标题栏Python在Qt的中API基本还是保持了Qt原有的样子,好多东西还是可以参照的,就比如这个已隐藏窗口的标题栏,在传统C++中,我们使用setWindowFlag(Qt::FramelessWindowHint);在Python中使用setWindowFlag(QtCore.Qt.FramelessWindowHint,True),是不是很相似,现在看下我们整个main.py程序的全貌。————————————————版权声明:本文为CSDN博主「DreamLife.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/z609932088/article/details/119914698# This Python file uses the following encoding: utf-8 import sys import os from PySide6 import QtCore from PySide6.QtWidgets import QApplication, QWidget from PySide6.QtCore import QFile from PySide6.QtUiTools import QUiLoader class HUD(QWidget): def __init__(self): super(HUD, self).__init__() self.load_ui() def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "hud.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() if __name__ == "__main__": app = QApplication([]) widget = HUD() widget.setWindowTitle("HUD") #设置标题名称 widget.setWindowFlag(QtCore.Qt.FramelessWindowHint,True) #设置程序隐藏标题栏 widget.show() with open("images.qss","r") as f: _style = f.read() app.setStyleSheet(_style) sys.exit(app.exec_()) # This Python file uses the following encoding: utf-8 import sys import os from PySide6 import QtCore from PySide6 import QtNetwork from PySide6.QtNetwork import QUdpSocket from PySide6.QtWidgets import QApplication, QWidget from PySide6.QtCore import QFile,QObject from PySide6.QtUiTools import QUiLoader class HUD(QWidget): def __init__(self): super(HUD, self).__init__() self.load_ui() self.initSocket() def load_ui(self): loader = QUiLoader() path = os.path.join(os.path.dirname(__file__), "hud.ui") ui_file = QFile(path) ui_file.open(QFile.ReadOnly) loader.load(ui_file, self) ui_file.close() def initSocket(self): udpSocket = QUdpSocket(self) #初始化 udpSocket.bind(6876) #绑定端口 # self.connect(udpSocket,SIGNAL('readyRead()'),self,SLOT('readPendingDatagrams')) udpSocket.readyRead.connect(self.readPendingDatagrams) #新的信号槽编写方式 def readPendingDatagrams(self): while udpSocket.hasPendingDatagrams: datagram = QByteArray() datagram.resize(udpSocket.pendingDatagramSize()) (sender,senderPort) = udpSocket.readDatagram(datagram.data(), datagram.size()) processTheDatagram(datagram) print(datagram) if __name__ == "__main__": app = QApplication([]) widget = HUD() widget.setWindowTitle("HUD") #设置标题名称 widget.setWindowFlag(QtCore.Qt.FramelessWindowHint,True) #设置程序隐藏标题栏 widget.setAttribute(QtCore.Qt.WA_TranslucentBackground,True) #设置窗口透明 widget.show() with open("images.qss","r") as f: _style = f.read() app.setStyleSheet(_style) sys.exit(app.exec_())
本文将主要介绍医学四视图的基本布局。包括轴、矢、冠和3D显示窗口以及一个窗宽窗位调节窗口。电梯1 布局2 代码2.1 imagemanage.h2.2 imagemanage.cpp☞ 源码1 布局 本模块是还是在ThirdVtk基础上添加一个模块,下图所示:#ifndef IMAGEMANAGE_H #define IMAGEMANAGE_H #include <QWidget> #include <QSplitter> #include <QHBoxLayout> #include <QVBoxLayout> #include <QGridLayout> #include <QTextEdit> #include <QResizeEvent> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" namespace Ui { class ImageManage; } class ImageManage : public QWidget { Q_OBJECT public: explicit ImageManage(QWidget *parent = nullptr); ~ImageManage(); void setCurrentTab(int temp =0); protected: void resizeEvent(QResizeEvent *event) override; private: Ui::ImageManage *ui; QSplitter *mSplitterMain = nullptr; QSplitter *mSplitterVertical = nullptr; QSplitter *mSplitterUp = nullptr; QSplitter *mSplitterDown = nullptr; }; #endif // IMAGEMANAGE_H 2.2 imagemanage.cpp#include "imagemanage.h" #include "ui_imagemanage.h" #include <QtDebug> ImageManage::ImageManage(QWidget *parent) : QWidget(parent), ui(new Ui::ImageManage) { ui->setupUi(this); mSplitterMain = new QSplitter(Qt::Horizontal,this); mSplitterVertical = new QSplitter(Qt::Vertical,mSplitterMain); mSplitterUp = new QSplitter(Qt::Horizontal,mSplitterVertical); mSplitterUp->addWidget(ui->widget_1); mSplitterUp->addWidget(ui->widget_2); mSplitterUp->setStretchFactor(0,1); mSplitterUp->setStretchFactor(1,1); mSplitterDown = new QSplitter(Qt::Horizontal,mSplitterVertical); mSplitterDown->addWidget(ui->widget_3); mSplitterDown->addWidget(ui->widget_4); mSplitterDown->setStretchFactor(0,1); mSplitterDown->setStretchFactor(1,1); mSplitterMain->insertWidget(0,mSplitterVertical); mSplitterMain->insertWidget(1,ui->widget_5); mSplitterMain->setStretchFactor(0,1); //很魔性啊 } ImageManage::~ImageManage() { delete ui; } void ImageManage::setCurrentTab(int temp) { } void ImageManage::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); mSplitterMain->resize(this->size()); }
摘要文章目录1 官方示例展示2 代码搬运2.1 qscalarstocolors.h2.2 qscalarstocolors.cpp3 运行效果★ 源码 ★1 官方示例展示 今天我们又来搬运代码了,今天搬运的是官方实例QScalarsToColors,下面看向官方实例演示#ifndef QSCALARSTOCOLORS_H #define QSCALARSTOCOLORS_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "QVTKOpenGLWidget.h" #include "vtkChartXY.h" #include "vtkColorTransferFunction.h" #include "vtkCompositeTransferFunctionItem.h" #include "vtkContextScene.h" #include "vtkContextView.h" #include "vtkFloatArray.h" #include "vtkGenericOpenGLRenderWindow.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkPiecewiseFunction.h" #include "vtkPlot.h" #include "vtkQtTableView.h" #include "vtkRenderer.h" #include "vtkRenderWindowInteractor.h" #include "vtkTimerLog.h" #include <QResizeEvent> namespace Ui { class QScalarsToColors; } class QScalarsToColors : public QWidget { Q_OBJECT public: explicit QScalarsToColors(QWidget *parent = 0); ~QScalarsToColors(); void resizeEvent(QResizeEvent *event)override; private: Ui::QScalarsToColors *ui; QVTKOpenGLWidget *qvtkWidget = nullptr; vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; vtkNew<vtkContextView> view; }; #endif // QSCALARSTOCOLORS_H 2.2 qscalarstocolors.cpp#include "qscalarstocolors.h" #include "ui_qscalarstocolors.h" QScalarsToColors::QScalarsToColors(QWidget *parent) : QWidget(parent), ui(new Ui::QScalarsToColors) { ui->setupUi(this); qvtkWidget = new QVTKOpenGLWidget(ui->widget); qvtkWidget->SetRenderWindow(renderWindow); view->SetRenderWindow(qvtkWidget->GetRenderWindow()); view->SetInteractor(qvtkWidget->GetInteractor()); vtkNew<vtkChartXY> chart; chart->SetTitle("Chart"); view->GetScene()->AddItem(chart); vtkNew<vtkColorTransferFunction> colorTransferFunction; colorTransferFunction->AddHSVSegment(0.,0.,1.,1.,0.3333,0.3333,1.,1.); colorTransferFunction->AddHSVSegment(0.3333,0.3333,1.,1.,0.6666,0.6666,1.,1.); colorTransferFunction->AddHSVSegment(0.6666,0.6666,1.,1.,1.,0.,1.,1.); colorTransferFunction->Build(); vtkNew<vtkPiecewiseFunction> opacityFunction; opacityFunction->AddPoint(0.,0.); opacityFunction->AddPoint(0.5,0.5); opacityFunction->AddPoint(1.,1.); vtkNew<vtkCompositeTransferFunctionItem> item3; item3->SetColorTransferFunction(colorTransferFunction); item3->SetOpacityFunction(opacityFunction); item3->SetOpacity(0.2); item3->SetMaskAboveCurve(true); chart->AddPlot(item3); } QScalarsToColors::~QScalarsToColors() { delete ui; } void QScalarsToColors::resizeEvent(QResizeEvent *event) { qvtkWidget->resize(ui->widget->size()); }
摘要文章目录1 官方示例展示2 代码搬运2.1 qcharttable.h2.2 qcharttable.cpp3 运行效果★ 源码 ★1 官方示例展示 今天接着人搬运代码,官方实例QChartTable,官方演示效果#ifndef QCHARTTABLE_H #define QCHARTTABLE_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkChartXY.h" #include "vtkContextScene.h" #include "vtkContextView.h" #include "vtkFloatArray.h" #include "vtkGenericOpenGLRenderWindow.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkPlot.h" #include "vtkQtTableView.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkSmartPointer.h" #include "vtkTable.h" #include "vtkTimerLog.h" #include "QHBoxLayout" #include "QSurfaceFormat" #include "QResizeEvent" namespace Ui { class QChartTable; } class QChartTable : public QWidget { Q_OBJECT public: explicit QChartTable(QWidget *parent = 0); ~QChartTable(); void resizeEvent(QResizeEvent *event); private: Ui::QChartTable *ui; QVTKOpenGLWidget *qvtkWidget = nullptr; vtkNew<vtkGenericOpenGLRenderWindow> renderWidow; vtkNew<vtkContextView> view; vtkNew<vtkTable> table; vtkNew<vtkFloatArray> arrX; vtkNew<vtkFloatArray> arrC; vtkNew<vtkFloatArray> arrS; vtkNew<vtkTimerLog> timers; vtkNew<vtkChartXY> chart; vtkNew<vtkQtTableView> tableview; }; #endif // QCHARTTABLE_H 2.2 qcharttable.cpp#include "qcharttable.h" #include "ui_qcharttable.h" QChartTable::QChartTable(QWidget *parent) : QWidget(parent), ui(new Ui::QChartTable) { ui->setupUi(this); qvtkWidget = new QVTKOpenGLWidget(ui->widget); qvtkWidget->SetRenderWindow(renderWidow); view->SetRenderWindow(renderWidow); view->SetInteractor(renderWidow->GetInteractor()); arrX->SetName("X Axis"); table->AddColumn(arrX); arrC->SetName("Cosine"); table->AddColumn(arrC); arrS->SetName("Sine"); table->AddColumn(arrS); int numPoints = 29; float inc = 7.0 / (numPoints - 1); table->SetNumberOfRows(numPoints); for(auto i = 0;i< numPoints;i++) { table->SetValue(i,0,i * inc); table->SetValue(i,1,cos(i * inc)+0.0); table->SetValue(i,2,sin(i * inc)+0.0); } view->GetScene()->AddItem(chart); vtkPlot *line = chart->AddPlot(vtkChart::LINE); line->SetInputData(table,0,1); line->SetColor(255,0,255); line = chart->AddPlot(vtkChart::LINE); line->SetInputData(table,0,2); line->SetColor(0,255,255); line->SetWidth(2.0); tableview->SetSplitMultiComponentColumns(true); tableview->AddRepresentationFromInput(table); tableview->Update(); QHBoxLayout *layout = new QHBoxLayout(ui->widget); layout->addWidget(qvtkWidget, 2); layout->addWidget(tableview->GetWidget()); } QChartTable::~QChartTable() { delete ui; } void QChartTable::resizeEvent(QResizeEvent *event) { // qvtkWidget->resize(ui->widget->size()); }
摘要文章目录1 官方示例展示2 代码搬运2.1 piecewiseitem.h2.2 piecewiseitem.cpp3 运行效果★ 源码 ★1 官方示例展示 今天搬运的代码是官方实例PiecewiseItem,先看先官方代码跑起来的样子。2 代码搬运2.1 piecewiseitem.h#ifndef PIECEWISEITEM_H #define PIECEWISEITEM_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkSmartPointer.h" #include "vtkContextView.h" #include "vtkContextScene.h" #include "vtkPiecewiseFunction.h" #include "vtkPiecewiseFunctionItem.h" #include "vtkPiecewiseControlPointsItem.h" namespace Ui { class PiecewiseItem; } class PiecewiseItem : public QWidget { Q_OBJECT public: explicit PiecewiseItem(QWidget *parent = 0); ~PiecewiseItem(); private: Ui::PiecewiseItem *ui; vtkSmartPointer<vtkContextView> view = nullptr; vtkSmartPointer<vtkPiecewiseFunction> source = nullptr; vtkSmartPointer<vtkPiecewiseControlPointsItem> item = nullptr; }; #endif // PIECEWISEITEM_H 2.2 piecewiseitem.cpp#include "piecewiseitem.h" #include "ui_piecewiseitem.h" PiecewiseItem::PiecewiseItem(QWidget *parent) : QWidget(parent), ui(new Ui::PiecewiseItem) { ui->setupUi(this); view = vtkSmartPointer<vtkContextView>::New(); view->SetRenderWindow(ui->widget->GetRenderWindow()); view->GetRenderer()->SetBackground(0,0,1); source = vtkSmartPointer<vtkPiecewiseFunction>::New(); source->AddPoint(0,0); source->AddPoint(200,200); source->AddPoint(400,600); source->AddPoint(700,500); item = vtkSmartPointer<vtkPiecewiseControlPointsItem>::New(); item->SetPiecewiseFunction(source); view->GetScene()->AddItem(item); } PiecewiseItem::~PiecewiseItem() { delete ui; }
这个我也不知道是啥东西。文章目录1 官方示例展示2 代码搬运2.1 labeledmesh.h2.2 labeledmesh.cpp3运行效果★ 源码 ★1 官方示例展示 哎呀,这英语才是第一生产力,英语不好,是真的很烦人那。今天我们么接着搬运代码,官方示例如下2 代码搬运2.1 labeledmesh.h#ifndef LABELEDMESH_H #define LABELEDMESH_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkSmartPointer.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper2D.h" #include "vtkActor2D.h" #include "vtkSphereSource.h" #include "vtkPolyDataMapper.h" #include "vtkActor.h" #include "vtkIdFilter.h" #include "vtkRenderer.h" #include "vtkSelectVisiblePoints.h" #include "vtkLabeledDataMapper.h" #include "vtkCellCenters.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkTextProperty.h" static int xLength; static int yLength; static vtkSmartPointer<vtkSelectVisiblePoints> visPts; static vtkSmartPointer<vtkSelectVisiblePoints> visCells; static vtkSmartPointer<vtkPoints> pts; static vtkSmartPointer<vtkRenderWindow>renwin; namespace Ui { class LabeledMesh; } class LabeledMesh : public QWidget { Q_OBJECT public: explicit LabeledMesh(QWidget *parent = 0); ~LabeledMesh(); void PlaceWindow(int xmin, int ymin); void MoveWindow(); private: Ui::LabeledMesh *ui; }; #endif // LABELEDMESH_H 2.2 labeledmesh.cpp#include "labeledmesh.h" #include "ui_labeledmesh.h" LabeledMesh::LabeledMesh(QWidget *parent) : QWidget(parent), ui(new Ui::LabeledMesh) { ui->setupUi(this); int xmin = 200; xLength = 100; int xmax = xmin + xLength; int ymin = 200; yLength = 100; int ymax = xmin+yLength; pts = vtkSmartPointer<vtkPoints>::New(); pts->InsertPoint(0,xmin,ymin,0); pts->InsertPoint(1,xmax,ymin,0); pts->InsertPoint(2,xmax,ymax,0); pts->InsertPoint(3,xmin,ymax,0); vtkSmartPointer<vtkCellArray> rect = vtkSmartPointer<vtkCellArray>::New(); rect->InsertNextCell(5); rect->InsertCellPoint(0); rect->InsertCellPoint(1); rect->InsertCellPoint(2); rect->InsertCellPoint(3); rect->InsertCellPoint(0); vtkSmartPointer<vtkPolyData> selectRect = vtkSmartPointer<vtkPolyData>::New(); selectRect->SetPoints(pts); selectRect->SetLines(rect); vtkSmartPointer<vtkPolyDataMapper2D> rectMapper = vtkSmartPointer<vtkPolyDataMapper2D>::New(); rectMapper->SetInputData(selectRect); vtkSmartPointer<vtkActor2D> rectActor = vtkSmartPointer<vtkActor2D>::New(); rectActor->SetMapper(rectMapper); vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New(); vtkSmartPointer<vtkPolyDataMapper> sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); sphereMapper->SetInputConnection(sphere->GetOutputPort()); vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New(); sphereActor->SetMapper(sphereMapper); vtkSmartPointer<vtkIdFilter> ids = vtkSmartPointer<vtkIdFilter>::New(); ids->SetInputConnection(sphere->GetOutputPort()); ids->PointIdsOn(); ids->CellIdsOn(); ids->FieldDataOn(); vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer<vtkRenderer>::New(); visPts = vtkSmartPointer<vtkSelectVisiblePoints>::New(); visPts->SetInputConnection(ids->GetOutputPort()); visPts->SetRenderer(ren1); visPts->SelectionWindowOn(); visPts->SetSelection(xmin,xmin+xLength,ymin,ymin+yLength); vtkSmartPointer<vtkLabeledDataMapper> ldm = vtkSmartPointer<vtkLabeledDataMapper>::New(); ldm->SetInputConnection(visPts->GetOutputPort()); ldm->SetLabelModeToLabelFieldData(); vtkSmartPointer<vtkActor2D> pointLabels = vtkSmartPointer<vtkActor2D>::New(); pointLabels->SetMapper(ldm); vtkSmartPointer<vtkCellCenters> cc = vtkSmartPointer<vtkCellCenters>::New(); cc->SetInputConnection(ids->GetOutputPort()); visCells = vtkSmartPointer<vtkSelectVisiblePoints>::New(); visCells->SetInputConnection(cc->GetOutputPort()); visCells->SetRenderer(ren1); visCells->SelectionWindowOn(); visCells->SetSelection(xmin,xmin+xLength,ymin,ymin+ yLength); vtkSmartPointer<vtkLabeledDataMapper> cellmapper = vtkSmartPointer<vtkLabeledDataMapper>::New(); cellmapper->SetInputConnection(visCells->GetOutputPort()); cellmapper->SetLabelModeToLabelFieldData(); cellmapper->GetLabelTextProperty()->SetColor(0,1,0); vtkSmartPointer<vtkActor2D> cellLabels = vtkSmartPointer<vtkActor2D>::New(); cellLabels->SetMapper(cellmapper); ui->widget->GetRenderWindow()->AddRenderer(ren1); ren1->AddActor(sphereActor); ren1->AddActor2D(rectActor); ren1->AddActor2D(pointLabels); ren1->AddActor2D(cellLabels); // MoveWindow(); // PlaceWindow(xmin,ymin); } LabeledMesh::~LabeledMesh() { delete ui; } void LabeledMesh::PlaceWindow(int xmin, int ymin) { int xmax = xmin + xLength; int ymax = ymin + yLength; visPts->SetSelection(xmin,xmax,ymin,ymax); visCells->SetSelection(xmin,xmax,ymin,ymax); pts->InsertPoint(0,xmin,ymin,0); pts->InsertPoint(1,xmin,ymin,0); pts->InsertPoint(2,xmin,ymin,0); pts->InsertPoint(3,xmin,ymin,0); pts->Modified(); renwin->Render(); } void LabeledMesh::MoveWindow() { for(int y = 100;y<300;y+=25) for(int x = 100;x<300;x+=25) PlaceWindow(x,y); }
摘要文章目录1 官方示例展示2 代码搬运2.1 graphitem.h2.2 graphitem.cpp2.3 vtkContextItem.h2.4 vtkContextItem.cpp3 运行效果4 错误解决方法Error: no override found for 'vtkContextDevice2D'.★ 源码 ★1 官方示例展示前面有好几个例子有点复杂,现在还搞不到定,先搬运下这个。下图是官方的示例。有个比较尴尬的是发生了,就是官方的Demo现在也不能演示了,没有内容了,直接给我白屏了。2 代码搬运2.1 graphitem.h#include "graphitem.h" #include "ui_graphitem.h" GraphItem::GraphItem(QWidget *parent) : QWidget(parent), ui(new Ui::GraphItem) { ui->setupUi(this); mview = vtkSmartPointer<vtkContextView>::New(); mview->GetRenderer()->SetBackground(0.0, 1.0, 1.0); mview->GetRenderWindow()->SetSize(800, 600); source = vtkSmartPointer<vtkRandomGraphSource>::New(); source->SetNumberOfVertices(100); source->SetNumberOfEdges(0); source->StartWithTreeOn(); source->Update(); item = vtkSmartPointer<vtkGraphItem>::New(); item->SetGraph(source->GetOutput()); mview->GetScene()->AddItem(item); anim = vtkSmartPointer<GraphAnimate>::New(); anim->view = mview; anim->GraphItem = item; mview->SetRenderWindow(ui->widget->GetRenderWindow()); mview->GetRenderWindow()->GetInteractor()->Initialize(); mview->GetRenderWindow()->GetInteractor()->CreateOneShotTimer(10); mview->GetRenderWindow()->GetInteractor()->AddObserver(vtkCommand::TimerEvent, anim); } GraphItem::~GraphItem() { delete ui; } void GraphItem::startinteractor() { // view->GetRenderWindow()->GetInteractor()->Start(); } 2.2 graphitem.cpp#include "graphitem.h" #include "ui_graphitem.h" GraphItem::GraphItem(QWidget *parent) : QWidget(parent), ui(new Ui::GraphItem) { ui->setupUi(this); mview = vtkSmartPointer<vtkContextView>::New(); mview->GetRenderer()->SetBackground(0.0, 1.0, 1.0); mview->GetRenderWindow()->SetSize(800, 600); source = vtkSmartPointer<vtkRandomGraphSource>::New(); source->SetNumberOfVertices(100); source->SetNumberOfEdges(0); source->StartWithTreeOn(); source->Update(); item = vtkSmartPointer<vtkGraphItem>::New(); item->SetGraph(source->GetOutput()); mview->GetScene()->AddItem(item); anim = vtkSmartPointer<GraphAnimate>::New(); anim->view = mview; anim->GraphItem = item; mview->SetRenderWindow(ui->widget->GetRenderWindow()); mview->GetRenderWindow()->GetInteractor()->Initialize(); mview->GetRenderWindow()->GetInteractor()->CreateOneShotTimer(10); mview->GetRenderWindow()->GetInteractor()->AddObserver(vtkCommand::TimerEvent, anim); } GraphItem::~GraphItem() { delete ui; } void GraphItem::startinteractor() { // view->GetRenderWindow()->GetInteractor()->Start(); } 2.3 vtkContextItem.h#ifndef VTKGRAPHITEM_H #define VTKGRAPHITEM_H #include "vtkContextItem.h" #include "vtkEdgeListIterator.h" #include "vtkOutEdgeIterator.h" #include "vtkGraph.h" #include "vtkMinimalStandardRandomSequence.h" #include "vtkVariant.h" #include "vtkContext2D.h" #include "vtkContextScene.h" #include "vtkContextMouseEvent.h" #include "vtkPen.h" #include "vtkBrush.h" #include "vtkTextProperty.h" #include "vtkTransform2D.h" #include "vtkObjectFactory.h" #include "vtkSmartPointer.h" #include "utility" #include "vector" class vtkContext2D; class vtkGraph; class vtkGraphItem : public vtkContextItem { public: vtkTypeMacro(vtkGraphItem,vtkContextItem); void PrintSelf(ostream &os, vtkIndent indent) override; static vtkGraphItem *New(); vtkGetObjectMacro(Graph,vtkGraph); virtual void SetGraph(vtkGraph* g); bool Paint(vtkContext2D *painter) override; bool Hit(const vtkContextMouseEvent &mouse)override; bool MouseEnterEvent(const vtkContextMouseEvent &mouse)override; bool MouseMoveEvent(const vtkContextMouseEvent &mouse)override; bool MouseLeaveEvent(const vtkContextMouseEvent &mouse)override; bool MouseButtonPressEvent(const vtkContextMouseEvent &mouse)override; bool MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse)override; void UpdatePositions(); protected: vtkGraphItem(); ~vtkGraphItem() override; float LastPosition[2]; bool MouseOver; int MouseButtonPressed; vtkGraph *Graph; vtkIdType HitVertex; class Implementation; Implementation *Impl; private: vtkGraphItem(const vtkGraphItem &) = delete; void operator =(const vtkGraphItem &) = delete; }; #endif // VTKGRAPHITEM_H 2.4 vtkContextItem.cpp这段代码偷懒了,直接把Demo中的代码复制过来了#include "vtkgraphitem.h" vtkCxxSetObjectMacro(vtkGraphItem, Graph, vtkGraph); vtkStandardNewMacro(vtkGraphItem); class vtkGraphItem::Implementation { public: Implementation() { Random = vtkSmartPointer<vtkMinimalStandardRandomSequence>::New(); } void CheckPositionSize(vtkIdType i) { while (i >= static_cast<vtkIdType>(this->Position.size())) { int size[2] = {100, 100}; if (this->Item->GetScene()) { this->Item->GetScene()->GetGeometry(size); } this->Random->Next(); float x = static_cast<int>(this->Random->GetValue()*size[0]); this->Random->Next(); float y = static_cast<int>(this->Random->GetValue()*size[1]); this->Position.push_back(std::make_pair(x, y)); } } void GetPosition(vtkIdType i, float x[2]) { this->CheckPositionSize(i); x[0] = this->Position[i].first; x[1] = this->Position[i].second; } void SetPosition(vtkIdType i, float x[2]) { this->CheckPositionSize(i); this->Position[i] = std::make_pair(x[0], x[1]); } void CheckVelocitySize(vtkIdType i) { while (i >= static_cast<vtkIdType>(this->Velocity.size())) { this->Velocity.push_back(std::make_pair(0.0f, 0.0f)); } } void GetVelocity(vtkIdType i, float x[2]) { this->CheckVelocitySize(i); x[0] = this->Velocity[i].first; x[1] = this->Velocity[i].second; } void SetVelocity(vtkIdType i, float x[2]) { this->CheckVelocitySize(i); this->Velocity[i] = std::make_pair(x[0], x[1]); } vtkSmartPointer<vtkMinimalStandardRandomSequence> Random; vtkGraphItem* Item; std::vector<std::pair<float, float> > Position; std::vector<std::pair<float, float> > Velocity; }; //----------------------------------------------------------------------------- vtkGraphItem::vtkGraphItem() { this->Impl = new Implementation(); this->Impl->Item = this; this->Graph = nullptr; this->MouseOver = false; this->MouseButtonPressed = -1; this->HitVertex = 0; } //----------------------------------------------------------------------------- vtkGraphItem::~vtkGraphItem() { delete this->Impl; this->SetGraph(nullptr); } //----------------------------------------------------------------------------- bool vtkGraphItem::Paint(vtkContext2D *painter) { painter->GetTextProp()->SetVerticalJustificationToCentered(); painter->GetTextProp()->SetJustificationToCentered(); painter->GetTextProp()->SetColor(0.0, 0.0, 0.0); painter->GetTextProp()->SetFontSize(12); painter->GetPen()->SetColorF(0.0f, 0.0f, 0.0f); painter->GetBrush()->SetColorF(0.8f, 0.8f, 1.0f, 0.5f); vtkSmartPointer<vtkEdgeListIterator> it = vtkSmartPointer<vtkEdgeListIterator>::New(); this->Graph->GetEdges(it); float line[4] = {0.0f, 0.0f, 0.0f, 0.0f}; while (it->HasNext()) { vtkEdgeType e = it->Next(); this->Impl->GetPosition(e.Source, line); this->Impl->GetPosition(e.Target, line+2); for (int i = 0; i < 4; ++i) { line[i] += 10.0f; } painter->DrawLine(line); } float dims[4] = {0.0f, 0.0f, 20.0f, 20.0f}; for (vtkIdType i = 0; i < this->Graph->GetNumberOfVertices(); ++i) { this->Impl->GetPosition(i, dims); painter->DrawRect(dims[0], dims[1], dims[2], dims[3]); float x = dims[0] + 0.5 * dims[2]; float y = dims[1] + 0.5 * dims[3]; painter->DrawString(x, y, vtkVariant(i).ToString()); } return true; } //----------------------------------------------------------------------------- bool vtkGraphItem::Hit(const vtkContextMouseEvent &mouse) { float pos[2] = {0.0f, 0.0f}; for (vtkIdType i = this->Graph->GetNumberOfVertices()-1; i >= 0; --i) { this->Impl->GetPosition(i, pos); if (mouse.GetPos()[0] > pos[0] && mouse.GetPos()[0] < pos[0] + 20.0f && mouse.GetPos()[1] > pos[1] && mouse.GetPos()[1] < pos[1] + 20.0f) { this->HitVertex = i; return true; } } return false; } //----------------------------------------------------------------------------- bool vtkGraphItem::MouseEnterEvent(const vtkContextMouseEvent &) { this->MouseOver = true; return true; } //----------------------------------------------------------------------------- bool vtkGraphItem::MouseMoveEvent(const vtkContextMouseEvent &mouse) { int deltaX = static_cast<int>(mouse.GetPos()[0] - this->LastPosition[0]); int deltaY = static_cast<int>(mouse.GetPos()[1] - this->LastPosition[1]); this->LastPosition[0] = mouse.GetPos()[0]; this->LastPosition[1] = mouse.GetPos()[1]; if (this->MouseButtonPressed == 0) { // Move the vertex by this amount float pos[2]; this->Impl->GetPosition(this->HitVertex, pos); pos[0] += deltaX; pos[1] += deltaY; this->Impl->SetPosition(this->HitVertex, pos); return true; } #if 0 if (this->MouseButtonPressed == 1) { if (deltaX > 0.0) { if (!this->GetTransform()) { vtkSmartPointer<vtkTransform2D> t = vtkSmartPointer<vtkTransform2D>::New(); t->Identity(); this->SetTransform(t); } this->GetTransform()->Scale(deltaX/50.0f, deltaX/50.0f); } return true; } #endif return false; } //----------------------------------------------------------------------------- bool vtkGraphItem::MouseLeaveEvent(const vtkContextMouseEvent &) { this->MouseOver = false; return true; } //----------------------------------------------------------------------------- bool vtkGraphItem::MouseButtonPressEvent(const vtkContextMouseEvent &mouse) { this->MouseButtonPressed = mouse.GetButton(); this->LastPosition[0] = mouse.GetPos()[0]; this->LastPosition[1] = mouse.GetPos()[1]; return true; } //----------------------------------------------------------------------------- bool vtkGraphItem::MouseButtonReleaseEvent(const vtkContextMouseEvent &) { this->MouseButtonPressed = -1; return true; } //----------------------------------------------------------------------------- void vtkGraphItem::UpdatePositions() { vtkIdType numVerts = this->Graph->GetNumberOfVertices(); float restDistance = 40.0f; float dampenLast = 0.5f; float springConstant = 0.3f; float repulseConstant = 1.0f; //float restDistance = 40.0f; //float dampenLast = 0.5f; //float springConstant = 0.1f; //float repulseConstant = 2.0f; float epsilon = 0.0000001f; float border = 20.0f; vtkSmartPointer<vtkOutEdgeIterator> it = vtkSmartPointer<vtkOutEdgeIterator>::New(); float uPos[2]; float vPos[2]; float uVel[2]; int geom[2] = {100, 100}; if (this->GetScene()) { this->GetScene()->GetGeometry(geom); } for (vtkIdType u = 0; u < numVerts; ++u) { if (this->MouseButtonPressed == 0 && u == this->HitVertex) { continue; } this->Impl->GetPosition(u, uPos); float fx = 0.0; float fy = 0.0; for (vtkIdType v = 0; v < numVerts; ++v) { this->Impl->GetPosition(v, vPos); float deltaX = uPos[0] - vPos[0]; float deltaY = uPos[1] - vPos[1]; float distSquared = deltaX*deltaX + deltaY*deltaY; // Avoid divide by zero distSquared += epsilon; fx += repulseConstant * deltaX / distSquared; fy += repulseConstant * deltaY / distSquared; } this->Graph->GetOutEdges(u, it); while (it->HasNext()) { vtkOutEdgeType e = it->Next(); vtkIdType v = e.Target; if (u == v) { continue; } this->Impl->GetPosition(v, vPos); float deltaX = uPos[0] - vPos[0]; float deltaY = uPos[1] - vPos[1]; float dist = sqrt(deltaX*deltaX + deltaY*deltaY); float force = springConstant*(dist - restDistance); fx -= force * deltaX / dist; fy -= force * deltaY / dist; } float center[2] = {uPos[0] + 10.0f, uPos[1] + 10.0f}; // Change the force if it is near the edge if (center[0] < border) { fx += -(center[0] - border); } else if (center[0] > geom[0] - border) { fx += -(center[0] - (geom[0] - border)); } if (center[1] < border) { fy += -(center[1] - border); } else if (center[1] > geom[1] - border) { fy += -(center[1] - (geom[1] - border)); } // Update velocity and position this->Impl->GetVelocity(u, uVel); uVel[0] = dampenLast*uVel[0] + fx; uVel[1] = dampenLast*uVel[1] + fy; uPos[0] += uVel[0]; uPos[1] += uVel[1]; this->Impl->SetPosition(u, uPos); this->Impl->SetVelocity(u, uVel); } } //----------------------------------------------------------------------------- void vtkGraphItem::PrintSelf(ostream &os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } 3 运行效果这个就尴尬了,目前在的这台电脑上市出不来效果了,包括官方的Demo也是白屏状态,目前还不知道啥情况。留坑。4 错误解决方法Error: no override found for ‘vtkContextDevice2D’.在main中加入VTK_MODULE_INIT(vtkRenderingContextOpenGL);在加入上面的语句后,会出现如下错误老鸟一看这应该就是丢库了,我这二货还不知道,搞了好久,网上找了半天,终于找到了提示,需要看下库有没有包含进去[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Kj3nzL5-1628730592619)(https://raw.githubusercontent.com/DreamLife-Jianwei/CSDNResources/master/20210629093058.png)] 如上图所示,在检查了我包含的库文件后,修改代码为VTK_MODULE_INIT(vtkRenderingContextOpenGL2); 搞定!!!★ 源码 ★ 源码分享一时爽,一直分享一直爽, 链接如下:自取:https://github.com/DreamLife-Jianwei/Qt-Vtk
这个我也不知道是啥呀,接着还是先占位更新吧。文章目录1 官方示例展示2 官方源代码★ 源码 ★1 官方示例展示 嗯哼哼,今天出师不利呀,占坑,不要给我寄刀片。2 官方源代码#include "vtkBoxWidget.h" #include "vtkCamera.h" #include "vtkCommand.h" #include "vtkColorTransferFunction.h" #include "vtkDICOMImageReader.h" #include "vtkImageData.h" #include "vtkImageResample.h" #include "vtkMetaImageReader.h" #include "vtkPiecewiseFunction.h" #include "vtkPlanes.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include "vtkXMLImageDataReader.h" #include "vtkSmartVolumeMapper.h" #define VTI_FILETYPE 1 #define MHA_FILETYPE 2 // Callback for moving the planes from the box widget to the mapper class vtkBoxWidgetCallback : public vtkCommand { public: static vtkBoxWidgetCallback *New() { return new vtkBoxWidgetCallback; } void Execute(vtkObject *caller, unsigned long, void*) override { vtkBoxWidget *widget = reinterpret_cast<vtkBoxWidget*>(caller); if (this->Mapper) { vtkPlanes *planes = vtkPlanes::New(); widget->GetPlanes(planes); this->Mapper->SetClippingPlanes(planes); planes->Delete(); } } void SetMapper(vtkSmartVolumeMapper* m) { this->Mapper = m; } protected: vtkBoxWidgetCallback() { this->Mapper = nullptr; } vtkSmartVolumeMapper *Mapper; }; void PrintUsage() { cout << "Usage: " << endl; cout << endl; cout << " GPURenderDemo <options>" << endl; cout << endl; cout << "where options may include: " << endl; cout << endl; cout << " -DICOM <directory>" << endl; cout << " -VTI <filename>" << endl; cout << " -MHA <filename>" << endl; cout << " -DependentComponents" << endl; cout << " -Clip" << endl; cout << " -MIP <window> <level>" << endl; cout << " -CompositeRamp <window> <level>" << endl; cout << " -CompositeShadeRamp <window> <level>" << endl; cout << " -CT_Skin" << endl; cout << " -CT_Bone" << endl; cout << " -CT_Muscle" << endl; cout << " -FrameRate <rate>" << endl; cout << " -DataReduction <factor>" << endl; cout << endl; cout << "You must use either the -DICOM option to specify the directory where" << endl; cout << "the data is located or the -VTI or -MHA option to specify the path of a .vti file." << endl; cout << endl; cout << "By default, the program assumes that the file has independent components," << endl; cout << "use -DependentComponents to specify that the file has dependent components." << endl; cout << endl; cout << "Use the -Clip option to display a cube widget for clipping the volume." << endl; cout << "Use the -FrameRate option with a desired frame rate (in frames per second)" << endl; cout << "which will control the interactive rendering rate." << endl; cout << "Use the -DataReduction option with a reduction factor (greater than zero and" << endl; cout << "less than one) to reduce the data before rendering." << endl; cout << "Use one of the remaining options to specify the blend function" << endl; cout << "and transfer functions. The -MIP option utilizes a maximum intensity" << endl; cout << "projection method, while the others utilize compositing. The" << endl; cout << "-CompositeRamp option is unshaded compositing, while the other" << endl; cout << "compositing options employ shading." << endl; cout << endl; cout << "Note: MIP, CompositeRamp, CompositeShadeRamp, CT_Skin, CT_Bone," << endl; cout << "and CT_Muscle are appropriate for DICOM data. MIP, CompositeRamp," << endl; cout << "and RGB_Composite are appropriate for RGB data." << endl; cout << endl; cout << "Example: GPURenderDemo -DICOM CTNeck -MIP 4096 1024" << endl; cout << endl; } int main(int argc, char *argv[]) { // Parse the parameters int count = 1; char *dirname = nullptr; double opacityWindow = 4096; double opacityLevel = 2048; int blendType = 0; int clip = 0; double reductionFactor = 1.0; double frameRate = 10.0; char *fileName=nullptr; int fileType=0; bool independentComponents=true; while ( count < argc ) { if ( !strcmp( argv[count], "?" ) ) { PrintUsage(); exit(EXIT_SUCCESS); } else if ( !strcmp( argv[count], "-DICOM" ) ) { size_t size = strlen(argv[count+1])+1; dirname = new char[size]; snprintf( dirname, size, "%s", argv[count+1] ); count += 2; } else if ( !strcmp( argv[count], "-VTI" ) ) { size_t size = strlen(argv[count+1])+1; fileName = new char[size]; fileType = VTI_FILETYPE; snprintf( fileName, size, "%s", argv[count+1] ); count += 2; } else if ( !strcmp( argv[count], "-MHA" ) ) { size_t size = strlen(argv[count+1])+1; fileName = new char[size]; fileType = MHA_FILETYPE; snprintf( fileName, size, "%s", argv[count+1] ); count += 2; } else if ( !strcmp( argv[count], "-Clip") ) { clip = 1; count++; } else if ( !strcmp( argv[count], "-MIP" ) ) { opacityWindow = atof( argv[count+1] ); opacityLevel = atof( argv[count+2] ); blendType = 0; count += 3; } else if ( !strcmp( argv[count], "-CompositeRamp" ) ) { opacityWindow = atof( argv[count+1] ); opacityLevel = atof( argv[count+2] ); blendType = 1; count += 3; } else if ( !strcmp( argv[count], "-CompositeShadeRamp" ) ) { opacityWindow = atof( argv[count+1] ); opacityLevel = atof( argv[count+2] ); blendType = 2; count += 3; } else if ( !strcmp( argv[count], "-CT_Skin" ) ) { blendType = 3; count += 1; } else if ( !strcmp( argv[count], "-CT_Bone" ) ) { blendType = 4; count += 1; } else if ( !strcmp( argv[count], "-CT_Muscle" ) ) { blendType = 5; count += 1; } else if ( !strcmp( argv[count], "-RGB_Composite" ) ) { blendType = 6; count += 1; } else if ( !strcmp( argv[count], "-FrameRate") ) { frameRate = atof( argv[count+1] ); if ( frameRate < 0.01 || frameRate > 60.0 ) { cout << "Invalid frame rate - use a number between 0.01 and 60.0" << endl; cout << "Using default frame rate of 10 frames per second." << endl; frameRate = 10.0; } count += 2; } else if ( !strcmp( argv[count], "-ReductionFactor") ) { reductionFactor = atof( argv[count+1] ); if ( reductionFactor <= 0.0 || reductionFactor >= 1.0 ) { cout << "Invalid reduction factor - use a number between 0 and 1 (exclusive)" << endl; cout << "Using the default of no reduction." << endl; reductionFactor = 1.0; } count += 2; } else if ( !strcmp( argv[count], "-DependentComponents") ) { independentComponents=false; count += 1; } else { cout << "Unrecognized option: " << argv[count] << endl; cout << endl; PrintUsage(); exit(EXIT_FAILURE); } } if ( !dirname && !fileName) { cout << "Error: you must specify a directory of DICOM data or a .vti file or a .mha!" << endl; cout << endl; PrintUsage(); exit(EXIT_FAILURE); } // Create the renderer, render window and interactor vtkRenderer *renderer = vtkRenderer::New(); vtkRenderWindow *renWin = vtkRenderWindow::New(); renWin->AddRenderer(renderer); // Connect it all. Note that funny arithematic on the // SetDesiredUpdateRate - the vtkRenderWindow divides it // allocated time across all renderers, and the renderer // divides it time across all props. If clip is // true then there are two props vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); iren->SetRenderWindow(renWin); iren->SetDesiredUpdateRate(frameRate / (1+clip) ); iren->GetInteractorStyle()->SetDefaultRenderer(renderer); // Read the data vtkAlgorithm *reader=nullptr; vtkImageData *input=nullptr; if(dirname) { vtkDICOMImageReader *dicomReader = vtkDICOMImageReader::New(); dicomReader->SetDirectoryName(dirname); dicomReader->Update(); input=dicomReader->GetOutput(); reader=dicomReader; } else if ( fileType == VTI_FILETYPE ) { vtkXMLImageDataReader *xmlReader = vtkXMLImageDataReader::New(); xmlReader->SetFileName(fileName); xmlReader->Update(); input=xmlReader->GetOutput(); reader=xmlReader; } else if ( fileType == MHA_FILETYPE ) { vtkMetaImageReader *metaReader = vtkMetaImageReader::New(); metaReader->SetFileName(fileName); metaReader->Update(); input=metaReader->GetOutput(); reader=metaReader; } else { cout << "Error! Not VTI or MHA!" << endl; exit(EXIT_FAILURE); } // Verify that we actually have a volume int dim[3]; input->GetDimensions(dim); if ( dim[0] < 2 || dim[1] < 2 || dim[2] < 2 ) { cout << "Error loading data!" << endl; exit(EXIT_FAILURE); } vtkImageResample *resample = vtkImageResample::New(); if ( reductionFactor < 1.0 ) { resample->SetInputConnection( reader->GetOutputPort() ); resample->SetAxisMagnificationFactor(0, reductionFactor); resample->SetAxisMagnificationFactor(1, reductionFactor); resample->SetAxisMagnificationFactor(2, reductionFactor); } // Create our volume and mapper vtkVolume *volume = vtkVolume::New(); vtkSmartVolumeMapper *mapper = vtkSmartVolumeMapper::New(); // Add a box widget if the clip option was selected vtkBoxWidget *box = vtkBoxWidget::New(); if (clip) { box->SetInteractor(iren); box->SetPlaceFactor(1.01); if ( reductionFactor < 1.0 ) { box->SetInputConnection(resample->GetOutputPort()); } else { box->SetInputData(input); } box->SetDefaultRenderer(renderer); box->InsideOutOn(); box->PlaceWidget(); vtkBoxWidgetCallback *callback = vtkBoxWidgetCallback::New(); callback->SetMapper(mapper); box->AddObserver(vtkCommand::InteractionEvent, callback); callback->Delete(); box->EnabledOn(); box->GetSelectedFaceProperty()->SetOpacity(0.0); } if ( reductionFactor < 1.0 ) { mapper->SetInputConnection( resample->GetOutputPort() ); } else { mapper->SetInputConnection( reader->GetOutputPort() ); } // Set the sample distance on the ray to be 1/2 the average spacing double spacing[3]; if ( reductionFactor < 1.0 ) { resample->GetOutput()->GetSpacing(spacing); } else { input->GetSpacing(spacing); } // mapper->SetSampleDistance( (spacing[0]+spacing[1]+spacing[2])/6.0 ); // mapper->SetMaximumImageSampleDistance(10.0); // Create our transfer function vtkColorTransferFunction *colorFun = vtkColorTransferFunction::New(); vtkPiecewiseFunction *opacityFun = vtkPiecewiseFunction::New(); // Create the property and attach the transfer functions vtkVolumeProperty *property = vtkVolumeProperty::New(); property->SetIndependentComponents(independentComponents); property->SetColor( colorFun ); property->SetScalarOpacity( opacityFun ); property->SetInterpolationTypeToLinear(); // connect up the volume to the property and the mapper volume->SetProperty( property ); volume->SetMapper( mapper ); // Depending on the blend type selected as a command line option, // adjust the transfer function switch ( blendType ) { // MIP // Create an opacity ramp from the window and level values. // Color is white. Blending is MIP. case 0: colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0 ); opacityFun->AddSegment( opacityLevel - 0.5*opacityWindow, 0.0, opacityLevel + 0.5*opacityWindow, 1.0 ); mapper->SetBlendModeToMaximumIntensity(); break; // CompositeRamp // Create a ramp from the window and level values. Use compositing // without shading. Color is a ramp from black to white. case 1: colorFun->AddRGBSegment(opacityLevel - 0.5*opacityWindow, 0.0, 0.0, 0.0, opacityLevel + 0.5*opacityWindow, 1.0, 1.0, 1.0 ); opacityFun->AddSegment( opacityLevel - 0.5*opacityWindow, 0.0, opacityLevel + 0.5*opacityWindow, 1.0 ); mapper->SetBlendModeToComposite(); property->ShadeOff(); break; // CompositeShadeRamp // Create a ramp from the window and level values. Use compositing // with shading. Color is white. case 2: colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0 ); opacityFun->AddSegment( opacityLevel - 0.5*opacityWindow, 0.0, opacityLevel + 0.5*opacityWindow, 1.0 ); mapper->SetBlendModeToComposite(); property->ShadeOn(); break; // CT_Skin // Use compositing and functions set to highlight skin in CT data // Not for use on RGB data case 3: colorFun->AddRGBPoint( -3024, 0, 0, 0, 0.5, 0.0 ); colorFun->AddRGBPoint( -1000, .62, .36, .18, 0.5, 0.0 ); colorFun->AddRGBPoint( -500, .88, .60, .29, 0.33, 0.45 ); colorFun->AddRGBPoint( 3071, .83, .66, 1, 0.5, 0.0 ); opacityFun->AddPoint(-3024, 0, 0.5, 0.0 ); opacityFun->AddPoint(-1000, 0, 0.5, 0.0 ); opacityFun->AddPoint(-500, 1.0, 0.33, 0.45 ); opacityFun->AddPoint(3071, 1.0, 0.5, 0.0); mapper->SetBlendModeToComposite(); property->ShadeOn(); property->SetAmbient(0.1); property->SetDiffuse(0.9); property->SetSpecular(0.2); property->SetSpecularPower(10.0); property->SetScalarOpacityUnitDistance(0.8919); break; // CT_Bone // Use compositing and functions set to highlight bone in CT data // Not for use on RGB data case 4: colorFun->AddRGBPoint( -3024, 0, 0, 0, 0.5, 0.0 ); colorFun->AddRGBPoint( -16, 0.73, 0.25, 0.30, 0.49, .61 ); colorFun->AddRGBPoint( 641, .90, .82, .56, .5, 0.0 ); colorFun->AddRGBPoint( 3071, 1, 1, 1, .5, 0.0 ); opacityFun->AddPoint(-3024, 0, 0.5, 0.0 ); opacityFun->AddPoint(-16, 0, .49, .61 ); opacityFun->AddPoint(641, .72, .5, 0.0 ); opacityFun->AddPoint(3071, .71, 0.5, 0.0); mapper->SetBlendModeToComposite(); property->ShadeOn(); property->SetAmbient(0.1); property->SetDiffuse(0.9); property->SetSpecular(0.2); property->SetSpecularPower(10.0); property->SetScalarOpacityUnitDistance(0.8919); break; // CT_Muscle // Use compositing and functions set to highlight muscle in CT data // Not for use on RGB data case 5: colorFun->AddRGBPoint( -3024, 0, 0, 0, 0.5, 0.0 ); colorFun->AddRGBPoint( -155, .55, .25, .15, 0.5, .92 ); colorFun->AddRGBPoint( 217, .88, .60, .29, 0.33, 0.45 ); colorFun->AddRGBPoint( 420, 1, .94, .95, 0.5, 0.0 ); colorFun->AddRGBPoint( 3071, .83, .66, 1, 0.5, 0.0 ); opacityFun->AddPoint(-3024, 0, 0.5, 0.0 ); opacityFun->AddPoint(-155, 0, 0.5, 0.92 ); opacityFun->AddPoint(217, .68, 0.33, 0.45 ); opacityFun->AddPoint(420,.83, 0.5, 0.0); opacityFun->AddPoint(3071, .80, 0.5, 0.0); mapper->SetBlendModeToComposite(); property->ShadeOn(); property->SetAmbient(0.1); property->SetDiffuse(0.9); property->SetSpecular(0.2); property->SetSpecularPower(10.0); property->SetScalarOpacityUnitDistance(0.8919); break; // RGB_Composite // Use compositing and functions set to highlight red/green/blue regions // in RGB data. Not for use on single component data case 6: opacityFun->AddPoint(0, 0.0); opacityFun->AddPoint(5.0, 0.0); opacityFun->AddPoint(30.0, 0.05); opacityFun->AddPoint(31.0, 0.0); opacityFun->AddPoint(90.0, 0.0); opacityFun->AddPoint(100.0, 0.3); opacityFun->AddPoint(110.0, 0.0); opacityFun->AddPoint(190.0, 0.0); opacityFun->AddPoint(200.0, 0.4); opacityFun->AddPoint(210.0, 0.0); opacityFun->AddPoint(245.0, 0.0); opacityFun->AddPoint(255.0, 0.5); mapper->SetBlendModeToComposite(); property->ShadeOff(); property->SetScalarOpacityUnitDistance(1.0); break; default: vtkGenericWarningMacro("Unknown blend type."); break; } // Set the default window size renWin->SetSize(600,600); renWin->Render(); // Add the volume to the scene renderer->AddVolume( volume ); renderer->ResetCamera(); // interact with data renWin->Render(); iren->Start(); opacityFun->Delete(); colorFun->Delete(); property->Delete(); box->Delete(); volume->Delete(); mapper->Delete(); reader->Delete(); resample->Delete(); renderer->Delete(); renWin->Delete(); iren->Delete(); return 0; }
实在抱歉,今天这个我也还是不知道干啥的,目前还没有用到相关内容,只能先暂停,后续用到,继续更新。文章目录1 官方示例展示2 官方源码★ 源码 ★1 官方示例展示 这个官方示例运行起来好像没有达到预定的效果。报错了。2 官方源码// VTK includes #include "vtkBoxWidget.h" #include "vtkCamera.h" #include "vtkCommand.h" #include "vtkColorTransferFunction.h" #include "vtkDICOMImageReader.h" #include "vtkImageData.h" #include "vtkImageResample.h" #include "vtkMetaImageReader.h" #include "vtkPiecewiseFunction.h" #include "vtkPlanes.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkVolume.h" #include "vtkVolumeProperty.h" #include "vtkXMLImageDataReader.h" #include "vtkFixedPointVolumeRayCastMapper.h" #define VTI_FILETYPE 1 #define MHA_FILETYPE 2 void PrintUsage() { cout << "Usage: " << endl; cout << endl; cout << " FixedPointVolumeRayCastMapperCT <options>" << endl; cout << endl; cout << "where options may include: " << endl; cout << endl; cout << " -DICOM <directory>" << endl; cout << " -VTI <filename>" << endl; cout << " -MHA <filename>" << endl; cout << " -DependentComponents" << endl; cout << " -Clip" << endl; cout << " -MIP <window> <level>" << endl; cout << " -CompositeRamp <window> <level>" << endl; cout << " -CompositeShadeRamp <window> <level>" << endl; cout << " -CT_Skin" << endl; cout << " -CT_Bone" << endl; cout << " -CT_Muscle" << endl; cout << " -FrameRate <rate>" << endl; cout << " -DataReduction <factor>" << endl; cout << endl; cout << "You must use either the -DICOM option to specify the directory where" << endl; cout << "the data is located or the -VTI or -MHA option to specify the path of a .vti file." << endl; cout << endl; cout << "By default, the program assumes that the file has independent components," << endl; cout << "use -DependentComponents to specify that the file has dependent components." << endl; cout << endl; cout << "Use the -Clip option to display a cube widget for clipping the volume." << endl; cout << "Use the -FrameRate option with a desired frame rate (in frames per second)" << endl; cout << "which will control the interactive rendering rate." << endl; cout << "Use the -DataReduction option with a reduction factor (greater than zero and" << endl; cout << "less than one) to reduce the data before rendering." << endl; cout << "Use one of the remaining options to specify the blend function" << endl; cout << "and transfer functions. The -MIP option utilizes a maximum intensity" << endl; cout << "projection method, while the others utilize compositing. The" << endl; cout << "-CompositeRamp option is unshaded compositing, while the other" << endl; cout << "compositing options employ shading." << endl; cout << endl; cout << "Note: MIP, CompositeRamp, CompositeShadeRamp, CT_Skin, CT_Bone," << endl; cout << "and CT_Muscle are appropriate for DICOM data. MIP, CompositeRamp," << endl; cout << "and RGB_Composite are appropriate for RGB data." << endl; cout << endl; cout << "Example: FixedPointVolumeRayCastMapperCT -DICOM CTNeck -MIP 4096 1024" << endl; cout << endl; } int main(int argc, char *argv[]) { // Parse the parameters int count = 1; char *dirname = nullptr; double opacityWindow = 4096; double opacityLevel = 2048; int blendType = 0; int clip = 0; double reductionFactor = 1.0; double frameRate = 10.0; char *fileName=nullptr; int fileType=0; bool independentComponents=true; while ( count < argc ) { if ( !strcmp( argv[count], "?" ) ) { PrintUsage(); exit(EXIT_SUCCESS); } else if ( !strcmp( argv[count], "-DICOM" ) ) { size_t size = strlen(argv[count+1])+1; dirname = new char[size]; snprintf( dirname, size, "%s", argv[count+1] ); count += 2; } else if ( !strcmp( argv[count], "-VTI" ) ) { size_t size = strlen(argv[count+1])+1; fileName = new char[size]; fileType = VTI_FILETYPE; snprintf( fileName, size, "%s", argv[count+1] ); count += 2; } else if ( !strcmp( argv[count], "-MHA" ) ) { size_t size = strlen(argv[count+1])+1; fileName = new char[size]; fileType = MHA_FILETYPE; snprintf( fileName, size, "%s", argv[count+1] ); count += 2; } else if ( !strcmp( argv[count], "-Clip") ) { clip = 1; count++; } else if ( !strcmp( argv[count], "-MIP" ) ) { opacityWindow = atof( argv[count+1] ); opacityLevel = atof( argv[count+2] ); blendType = 0; count += 3; } else if ( !strcmp( argv[count], "-CompositeRamp" ) ) { opacityWindow = atof( argv[count+1] ); opacityLevel = atof( argv[count+2] ); blendType = 1; count += 3; } else if ( !strcmp( argv[count], "-CompositeShadeRamp" ) ) { opacityWindow = atof( argv[count+1] ); opacityLevel = atof( argv[count+2] ); blendType = 2; count += 3; } else if ( !strcmp( argv[count], "-CT_Skin" ) ) { blendType = 3; count += 1; } else if ( !strcmp( argv[count], "-CT_Bone" ) ) { blendType = 4; count += 1; } else if ( !strcmp( argv[count], "-CT_Muscle" ) ) { blendType = 5; count += 1; } else if ( !strcmp( argv[count], "-RGB_Composite" ) ) { blendType = 6; count += 1; } else if ( !strcmp( argv[count], "-FrameRate") ) { frameRate = atof( argv[count+1] ); if ( frameRate < 0.01 || frameRate > 60.0 ) { cout << "Invalid frame rate - use a number between 0.01 and 60.0" << endl; cout << "Using default frame rate of 10 frames per second." << endl; frameRate = 10.0; } count += 2; } else if ( !strcmp( argv[count], "-ReductionFactor") ) { reductionFactor = atof( argv[count+1] ); if ( reductionFactor <= 0.0 || reductionFactor >= 1.0 ) { cout << "Invalid reduction factor - use a number between 0 and 1 (exclusive)" << endl; cout << "Using the default of no reduction." << endl; reductionFactor = 1.0; } count += 2; } else if ( !strcmp( argv[count], "-DependentComponents") ) { independentComponents=false; count += 1; } else { cout << "Unrecognized option: " << argv[count] << endl; cout << endl; PrintUsage(); exit(EXIT_FAILURE); } } if ( !dirname && !fileName) { cout << "Error: you must specify a directory of DICOM data or a .vti file or a .mha!" << endl; cout << endl; PrintUsage(); exit(EXIT_FAILURE); } // Create the renderer, render window and interactor vtkRenderer *renderer = vtkRenderer::New(); vtkRenderWindow *renWin = vtkRenderWindow::New(); renWin->AddRenderer(renderer); // Connect it all. Note that funny arithematic on the // SetDesiredUpdateRate - the vtkRenderWindow divides it // allocated time across all renderers, and the renderer // divides it time across all props. If clip is // true then there are two props vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); iren->SetRenderWindow(renWin); iren->SetDesiredUpdateRate(frameRate / (1+clip) ); iren->GetInteractorStyle()->SetDefaultRenderer(renderer); // Read the data vtkAlgorithm *reader=nullptr; vtkImageData *input=nullptr; if(dirname) { vtkDICOMImageReader *dicomReader = vtkDICOMImageReader::New(); dicomReader->SetDirectoryName(dirname); dicomReader->Update(); input=dicomReader->GetOutput(); reader=dicomReader; } else if ( fileType == VTI_FILETYPE ) { vtkXMLImageDataReader *xmlReader = vtkXMLImageDataReader::New(); xmlReader->SetFileName(fileName); xmlReader->Update(); input=xmlReader->GetOutput(); reader=xmlReader; } else if ( fileType == MHA_FILETYPE ) { vtkMetaImageReader *metaReader = vtkMetaImageReader::New(); metaReader->SetFileName(fileName); metaReader->Update(); input=metaReader->GetOutput(); reader=metaReader; } else { cout << "Error! Not VTI or MHA!" << endl; exit(EXIT_FAILURE); } // Verify that we actually have a volume int dim[3]; input->GetDimensions(dim); if ( dim[0] < 2 || dim[1] < 2 || dim[2] < 2 ) { cout << "Error loading data!" << endl; exit(EXIT_FAILURE); } vtkImageResample *resample = vtkImageResample::New(); if ( reductionFactor < 1.0 ) { resample->SetInputConnection( reader->GetOutputPort() ); resample->SetAxisMagnificationFactor(0, reductionFactor); resample->SetAxisMagnificationFactor(1, reductionFactor); resample->SetAxisMagnificationFactor(2, reductionFactor); } // Create our volume and mapper vtkVolume *volume = vtkVolume::New(); vtkFixedPointVolumeRayCastMapper *mapper = vtkFixedPointVolumeRayCastMapper::New(); if ( reductionFactor < 1.0 ) { mapper->SetInputConnection( resample->GetOutputPort() ); } else { mapper->SetInputConnection( reader->GetOutputPort() ); } // Set the sample distance on the ray to be 1/2 the average spacing double spacing[3]; if ( reductionFactor < 1.0 ) { resample->GetOutput()->GetSpacing(spacing); } else { input->GetSpacing(spacing); } // mapper->SetSampleDistance( (spacing[0]+spacing[1]+spacing[2])/6.0 ); // mapper->SetMaximumImageSampleDistance(10.0); // Create our transfer function vtkColorTransferFunction *colorFun = vtkColorTransferFunction::New(); vtkPiecewiseFunction *opacityFun = vtkPiecewiseFunction::New(); // Create the property and attach the transfer functions vtkVolumeProperty *property = vtkVolumeProperty::New(); property->SetIndependentComponents(independentComponents); property->SetColor( colorFun ); property->SetScalarOpacity( opacityFun ); property->SetInterpolationTypeToLinear(); // connect up the volume to the property and the mapper volume->SetProperty( property ); volume->SetMapper( mapper ); // Depending on the blend type selected as a command line option, // adjust the transfer function switch ( blendType ) { // MIP // Create an opacity ramp from the window and level values. // Color is white. Blending is MIP. case 0: colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0 ); opacityFun->AddSegment( opacityLevel - 0.5*opacityWindow, 0.0, opacityLevel + 0.5*opacityWindow, 1.0 ); mapper->SetBlendModeToMaximumIntensity(); break; // CompositeRamp // Create a ramp from the window and level values. Use compositing // without shading. Color is a ramp from black to white. case 1: colorFun->AddRGBSegment(opacityLevel - 0.5*opacityWindow, 0.0, 0.0, 0.0, opacityLevel + 0.5*opacityWindow, 1.0, 1.0, 1.0 ); opacityFun->AddSegment( opacityLevel - 0.5*opacityWindow, 0.0, opacityLevel + 0.5*opacityWindow, 1.0 ); mapper->SetBlendModeToComposite(); property->ShadeOff(); break; // CompositeShadeRamp // Create a ramp from the window and level values. Use compositing // with shading. Color is white. case 2: colorFun->AddRGBSegment(0.0, 1.0, 1.0, 1.0, 255.0, 1.0, 1.0, 1.0 ); opacityFun->AddSegment( opacityLevel - 0.5*opacityWindow, 0.0, opacityLevel + 0.5*opacityWindow, 1.0 ); mapper->SetBlendModeToComposite(); property->ShadeOn(); break; // CT_Skin // Use compositing and functions set to highlight skin in CT data // Not for use on RGB data case 3: colorFun->AddRGBPoint( -3024, 0, 0, 0, 0.5, 0.0 ); colorFun->AddRGBPoint( -1000, .62, .36, .18, 0.5, 0.0 ); colorFun->AddRGBPoint( -500, .88, .60, .29, 0.33, 0.45 ); colorFun->AddRGBPoint( 3071, .83, .66, 1, 0.5, 0.0 ); opacityFun->AddPoint(-3024, 0, 0.5, 0.0 ); opacityFun->AddPoint(-1000, 0, 0.5, 0.0 ); opacityFun->AddPoint(-500, 1.0, 0.33, 0.45 ); opacityFun->AddPoint(3071, 1.0, 0.5, 0.0); mapper->SetBlendModeToComposite(); property->ShadeOn(); property->SetAmbient(0.1); property->SetDiffuse(0.9); property->SetSpecular(0.2); property->SetSpecularPower(10.0); property->SetScalarOpacityUnitDistance(0.8919); break; // CT_Bone // Use compositing and functions set to highlight bone in CT data // Not for use on RGB data case 4: colorFun->AddRGBPoint( -3024, 0, 0, 0, 0.5, 0.0 ); colorFun->AddRGBPoint( -16, 0.73, 0.25, 0.30, 0.49, .61 ); colorFun->AddRGBPoint( 641, .90, .82, .56, .5, 0.0 ); colorFun->AddRGBPoint( 3071, 1, 1, 1, .5, 0.0 ); opacityFun->AddPoint(-3024, 0, 0.5, 0.0 ); opacityFun->AddPoint(-16, 0, .49, .61 ); opacityFun->AddPoint(641, .72, .5, 0.0 ); opacityFun->AddPoint(3071, .71, 0.5, 0.0); mapper->SetBlendModeToComposite(); property->ShadeOn(); property->SetAmbient(0.1); property->SetDiffuse(0.9); property->SetSpecular(0.2); property->SetSpecularPower(10.0); property->SetScalarOpacityUnitDistance(0.8919); break; // CT_Muscle // Use compositing and functions set to highlight muscle in CT data // Not for use on RGB data case 5: colorFun->AddRGBPoint( -3024, 0, 0, 0, 0.5, 0.0 ); colorFun->AddRGBPoint( -155, .55, .25, .15, 0.5, .92 ); colorFun->AddRGBPoint( 217, .88, .60, .29, 0.33, 0.45 ); colorFun->AddRGBPoint( 420, 1, .94, .95, 0.5, 0.0 ); colorFun->AddRGBPoint( 3071, .83, .66, 1, 0.5, 0.0 ); opacityFun->AddPoint(-3024, 0, 0.5, 0.0 ); opacityFun->AddPoint(-155, 0, 0.5, 0.92 ); opacityFun->AddPoint(217, .68, 0.33, 0.45 ); opacityFun->AddPoint(420,.83, 0.5, 0.0); opacityFun->AddPoint(3071, .80, 0.5, 0.0); mapper->SetBlendModeToComposite(); property->ShadeOn(); property->SetAmbient(0.1); property->SetDiffuse(0.9); property->SetSpecular(0.2); property->SetSpecularPower(10.0); property->SetScalarOpacityUnitDistance(0.8919); break; // RGB_Composite // Use compositing and functions set to highlight red/green/blue regions // in RGB data. Not for use on single component data case 6: opacityFun->AddPoint(0, 0.0); opacityFun->AddPoint(5.0, 0.0); opacityFun->AddPoint(30.0, 0.05); opacityFun->AddPoint(31.0, 0.0); opacityFun->AddPoint(90.0, 0.0); opacityFun->AddPoint(100.0, 0.3); opacityFun->AddPoint(110.0, 0.0); opacityFun->AddPoint(190.0, 0.0); opacityFun->AddPoint(200.0, 0.4); opacityFun->AddPoint(210.0, 0.0); opacityFun->AddPoint(245.0, 0.0); opacityFun->AddPoint(255.0, 0.5); mapper->SetBlendModeToComposite(); property->ShadeOff(); property->SetScalarOpacityUnitDistance(1.0); break; default: vtkGenericWarningMacro("Unknown blend type."); break; } // Set the default window size renWin->SetSize(600,600); renWin->Render(); // Add the volume to the scene renderer->AddVolume( volume ); renderer->ResetCamera(); // interact with data renWin->Render(); iren->Start(); opacityFun->Delete(); colorFun->Delete(); property->Delete(); volume->Delete(); mapper->Delete(); reader->Delete(); resample->Delete(); renderer->Delete(); renWin->Delete(); iren->Delete(); return 0; }
今天这个还是搞不懂,接着更新官方源代码。文章目录1 官方示例展示2 官方源代码2.1 EasyView.h2.2 EasyView.cpp★ 源码 ★1 官方示例展示 不知道这个Demo和CustomLinkView Demo有什么区别。简单运行没有看到啥不一样的呀,占坑,不要寄刀片。2 官方源代码2.1 EasyView.h#ifndef EasyView_H #define EasyView_H #include "vtkSmartPointer.h" // Required for smart pointer internal ivars. #include <QMainWindow> // Forward Qt class declarations class Ui_EasyView; // Forward VTK class declarations class vtkXMLTreeReader; class vtkGraphLayoutView; class vtkQtTableView; class vtkQtTreeView; class EasyView : public QMainWindow { Q_OBJECT public: // Constructor/Destructor EasyView(); ~EasyView() override; public slots: virtual void slotOpenXMLFile(); virtual void slotExit(); protected: protected slots: private: // Methods void SetupAnnotationLink(); // Members vtkSmartPointer<vtkXMLTreeReader> XMLReader; vtkSmartPointer<vtkGraphLayoutView> GraphView; vtkSmartPointer<vtkQtTreeView> TreeView; vtkSmartPointer<vtkQtTableView> TableView; vtkSmartPointer<vtkQtTreeView> ColumnView; // Designer form Ui_EasyView *ui; }; #endif // EasyView_H 2.2 EasyView.cpp#include "ui_EasyView.h" #include "EasyView.h" // VTK includes #include <vtkAnnotationLink.h> #include <vtkDataObjectToTable.h> #include <vtkDataRepresentation.h> #include "vtkGenericOpenGLRenderWindow.h" #include <vtkGraphLayoutView.h> #include <vtkQtTableView.h> #include <vtkQtTreeView.h> #include <vtkRenderer.h> #include <vtkSelection.h> #include <vtkSelectionNode.h> #include <vtkTable.h> #include <vtkTableToGraph.h> #include <vtkTreeLayoutStrategy.h> #include <vtkViewTheme.h> #include <vtkViewUpdater.h> #include <vtkXMLTreeReader.h> // Qt includes #include <QDir> #include <QFileDialog> #include <QTreeView> #include "vtkSmartPointer.h" #define VTK_CREATE(type, name) \ vtkSmartPointer<type> name = vtkSmartPointer<type>::New() // Constructor EasyView::EasyView() { this->ui = new Ui_EasyView; this->ui->setupUi(this); vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; this->ui->vtkGraphViewWidget->SetRenderWindow(renderWindow); this->XMLReader = vtkSmartPointer<vtkXMLTreeReader>::New(); this->GraphView = vtkSmartPointer<vtkGraphLayoutView>::New(); this->TreeView = vtkSmartPointer<vtkQtTreeView>::New(); this->TableView = vtkSmartPointer<vtkQtTableView>::New(); this->ColumnView = vtkSmartPointer<vtkQtTreeView>::New(); this->ColumnView->SetUseColumnView(1); // Tell the table view to sort selections that it receives (but does // not initiate) to the top this->TableView->SetSortSelectionToTop(true); // Set widgets for the tree and table views this->ui->treeFrame->layout()->addWidget(this->TreeView->GetWidget()); this->ui->tableFrame->layout()->addWidget(this->TableView->GetWidget()); this->ui->columnFrame->layout()->addWidget(this->ColumnView->GetWidget()); // Graph View needs to get my render window this->GraphView->SetInteractor(this->ui->vtkGraphViewWidget->GetInteractor()); this->GraphView->SetRenderWindow(this->ui->vtkGraphViewWidget->GetRenderWindow()); // Set up the theme on the graph view :) vtkViewTheme* theme = vtkViewTheme::CreateNeonTheme(); this->GraphView->ApplyViewTheme(theme); theme->Delete(); // Set up action signals and slots connect(this->ui->actionOpenXMLFile, SIGNAL(triggered()), this, SLOT(slotOpenXMLFile())); connect(this->ui->actionExit, SIGNAL(triggered()), this, SLOT(slotExit())); // Apply application stylesheet QString css = "* { font: bold italic 18px \"Calibri\"; color: midnightblue }"; css += "QTreeView { font: bold italic 16px \"Calibri\"; color: midnightblue }"; //qApp->setStyleSheet(css); // Seems to cause a bug on some systems // But at least it's here as an example this->GraphView->Render(); }; // Set up the annotation between the vtk and qt views void EasyView::SetupAnnotationLink() { // Create a selection link and have all the views use it VTK_CREATE(vtkAnnotationLink,annLink); this->TreeView->GetRepresentation()->SetAnnotationLink(annLink); this->TreeView->GetRepresentation()->SetSelectionType(vtkSelectionNode::PEDIGREEIDS); this->TableView->GetRepresentation()->SetAnnotationLink(annLink); this->TableView->GetRepresentation()->SetSelectionType(vtkSelectionNode::PEDIGREEIDS); this->ColumnView->GetRepresentation()->SetAnnotationLink(annLink); this->ColumnView->GetRepresentation()->SetSelectionType(vtkSelectionNode::PEDIGREEIDS); this->GraphView->GetRepresentation()->SetAnnotationLink(annLink); this->GraphView->GetRepresentation()->SetSelectionType(vtkSelectionNode::PEDIGREEIDS); // Set up the theme on the graph view :) vtkViewTheme* theme = vtkViewTheme::CreateNeonTheme(); this->GraphView->ApplyViewTheme(theme); this->GraphView->Update(); theme->Delete(); VTK_CREATE(vtkViewUpdater,updater); updater->AddView(this->TreeView); updater->AddView(this->TableView); updater->AddView(this->ColumnView); updater->AddView(this->GraphView); updater->AddAnnotationLink(annLink); } EasyView::~EasyView() { } // Action to be taken upon graph file open void EasyView::slotOpenXMLFile() { // Browse for and open the file QDir dir; // Open the text data file QString fileName = QFileDialog::getOpenFileName( this, "Select the text data file", QDir::homePath(), "XML Files (*.xml);;All Files (*.*)"); if (fileName.isNull()) { cerr << "Could not open file" << endl; return; } // Create XML reader this->XMLReader->SetFileName( fileName.toLatin1() ); this->XMLReader->ReadTagNameOff(); this->XMLReader->Update(); // Set up some hard coded parameters for the graph view this->GraphView->SetVertexLabelArrayName("id"); this->GraphView->VertexLabelVisibilityOn(); this->GraphView->SetVertexColorArrayName("VertexDegree"); this->GraphView->ColorVerticesOn(); this->GraphView->SetEdgeColorArrayName("edge id"); this->GraphView->ColorEdgesOn(); // Create a tree layout strategy VTK_CREATE(vtkTreeLayoutStrategy, treeStrat); treeStrat->RadialOn(); treeStrat->SetAngle(360); treeStrat->SetLogSpacingValue(1); this->GraphView->SetLayoutStrategy(treeStrat); // Set the input to the graph view this->GraphView->SetRepresentationFromInputConnection(this->XMLReader->GetOutputPort()); // Okay now do an explicit reset camera so that // the user doesn't have to move the mouse // in the window to see the resulting graph this->GraphView->ResetCamera(); // Now hand off tree to the tree view this->TreeView->SetRepresentationFromInputConnection(this->XMLReader->GetOutputPort()); this->ColumnView->SetRepresentationFromInputConnection(this->XMLReader->GetOutputPort()); // Extract a table and give to table view VTK_CREATE(vtkDataObjectToTable, toTable); toTable->SetInputConnection(this->XMLReader->GetOutputPort()); toTable->SetFieldType(vtkDataObjectToTable::VERTEX_DATA); this->TableView->SetRepresentationFromInputConnection(toTable->GetOutputPort()); this->SetupAnnotationLink(); // Hide an unwanted column in the tree view. this->TreeView->HideColumn(2); // Turn on some colors. this->TreeView->SetColorArrayName("vertex id"); this->TreeView->ColorByArrayOn(); // Update all the views this->TreeView->Update(); this->TableView->Update(); this->ColumnView->Update(); // Force a render on the graph view this->GraphView->Render(); } void EasyView::slotExit() { qApp->exit(); }
这个Demo已经拖了好久好久了,今天整理文章的时候,发现躲不过了呀,前面的几篇都发出了。文章目录1 官方示例展示2 官方源码2.1CustomLinkView.h2.2 CustomLinkView.cpp★ 源码 ★1 官方示例展示 啊呀,今天终于更新到这里了,一直拖延症到现在,还是没有弄明白这个项目是干啥的。仅仅展示官方代码,在项目中建了对应的文件。不要给我寄刀片哈。2 官方源码2.1CustomLinkView.h#ifndef CustomLinkView_H #define CustomLinkView_H #include "vtkSmartPointer.h" // Required for smart pointer internal ivars. #include <QMainWindow> // Forward Qt class declarations class Ui_CustomLinkView; // Forward VTK class declarations class vtkCommand; class vtkEventQtSlotConnect; class vtkGraphLayoutView; class vtkObject; class vtkQtTableView; class vtkQtTreeView; class vtkXMLTreeReader; class CustomLinkView : public QMainWindow { Q_OBJECT public: // Constructor/Destructor CustomLinkView(); ~CustomLinkView() override; public slots: virtual void slotOpenXMLFile(); virtual void slotExit(); protected: protected slots: public slots: // Qt signal (produced by vtkEventQtSlotConnect) will be connected to // this slot. // Full signature of the slot could be: // MySlot(vtkObject* caller, unsigned long vtk_event, // void* clientData, void* callData, vtkCommand*) void selectionChanged(vtkObject*, unsigned long, void*, void* callData); private: // Methods void SetupCustomLink(); // Members vtkSmartPointer<vtkXMLTreeReader> XMLReader; vtkSmartPointer<vtkGraphLayoutView> GraphView; vtkSmartPointer<vtkQtTreeView> TreeView; vtkSmartPointer<vtkQtTableView> TableView; vtkSmartPointer<vtkQtTreeView> ColumnView; // This class converts a vtkEvent to QT signal. vtkSmartPointer<vtkEventQtSlotConnect> Connections; // Designer form Ui_CustomLinkView *ui; }; #endif // CustomLinkView_H 2.2 CustomLinkView.cpp#include "ui_CustomLinkView.h" #include "CustomLinkView.h" #include <vtkAnnotationLink.h> #include <vtkCommand.h> #include <vtkDataObjectToTable.h> #include <vtkDataRepresentation.h> #include <vtkEventQtSlotConnect.h> #include "vtkGenericOpenGLRenderWindow.h" #include <vtkGraphLayoutView.h> #include <vtkQtTableView.h> #include <vtkQtTreeView.h> #include <vtkRenderer.h> #include <vtkSelection.h> #include <vtkSelectionNode.h> #include <vtkTable.h> #include <vtkTableToGraph.h> #include <vtkTreeLayoutStrategy.h> #include <vtkViewTheme.h> #include <vtkViewUpdater.h> #include <vtkXMLTreeReader.h> #include <QDir> #include <QFileDialog> #include <QTreeView> #include "vtkSmartPointer.h" #define VTK_CREATE(type, name) \ vtkSmartPointer<type> name = vtkSmartPointer<type>::New() // Constructor CustomLinkView::CustomLinkView() { this->ui = new Ui_CustomLinkView; this->ui->setupUi(this); vtkNew<vtkGenericOpenGLRenderWindow> renderWindow; this->ui->vtkGraphViewWidget->SetRenderWindow(renderWindow); this->XMLReader = vtkSmartPointer<vtkXMLTreeReader>::New(); this->GraphView = vtkSmartPointer<vtkGraphLayoutView>::New(); this->TreeView = vtkSmartPointer<vtkQtTreeView>::New(); this->TableView = vtkSmartPointer<vtkQtTableView>::New(); this->ColumnView = vtkSmartPointer<vtkQtTreeView>::New(); this->ColumnView->SetUseColumnView(1); // Tell the table view to sort selections that it receives (but does // not initiate) to the top this->TableView->SetSortSelectionToTop(true); // Set widgets for the tree and table views this->ui->treeFrame->layout()->addWidget(this->TreeView->GetWidget()); this->ui->tableFrame->layout()->addWidget(this->TableView->GetWidget()); this->ui->columnFrame->layout()->addWidget(this->ColumnView->GetWidget()); // Graph View needs to get my render window this->GraphView->SetInteractor( this->ui->vtkGraphViewWidget->GetInteractor()); this->GraphView->SetRenderWindow( this->ui->vtkGraphViewWidget->GetRenderWindow()); // Set up the theme on the graph view :) vtkViewTheme* theme = vtkViewTheme::CreateNeonTheme(); this->GraphView->ApplyViewTheme(theme); theme->Delete(); // Set up action signals and slots connect(this->ui->actionOpenXMLFile, SIGNAL(triggered()), this, SLOT(slotOpenXMLFile())); connect(this->ui->actionExit, SIGNAL(triggered()), this, SLOT(slotExit())); // Apply application stylesheet QString css = "* { font: bold italic 18px \"Calibri\"; color: midnightblue }"; css += "QTreeView { font: bold italic 16px \"Calibri\"; color: midnightblue }"; //qApp->setStyleSheet(css); // Seems to cause a bug on some systems // But at least it's here as an example this->GraphView->Render(); }; // Set up the annotation between the vtk and qt views void CustomLinkView::SetupCustomLink() { this->TreeView->GetRepresentation()->SetSelectionType( vtkSelectionNode::PEDIGREEIDS); this->TableView->GetRepresentation()->SetSelectionType( vtkSelectionNode::PEDIGREEIDS); this->ColumnView->GetRepresentation()->SetSelectionType( vtkSelectionNode::PEDIGREEIDS); this->GraphView->GetRepresentation()->SetSelectionType( vtkSelectionNode::PEDIGREEIDS); // Set up the theme on the graph view :) vtkViewTheme* theme = vtkViewTheme::CreateNeonTheme(); this->GraphView->ApplyViewTheme(theme); this->GraphView->Update(); theme->Delete(); // Create vtkEventQtSlotConnect and make the connections. Connections = vtkEventQtSlotConnect::New(); // Make the connection here. // Requires vtkObject which generates the event of type // vtkCommand::SelectionChangedEvent, pointer to object // which has the given slot. vtkEvent of type SelectionChangedEvent // from reach representation should invoke selectionChanged. Connections->Connect( this->GraphView->GetRepresentation(), vtkCommand::SelectionChangedEvent, this, SLOT(selectionChanged(vtkObject*, unsigned long, void*, void*))); Connections->Connect( this->TreeView->GetRepresentation(), vtkCommand::SelectionChangedEvent, this, SLOT(selectionChanged(vtkObject*, unsigned long, void*, void*))); Connections->Connect( this->TableView->GetRepresentation(), vtkCommand::SelectionChangedEvent, this, SLOT(selectionChanged(vtkObject*, unsigned long, void*, void*))); Connections->Connect( this->ColumnView->GetRepresentation(), vtkCommand::SelectionChangedEvent, this, SLOT(selectionChanged(vtkObject*, unsigned long, void*, void*))); } CustomLinkView::~CustomLinkView() { } // Action to be taken upon graph file open void CustomLinkView::slotOpenXMLFile() { // Browse for and open the file QDir dir; // Open the text data file QString fileName = QFileDialog::getOpenFileName( this, "Select the text data file", QDir::homePath(), "XML Files (*.xml);;All Files (*.*)"); if (fileName.isNull()) { cerr << "Could not open file" << endl; return; } // Create XML reader this->XMLReader->SetFileName( fileName.toLatin1() ); this->XMLReader->ReadTagNameOff(); this->XMLReader->Update(); // Set up some hard coded parameters for the graph view this->GraphView->SetVertexLabelArrayName("id"); this->GraphView->VertexLabelVisibilityOn(); this->GraphView->SetVertexColorArrayName("VertexDegree"); this->GraphView->ColorVerticesOn(); this->GraphView->SetEdgeColorArrayName("edge id"); this->GraphView->ColorEdgesOn(); // Create a tree layout strategy VTK_CREATE(vtkTreeLayoutStrategy, treeStrat); treeStrat->RadialOn(); treeStrat->SetAngle(360); treeStrat->SetLogSpacingValue(1); this->GraphView->SetLayoutStrategy(treeStrat); // Set the input to the graph view this->GraphView->SetRepresentationFromInputConnection( this->XMLReader->GetOutputPort()); // Okay now do an explicit reset camera so that // the user doesn't have to move the mouse // in the window to see the resulting graph this->GraphView->ResetCamera(); // Now hand off tree to the tree view this->TreeView->SetRepresentationFromInputConnection( this->XMLReader->GetOutputPort()); this->ColumnView->SetRepresentationFromInputConnection( this->XMLReader->GetOutputPort()); // Extract a table and give to table view VTK_CREATE(vtkDataObjectToTable, toTable); toTable->SetInputConnection(this->XMLReader->GetOutputPort()); toTable->SetFieldType(vtkDataObjectToTable::VERTEX_DATA); this->TableView->SetRepresentationFromInputConnection( toTable->GetOutputPort()); this->SetupCustomLink(); // Hide an unwanted column in the tree view. this->TreeView->HideColumn(2); // Turn on some colors. this->TreeView->SetColorArrayName("vertex id"); this->TreeView->ColorByArrayOn(); // Update all the views this->TreeView->Update(); this->TableView->Update(); this->ColumnView->Update(); // Force a render on the graph view this->GraphView->Render(); } void CustomLinkView::slotExit() { qApp->exit(); } // This defines the QT slot. They way it works is first get the vtkSelection, // push it to the default vtkAnnotationLink associated with each // vtkDataRepresentation of each view type and then call Update or // Render (if it is a vtkRenderView) on each view. void CustomLinkView::selectionChanged(vtkObject*, unsigned long, void* vtkNotUsed(clientData), void* callData) { vtkSelection* selection = reinterpret_cast<vtkSelection*>(callData); if(selection) { this->GraphView->GetRepresentation()->GetAnnotationLink()-> SetCurrentSelection(selection); this->TreeView->GetRepresentation()->GetAnnotationLink()-> SetCurrentSelection(selection); this->TableView->GetRepresentation()->GetAnnotationLink()-> SetCurrentSelection(selection); this->ColumnView->GetRepresentation()->GetAnnotationLink()-> SetCurrentSelection(selection); this->TreeView->Update(); this->TableView->Update(); this->ColumnView->Update(); this->GraphView->Render(); } }
文章目录Qt&Vtk-CreateTree1 代码搬运1.1createtree.h1.2 createtree.cpp2 运行效果3 知识点3.1 vtkGraphLayoutView3.2 vtkViewTheme3.3 vtkTree3.4 vtkMutableDirectedGraph3.5 vtkRenderView4 其他非编译错误参考链接★ 源码 ★Qt&Vtk-CreateTree今天我又来搬运代码了。今天终于不再搬运Cone了,今天我么能来搞Tree,官方实例运行起来的是下面这个样子。鼠标点击没有啥效果,先搞起来。1 代码搬运1.1createtree.h#ifndef CREATETREE_H #define CREATETREE_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkDataSetAttributes.h" #include "vtkGraphLayoutView.h" #include "vtkMutableDirectedGraph.h" #include "vtkRandomGraphSource.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkStringArray.h" #include "vtkTree.h" #include "vtkViewTheme.h" namespace Ui { class CreateTree; } class CreateTree : public QWidget { Q_OBJECT public: explicit CreateTree(QWidget *parent = 0); ~CreateTree(); void startInteractor(); private: Ui::CreateTree *ui; vtkMutableDirectedGraph *graph = nullptr; vtkStringArray *lables = nullptr; vtkTree *tree = nullptr; vtkGraphLayoutView *view = nullptr; vtkViewTheme *theme = nullptr; }; #endif // CREATETREE_H 1.2 createtree.cpp#include "createtree.h" #include "ui_createtree.h" #include <QDebug> CreateTree::CreateTree(QWidget *parent) : QWidget(parent), ui(new Ui::CreateTree) { ui->setupUi(this); graph = vtkMutableDirectedGraph::New(); vtkIdType a = graph->AddVertex(); vtkIdType b = graph->AddChild(a); vtkIdType c = graph->AddChild(a); vtkIdType d = graph->AddChild(b); vtkIdType e = graph->AddChild(c); vtkIdType f = graph->AddChild(c); lables = vtkStringArray::New(); //标签 lables->SetName("JianweiLable"); lables->InsertValue(a,"a"); lables->InsertValue(b,"b"); lables->InsertValue(c,"c"); lables->InsertValue(d,"d"); lables->InsertValue(e,"e"); lables->InsertValue(f,"f"); graph->GetVertexData()->AddArray(lables); tree = vtkTree::New(); bool validTree = tree->CheckedShallowCopy(graph); if(!validTree) { qDebug() << "Faile"; } view = vtkGraphLayoutView::New(); view->SetRepresentationFromInput(tree); theme = vtkViewTheme::CreateMellowTheme(); theme->SetLineWidth(5); //线的宽度 theme->SetCellOpacity(0.8); //cell的透明度 theme->SetCellAlphaRange(0.5,0.5); //cell的alpha的范围 theme->SetPointSize(10); //点的大小 theme->SetSelectedCellColor(1,0,1); //选中边的颜色 theme->SetSelectedPointColor(1,0,0); //选中是点的颜色 view->ApplyViewTheme(theme); view->EdgeLabelVisibilityOn(); //标签是否可见 view->SetEdgeLabelArrayName("JianweiLable"); view->SetVertexColorArrayName("VertexDegree"); view->SetColorVertices(true); view->SetVertexLabelArrayName("JianweiLable"); view->SetVertexLabelVisibility(true); view->Update(); view->ResetCamera(); view->SetRenderWindow(ui->widget->GetRenderWindow()); } CreateTree::~CreateTree() { delete ui; } void CreateTree::startInteractor() { view->GetInteractor()->Start(); } 这里有点问题就是,我的点不知道为啥是圆的呀,不是Demo中方块。3 知识点3.1 vtkGraphLayoutView参考链接:https://blog.csdn.net/hit1524468/article/details/113443882https://vtk.org/doc/nightly/html/classvtkGraphLayoutView.html3.2 vtkViewTheme暂无理解3.3 vtkTree参考链接:https://vtk.org/doc/nightly/html/classvtkTreeRingView.html
文章目录Qt&Vtk-Cone61 代码搬运1.1 cone6.h1.2 cone6.cpp2 运行效果3 知识点3.1 vtkBoxWidget★ 源码 ★Qt&Vtk-Cone6今天我们又来搬运代码了,今天还是搞Cone,哈哈哈,已经是第六个Cone,不过这是最后一个了,还有点意思,先看看官方的例子。1 代码搬运1.1 cone6.h#ifndef CONE6_H #define CONE6_H #include <QWidget> #include <QTimer> #include <QDebug> #include <QString> #include <QTextBrowser> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkConeSource.h" #include "vtkPolyDataMapper.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkCamera.h" #include "vtkActor.h" #include "vtkCommand.h" #include "vtkBoxWidget.h" #include "vtkTransform.h" #include "vtkInteractorStyleTrackballCamera.h" namespace Ui { class Cone6; } class vtkMyCallBack : public vtkCommand { public: static vtkMyCallBack *New() { return new vtkMyCallBack; } void Execute(vtkObject *caller, unsigned long eventId, void *callData) override; }; class Cone6 : public QWidget { Q_OBJECT public: explicit Cone6(QWidget *parent = 0); ~Cone6(); void startInteractor(); private: Ui::Cone6 *ui; vtkConeSource *cone = nullptr; vtkPolyDataMapper *mapper = nullptr; vtkActor *actor = nullptr; vtkRenderer *render = nullptr; vtkRenderWindowInteractor *iren = nullptr; vtkInteractorStyleTrackballCamera * style = nullptr; vtkBoxWidget *boxWidget = nullptr; vtkMyCallBack *callback = nullptr; }; #endif // CONE6_H 1.2 cone6.cpp#include "cone6.h" #include "ui_cone6.h" Cone6::Cone6(QWidget *parent) : QWidget(parent), ui(new Ui::Cone6) { ui->setupUi(this); cone = vtkConeSource::New(); cone->SetRadius(1); cone->SetResolution(20); cone->SetHeight(3); mapper = vtkPolyDataMapper::New(); mapper->SetInputConnection(cone->GetOutputPort()); actor = vtkActor::New(); actor->SetMapper(mapper); render = vtkRenderer::New(); render->AddActor(actor); render->SetBackground(0,0,1); ui->widget->GetRenderWindow()->AddRenderer(render); iren = vtkRenderWindowInteractor::New(); iren->SetRenderWindow(ui->widget->GetRenderWindow()); style = vtkInteractorStyleTrackballCamera::New(); iren->SetInteractorStyle(style); boxWidget = vtkBoxWidget::New(); boxWidget->SetInteractor(iren); boxWidget->SetPlaceFactor(1.25); boxWidget->SetProp3D(actor); boxWidget->PlaceWidget(); callback = vtkMyCallBack::New(); boxWidget->AddObserver(vtkCommand::InteractionEvent,callback); boxWidget->On(); iren->Initialize(); } Cone6::~Cone6() { delete ui; } void Cone6::startInteractor() { iren->Start(); } void vtkMyCallBack::Execute(vtkObject *caller, unsigned long eventId, void *callData) { vtkTransform *t = vtkTransform::New(); vtkBoxWidget *widget = reinterpret_cast<vtkBoxWidget*>(caller); widget->GetTransform(t); widget->GetProp3D()->SetUserTransform(t); t->Delete(); }
文章目录Qt&Vtk-Cone51 代码搬运1 cone5.h1.2 cone5.cpp2 运行效果2.1 需要调整函数调用时机3 知识点3.1 vtkInteractorStyleTrackballCamera★ 源码 ★Qt&Vtk-Cone5这个官方示例是个迷,目前在Qt没有跑起来。主要就是用到了vtkInteractorStyleTrackballCamera这个东西。官方的是示例有没有看出啥东西来。1 代码搬运1 cone5.h#ifndef CONE5_H #define CONE5_H #include <QWidget> #include <QTimer> #include <QDebug> #include <QString> #include <QTextBrowser> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkConeSource.h" #include "vtkRenderWindowInteractor.h" #include "vtkInteractorStyleTrackballCamera.h" #include "vtkPolyDataMapper.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkActor.h" #include "vtkCamera.h" namespace Ui { class Cone5; } class Cone5 : public QWidget { Q_OBJECT public: explicit Cone5(QWidget *parent = 0); ~Cone5(); void startiren(); private: Ui::Cone5 *ui; vtkConeSource *cone = nullptr; vtkPolyDataMapper *mapper = nullptr; vtkActor *actor = nullptr; vtkRenderer *render = nullptr; vtkRenderWindowInteractor *iren = nullptr; vtkInteractorStyleTrackballCamera *style = nullptr; }; #endif // CONE5_H 1.2 cone5.cpp#include "cone5.h" #include "ui_cone5.h" Cone5::Cone5(QWidget *parent) :QWidget(parent),ui(new Ui::Cone5) { ui->setupUi(this); cone = vtkConeSource::New(); cone->SetRadius(1); cone->SetResolution(100); cone->SetHeight(5); mapper = vtkPolyDataMapper::New(); mapper->SetInputConnection(cone->GetOutputPort()); actor = vtkActor::New(); actor->SetMapper(mapper); render = vtkRenderer::New(); render->AddActor(actor); render->SetBackground(0,1,0); ui->widget->GetRenderWindow()->AddRenderer(render); iren = vtkRenderWindowInteractor::New(); iren->SetRenderWindow(ui->widget->GetRenderWindow()); style = vtkInteractorStyleTrackballCamera::New(); iren->SetInteractorStyle(style); iren->Initialize(); // iren->Start(); //在Qt中无法跑起来,这里需要看下Start的源码 /* void vtkRenderWindowInteractor::Start() { // Let the compositing handle the event loop if it wants to. if (this->HasObserver(vtkCommand::StartEvent) && !this->HandleEventLoop) { this->InvokeEvent(vtkCommand::StartEvent,nullptr); return; } // As a convenience, initialize if we aren't initialized yet. if (!this->Initialized) { this->Initialize(); if (!this->Initialized) { return; } } // Pass execution to the subclass which will run the event loop, // this will not return until TerminateApp is called. this->StartEventLoop(); } */ } Cone5::~Cone5() { delete ui; } void Cone5::startiren() { iren->Start(); } 2.1 需要调整函数调用时机在Qt下一致运行的时候,发现了个问题,就是如果我在构造函数里面调用iren->Start();话,就会有问题,程序显示启动,但是没有界面出来。所以我看了一下源码中的Start()代码如下void vtkRenderWindowInteractor::Start() { // Let the compositing handle the event loop if it wants to. if (this->HasObserver(vtkCommand::StartEvent) && !this->HandleEventLoop) { this->InvokeEvent(vtkCommand::StartEvent,nullptr); return; } // As a convenience, initialize if we aren't initialized yet. if (!this->Initialized) { this->Initialize(); if (!this->Initialized) { return; } } // Pass execution to the subclass which will run the event loop, // this will not return until TerminateApp is called. this->StartEventLoop(); }
文章目录Qt&Vtk-Arrays1 基础工作1.1 新建界面设计师类1.2 放置一个QWidget并提升为QVTKOpenGLWidget2 代码搬运2.1 marrays.h2.2 marrays.cpp3 运行效果4 涉及知识点4.1 vtkPoints4.2 vtkNamedColors4.3 vtkCellArray4.4 vtkPointData★ 源码 ★Qt&Vtk-Arrays今天我有来搬运代码了,今天搬运的是我们vtk中的***Arrays***,原来实例运行效果如下。1 基础工作1.1 新建界面设计师类由于昨天在搬运第一个实例***AmbientSpheres***的时候,我对我的工程做了小小调整,今天我可以免去前面的那些步骤,直接新建一个Qt 界面设计师类就可以,就是下图中的这个。2 代码搬运2.1 marrays.h#ifndef MARRAYS_H #define MARRAYS_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkActor.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkIntArray.h" #include "vtkNamedColors.h" #include "vtkNew.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include <array> namespace Ui { class MArrays; } class MArrays : public QWidget { Q_OBJECT public: explicit MArrays(QWidget *parent = 0); ~MArrays(); private: Ui::MArrays *ui; vtkNew<vtkNamedColors> colors; //新建颜色对象 vtkNew<vtkDoubleArray> pcoords; //新建Double数组 std::array<std::array<double,3>,4> pts = {{{{0.0, 0.0, 0.0}}, {{0.0, 1.0, 0.0}}, {{1.0, 0.0, 0.0}}, {{1.0, 1.0, 0.0}}}}; //新建Double 二维数组 vtkNew<vtkPoints> points; //新建坐标点 vtkNew<vtkCellArray> strips; //暂时不清楚 vtkNew<vtkIntArray> temperature; //暂时不了解 vtkNew<vtkDoubleArray> vorticity; //Double 数组 vtkNew<vtkPolyData> polydata; //PolyData格式的数据 vtkNew<vtkPolyDataMapper> mapper; //映射器 vtkNew<vtkActor> actor; //就是Actor vtkNew<vtkRenderer> render; //渲染 }; #endif // MARRAYS_H 2.2 marrays.cpp#include "marrays.h" #include "ui_marrays.h" #include <QDebug> MArrays::MArrays(QWidget *parent) : QWidget(parent), ui(new Ui::MArrays) { ui->setupUi(this); pcoords->SetNumberOfComponents(3); //实例中说是设置其组件数为3,默认为1,这里还不明白 pcoords->SetNumberOfTuples(4); //设置pcoords可以容纳4个Tuples数据 for (auto i = 0ul;i<pts.size();++i) { //把数据加进去 pcoords->SetTuple(i,pts[i].data()); } points->SetData(pcoords); //我理解就是数据放进这个点数组里面 strips->InsertNextCell(4); //这个干啥还不清楚 strips->InsertCellPoint(0); strips->InsertCellPoint(1); strips->InsertCellPoint(2); strips->InsertCellPoint(3); // temperature->SetName("Temperature"); //这个为啥要设置名字,咱也不懂,先撸为敬 //测试这个和颜色有关系 temperature->InsertNextValue(10); temperature->InsertNextValue(20); temperature->InsertNextValue(50); temperature->InsertNextValue(80); // vorticity->SetName("Vorticity"); //这个为啥要设置名字,咱也不懂,先撸为敬 vorticity->InsertNextValue(1.0); vorticity->InsertNextValue(1.0); vorticity->InsertNextValue(1.0); vorticity->InsertNextValue(1.0); polydata->SetPoints(points); polydata->SetStrips(strips); polydata->GetPointData()->SetScalars(temperature); //官方文档中就一句话,设置标量数据,啥是标量数据呀,咋就能修改颜色了 polydata->GetPointData()->AddArray(vorticity); mapper->SetInputData(polydata); //映射器输入数据 mapper->SetScalarRange(0,80); //又一个Scalar 也能影响颜色,这尼玛,这个好像是要区我们temperature中的区一部分吧 actor->SetMapper(mapper); // render->AddActor(actor); //添加actor render->SetBackground(colors->GetColor3d("DarkSlateGray").GetData()); //设置渲染背景 ui->widget->GetRenderWindow()->AddRenderer(render); //添加渲染器 } MArrays::~MArrays() { delete ui; } vtkCellArray这个东西,我也没有找到啥有用的内容,咱也不知道这是个啥东西。这里暂时先引用官方的描述,待后面我逐渐明白了在做补存。object to represent cell connectivityvtkCellArray stores dataset topologies as an explicit connectivity table listing the point ids that make up each cell.Internally, the connectivity table is represented as two arrays: Offsets and Connectivity.Offsets is an array of [numCells+1] values indicating the index in the Connectivity array where each cell’s points start. The last value is always the length of the Connectivity array.The Connectivity array stores the lists of point ids for each cell.4.4 vtkPointData参考链接:https://vtk.org/doc/nightly/html/classvtkPointData.html
文章目录DCMTK 3.6.6编译1 编译环境2 获取源代码3 本地文件夹配置4 CMake配置5 VS编译6 懒人必备DCMTK 3.6.6编译 又来水经验了,本帖暂无多少技术含量,主要就是编译DCMTK,后面开发可能会用到吧。下面正式开始1 编译环境 本次基本编译环境如下:操纵系统:Windows 10 专业工作站版 21H1 ed2k://|file|cn_windows_10_business_editions_version_21h1_updated_jun_2021_x64_dvd_9d9154fa.iso|5707534336|69E3B7C619BD8C09CFC2B2C19A91E13E|/DCMTK源码:DCMTK 3.6.6https://www.dcmtk.org/dcmtk.php.enCMake版本:3.21.0-rc2https://cmake.org/download/VS版本:VS2017 Communityed2k://|file|mu_visual_studio_community_2017_version_15.3_x86_x64_11100062.exe|1069960|5984B3CD547F9F213DE21EFE5887F08D|/Git:我用的是VS自动安装的Git工具2 获取源代码 登录网址:https://www.dcmtk.org/dcmtk.php.en,往下拉,找到下图位置:选择dcmtk3.6.6.zip下载。3 本地文件夹配置 每个人的习惯不同,可以根据自己习惯配置。不过总是要包含源码目录、编译目录和安装目录的我习惯还是在一个文件夹下包含三个文件夹,如下图:4 CMake配置 比起MITK VTK编译,这个要简单很多,在设置好源码目录和编译目录后,开始第一次config就可以。这里我选择的是VS2017 64位作为编译工具。需要勾选编译动态库[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CzADhTs2-1627633230454)(https://raw.githubusercontent.com/DreamLife-Jianwei/CSDNResources/master/20210730154856.png)] 修改安装目录完成上面的操作后,就可以Config了,直到没有红色没有了就生成工程了。5 VS编译 编译更是没有好说的,直接选择ALL BUILD,等待编译就可以,我这里一个错误都没有,一次过。如下:至此,编译工作完成。6 懒人必备 这里有编译好库,可以直接拿来使用https://download.csdn.net/download/z609932088/20645417?spm=1001.2014.3001.5501
文章目录Qt&Vtk-AmbientSpheres1 效果展示2源码2.1 ambientspheres.h2.2 ambientspheres.cpp3 涉及主要知识点3.1 vtkCamera3.2 vtkLight3.3 vtkPolyDataMapper3.4 vtkActor3.5 vtkRenderWindow3.6 vtkRenderer★ 源码 ★Qt&Vtk-AmbientSpheres 从本章开始,将开始搬运官方实例代码,顺便开始学习,能理解多少算多少。1 效果展示 今天搬运第一个Vtk官方示例***AmbientSpheres***,如下图2源码 下面看下源代码,这次分别写在了头文件中和源文件中。2.1 ambientspheres.h#ifndef AMBIENTSPHERES_H #define AMBIENTSPHERES_H #include <QWidget> #include "QVTKOpenGLWidget.h" //新版本,旧版QVTKWidget #include "vtkAutoInit.h" #include "vtkSmartPointer.h" #include "vtkSphereSource.h" #include "vtkPolyDataMapper.h" #include "vtkActor.h" #include "vtkRenderer.h" #include "vtkRenderWindow.h" #include "vtkProperty.h" #include "vtkCamera.h" #include "vtkLight.h" namespace Ui { class AmbientSpheres; } class AmbientSpheres : public QWidget { Q_OBJECT public: explicit AmbientSpheres(QWidget *parent = 0); ~AmbientSpheres(); private: Ui::AmbientSpheres *ui; vtkSmartPointer<vtkSphereSource> sphere = nullptr; vtkSmartPointer<vtkPolyDataMapper> sphereMapper = nullptr; vtkSmartPointer<vtkActor> sphere1 = nullptr, sphere2 = nullptr, sphere3 = nullptr, sphere4 = nullptr, sphere5 = nullptr, sphere6 = nullptr, sphere7 = nullptr, sphere8 = nullptr; vtkSmartPointer<vtkRenderer> renderer = nullptr; vtkSmartPointer<vtkLight> light = nullptr; }; #endif // AMBIENTSPHERES_H 2.2 ambientspheres.cpp#include "ambientspheres.h" #include "ui_ambientspheres.h" #include <QDebug> /** * @brief AmbientSpheres::AmbientSpheres * @param parent * 照搬官方实例,有道翻译官方文件中内容如下 * This examples demonstrates the effect of specular lighting. * 这个例子演示了镜面照明的效果。 * 专业名词后面慢慢学习,代码先撸起来 */ AmbientSpheres::AmbientSpheres(QWidget *parent) :QWidget(parent),ui(new Ui::AmbientSpheres) { ui->setupUi(this); //创建一个球体 sphere = vtkSmartPointer<vtkSphereSource>::New(); sphere->SetThetaResolution(100); sphere->SetPhiResolution(50); //创建一个映射器 sphereMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); sphereMapper->SetInputConnection(sphere->GetOutputPort()); //创建8个小球 sphere1 = vtkSmartPointer<vtkActor>::New(); sphere2 = vtkSmartPointer<vtkActor>::New(); sphere3 = vtkSmartPointer<vtkActor>::New(); sphere4 = vtkSmartPointer<vtkActor>::New(); sphere5 = vtkSmartPointer<vtkActor>::New(); sphere6 = vtkSmartPointer<vtkActor>::New(); sphere7 = vtkSmartPointer<vtkActor>::New(); sphere8 = vtkSmartPointer<vtkActor>::New(); sphere1->SetMapper(sphereMapper); sphere1->GetProperty()->SetColor(1,0,0); //颜色 sphere1->GetProperty()->SetAmbient(0.125); //环境光系数 sphere1->GetProperty()->SetDiffuse(0.0); //漫反射光系数 sphere1->GetProperty()->SetSpecular(0.0); //镜面反射系数 //镜面系数SetSpecularPower() sphere2->SetMapper(sphereMapper); sphere2->GetProperty()->SetColor(1,0,1); sphere2->GetProperty()->SetAmbient(0.25); sphere2->GetProperty()->SetDiffuse(0.0); sphere2->GetProperty()->SetSpecular(0.0); sphere2->AddPosition(1.25,0,0); sphere3->SetMapper(sphereMapper); sphere3->GetProperty()->SetColor(1,0.1,0); sphere3->GetProperty()->SetAmbient(0.375); sphere3->GetProperty()->SetDiffuse(0.0); sphere3->GetProperty()->SetSpecular(0.0); sphere3->AddPosition(2.5,0,0); sphere4->SetMapper(sphereMapper); sphere4->GetProperty()->SetColor(1,0,0); sphere4->GetProperty()->SetAmbient(0.5); sphere4->GetProperty()->SetDiffuse(0.0); sphere4->GetProperty()->SetSpecular(0.0); sphere4->AddPosition(3.75,0,0); sphere5->SetMapper(sphereMapper); sphere5->GetProperty()->SetColor(1,0,0); sphere5->GetProperty()->SetAmbient(0.625); sphere5->GetProperty()->SetDiffuse(0.0); sphere5->GetProperty()->SetSpecular(0.0); sphere5->AddPosition(0.0,1.25,0); sphere6->SetMapper(sphereMapper); sphere6->GetProperty()->SetColor(1,0,0); sphere6->GetProperty()->SetAmbient(0.75); sphere6->GetProperty()->SetDiffuse(0.0); sphere6->GetProperty()->SetSpecular(0.0); sphere6->AddPosition(1.25,1.25,0); sphere7->SetMapper(sphereMapper); sphere7->GetProperty()->SetColor(1,0,0); sphere7->GetProperty()->SetAmbient(0.875); sphere7->GetProperty()->SetDiffuse(0.0); sphere7->GetProperty()->SetSpecular(0.0); sphere7->AddPosition(2.5,1.25,0); sphere8->SetMapper(sphereMapper); sphere8->GetProperty()->SetColor(1,0,0); sphere8->GetProperty()->SetAmbient(1.0); sphere8->GetProperty()->SetDiffuse(0.0); sphere8->GetProperty()->SetSpecular(0.0); sphere8->AddPosition(3.75,1.25,0); renderer = vtkSmartPointer<vtkRenderer>::New(); //窗口渲染器 renderer->AddActor(sphere1); renderer->AddActor(sphere2); renderer->AddActor(sphere3); renderer->AddActor(sphere4); renderer->AddActor(sphere5); renderer->AddActor(sphere6); renderer->AddActor(sphere7); renderer->AddActor(sphere8); renderer->SetBackground(0.1,0.2,0.4); //设置背景颜色 ui->widget->GetRenderWindow()->AddRenderer(renderer); // light = vtkSmartPointer<vtkLight>::New(); //创建光照 light->SetFocalPoint(1.875,0.6125,0); //设置灯光焦点 light->SetPosition(0.875,1.6125,1); //设置灯光位置 //设置灯光强度SetIntensity() //设置灯光锥角SetConeAngle() //选择设置平行光或者聚光PositionalOff/On() renderer->AddLight(light); renderer->GetActiveCamera()->SetFocalPoint(0,0,0); //设置相机焦点 renderer->GetActiveCamera()->SetPosition(0,0,1); //设置相机位置 renderer->GetActiveCamera()->SetViewUp(0,1,0); //设置图像正方向 renderer->GetActiveCamera()->ParallelProjectionOn(); //平行投影/透视投影 renderer->ResetCamera(); renderer->GetActiveCamera()->SetParallelScale(4.0); } AmbientSpheres::~AmbientSpheres() { delete ui; } 3 涉及主要知识点3.1 vtkCamera参考链接: https://vtk.org/doc/release/5.2/html/a00154.htmlhttps://blog.csdn.net/wzheng92/article/details/79935059https://blog.csdn.net/colddie/article/details/16948231
文章目录ITK 5.2.0编译1 编译环境2 获取源代码3 配置CMake3.1 在BUILD选择编译示例和动态库3.2 CMAKE下修改文件生成路径3.3 ITK配置3.4 Module配置3.5 再次Config3.6 再次Config3.7 Generate4 VS2017编译4.1 打开项目4.2 编译所有4.3 把相关文件移动到Bin目录中5 库文件博客签名2021ITK 5.2.0编译 为什么要编译ITK,不是闲的没事干了,是因为我在前面挖的坑,在使用VTK示例实现四视图的时候,发现图像是方向不对,开始一度怀疑是自己傻逼,尼玛抄代码都能抄出问题了,等我编译了官方原版的Demo后,发现原版也是错误的。而我又没有能力定位问题出在哪里了,所以只能问度娘,基本反馈就是VKT的DICOM模块只能读个基础的最标准的单个DICOM文件。甭指望它有多牛逼,要想完全解析DICOM,还得找一点专业的东西,其实还有两个更好的,和面在搞。今天先尝试下ITK是否能解决我的问题,哎,自己玩真的是很麻烦,跟无头苍蝇一样,一点方向也没有呀。1 编译环境 本次ITK编译使用VS2017作为主要编译工具,详细信息如下:操纵系统:Windows 10 专业工作站版 21H1 ed2k://|file|cn_windows_10_business_editions_version_21h1_updated_jun_2021_x64_dvd_9d9154fa.iso|5707534336|69E3B7C619BD8C09CFC2B2C19A91E13E|/ITK源码:ITK 5.2.0https://itk.org/download/CMake版本:3.21.0-rc2https://cmake.org/download/VS版本:VS2017 Communityed2k://|file|mu_visual_studio_community_2017_version_15.3_x86_x64_11100062.exe|1069960|5984B3CD547F9F213DE21EFE5887F08D|/Git:我用的是VS自动安装的Git工具2 获取源代码 直接从官网下载最新的ITK源码,https://itk.org/download/,我选择了最新的5.2.0版本。在本地建立ITK文件夹,在分别建立Bin和Build子文件夹。将下载好的ITK源码解压到ITK目录下,这样在ITK目录下就有三个目录了Bin:存放编译好的文件Build:存放编译文件InsightToolkit-5.2.0:源代码3 配置CMake 配置CMake最基础的就是配置源码路径、编译路径和选择分组显示,后面的Advanced勾选后可以看到更多的选项,如下图所示。在完成基本的配置后,就可以进行第一次Config了,第一Config需要选择编译器和编译版本 32/64等。3.1 在BUILD选择编译示例和动态库 再次Config后会有上图提示,确认一下没有问题,就可以在再次Config了。3.6 再次Config Config完成后,当没有红色后,就可以进行生成工程操作了。3.7 Generate Generate完成后,会在下面的信息中显示,如下图所示。这时就可以到VS中进行编译了。希望一切顺利。4 VS2017编译 正常可以点击生成按钮右边的打开工程那妞,但是针对电脑有多个VS环境的情况,建议还是在VS中手动打开比较好,不然有可能存在使用了非指定版本的VS打开。
文章目录MITK2021.2编译接受来自全国人民的点赞1 最终编译环境2 下载MITK源代码2.1 从Git下载代码2.2 存放位置3 CMake配置4 编译4.1 C4819警告5 体会MITK2021.2编译参考链接:https://blog.csdn.net/calmreason/article/details/90741241重要参考链接:https://www.cnblogs.com/shHome/p/14512199.html 为什么要编译MITK,因为公司目前的项目就是一MITK为模版改的的,领导说后面我们要用Qt和VTK来重新搞一遍,这个对于有经验的老司机来说,应该是没有太多难度的,但是我没有呀,我来这公司之前都没有接触过医疗,连VTK啥都不知道,感谢公司给我机会让我带薪学习。这也就是为啥要编译了,因为我准备抄袭,哈哈哈。接受来自全国人民的点赞 本次MITK编译主要耗时3天,整体战线有20天吧。终于成功了,我特意截图嘚瑟一下。还激动的给媳妇发了200红包,哎,私房钱又少200。为啥激动,因为太尼玛难编译了,而且好多问题出的都是无从下手的那种问题。更加主要的,直属领导是个兼职,除了周一例会和突发事件,基本不来公司,再说这种编译问题去问领导,是不是傻逼了;只能自己摸索。1 最终编译环境 为啥是最终编译环境呢,看下图,为了编译它,我换了三个版本的Qt和三个版本的VS,都是泪呀。还有一个更气人的就是公司的破电脑,都尼玛2021年了,还没有固态硬盘,每次打开VS死的心都有,就是你去上个厕所,回来硬盘等还是常亮。要不是对工作满满的热爱,真想炸了它。这里要特别说一下,编译的时候一定要保证网路畅通,能上Git2 下载MITK源代码 直接百度MITK,进入官网https://www.mitk.org/wiki/The_Medical_Imaging_Interaction_Toolkit_(MITK)2.1 从Git下载代码 开始进入有点陌生,为了保证咱们说的一个东西,还是点一下右侧我红框标出来的,点击MITK v2021.02进入到下载界面,为了保证我们后面编译顺畅,还是建议下载win版本的。2.2 存放位置 网上有专家说了,MITK编译目录放的太深的话,CMake直接会报路径太长错误,所以直接放C盘更目录。就是下面这样 文件夹里面是这个样子,分别用来放编译好的文件,编译文件和源码。3 CMake配置前置声明 这里还是要做点工作,以防后面出现好多乱七八糟的错误。在MITK源码目录下,有一个CMakeExternals文件夹,进到这个目录里面。把里面所有**.patch的文件改为CR LF** CMake配置基本就是默认配置,如果找不到Qt的路径,那就手动配置一下,剩下的就是默认就好了,没有晚上说的那些需要更改文件内容,主要就是取消编译实例,指定安装路径。4 编译 编译没有啥好说的,使用VS2017 打开MITK-superbuild.sln,—> 选择Release 64位 —>选择ALL_BUILD—>生成。准备迎接错误吧。4.1 C4819警告 按照大神说法,C4819是优先解决警告,正常情况下,解决完成C4819编译也就完成了。具体方法也很简单打开报警告的文件CTRL + A 全选,高级保存选项,选择编码和尾行格式保存文件高级保存选项:https://blog.csdn.net/willingtolove/article/details/1037724065 体会 现在真的要写些东西了,才发现好多东西不用写,也没得西戎;因为更多的是摸索的过程,好多坑也没有记录。其实在编译的过程中,遇到好多问题,C2220、MSB600系列、LNK系列等好多。换Qt版本,换VS版本,换MITK源码,单独编译VTK、ITK、Eigen及不下10次的编译失败,真的不想编译了,好在最后还是咬牙搞出来了,后面主力还是搞VTK。
文章目录Qt&Vtk 显示Jpg、Png、Tiff、Dicom、Bmp及3DCube1 简单介绍2 使用QVTKWidget3 功能实现3.1 JPG图片实现3.2 PNG图片实现3.3 BMP图片实现3.4 TIFF图片实现3.5 DICOM图片实现3.6 3D Cube实现4 关闭VTK调试窗口5 源码Qt&Vtk 显示Jpg、Png、Tiff、Dicom、Bmp及3DCube本文其实才能算是真正的Qt与Vtk结合,具体实现JPG、PNG、TIFF、DICOM、BMP及一个3D Cube显示。程序实际运行效果如下:1 简单介绍本文主要将在Qt中借助QvtkWidget来实现在Qt窗口中实现显示Jpg、Png、Tiff、Dicom、Bmp及3DCube等文件。如下图所示2 使用QVTKWidget在我们编译完成Vtk后,把***Bin\plugins\designer***下的***QVTKWidgetPlugin.dll***复制到Qt安装目录下的***Qt5.7.1\5.7\msvc2015_64\plugins\designer***,如下图所示但是在Qt Creator中是无法使用的。碰巧了,我还不会用Designer。在Qt Creator不是不能用了,我们可以通过提升控件的方式来搞。如下图,我使用了8个widget来提升成QVTKwidget。到这里,基本就可以完事了,可以真正去写后面的功能了3 功能实现3.1 JPG图片实现直接看代码吧,大致原理就是读取文件,建立渲染对象,选着窗口进行渲染。后面其他类型的图片也是这个套路。主要看代码吧,注释尽量忽略,我也不太懂图形学,都是按照自己的理解写的,凑合看。void MainWindow::renderJpegImage(int index, const char *temp) { /** * @brief 读取本地图片 * 1. 获取本地资源地址 * 2. 新建渲染对象 * 3. 设置图像名称 * 4. 更新 */ vtkSmartPointer<vtkJPEGReader> render = vtkSmartPointer<vtkJPEGReader>::New(); render -> SetFileName(temp); render -> Update(); /** * @brief 设置图片视图 * 1. 新建视图 * 2. 设置视图输入 * 3. 设置视图窗口 * 4. 视图渲染 */ vtkSmartPointer<vtkImageViewer2> viewer = vtkSmartPointer<vtkImageViewer2>::New(); viewer -> SetInputData(render -> GetOutput()); switch (index) { case 1: viewer -> SetRenderWindow(ui->widget_VTK_1->GetRenderWindow()); break; case 2: viewer -> SetRenderWindow(ui->widget_VTK_2->GetRenderWindow()); break; case 3: viewer -> SetRenderWindow(ui->widget_VTK_3->GetRenderWindow()); break; case 4: viewer -> SetRenderWindow(ui->widget_VTK_4->GetRenderWindow()); break; case 5: viewer -> SetRenderWindow(ui->widget_VTK_5->GetRenderWindow()); break; case 6: viewer -> SetRenderWindow(ui->widget_VTK_6->GetRenderWindow()); break; case 7: viewer -> SetRenderWindow(ui->widget_VTK_7->GetRenderWindow()); break; case 8: viewer -> SetRenderWindow(ui->widget_VTK_8->GetRenderWindow()); break; default: break; } viewer -> Render(); } 3.2 PNG图片实现void MainWindow::renderPngImage(int index, const char *temp) { /** * @brief 读取本地图片 * 1. 获取本地资源地址 * 2. 新建渲染对象 * 3. 设置图像名称 * 4. 更新 */ vtkSmartPointer<vtkPNGReader> render = vtkSmartPointer<vtkPNGReader>::New(); render -> SetFileName(temp); render -> Update(); /** * @brief 设置图片视图 * 1. 新建视图 * 2. 设置视图输入 * 3. 设置视图窗口 * 4. 视图渲染 */ vtkSmartPointer<vtkImageViewer2> viewer = vtkSmartPointer<vtkImageViewer2>::New(); viewer -> SetInputData(render -> GetOutput()); switch (index) { case 1: viewer -> SetRenderWindow(ui->widget_VTK_1->GetRenderWindow()); break; case 2: viewer -> SetRenderWindow(ui->widget_VTK_2->GetRenderWindow()); break; case 3: viewer -> SetRenderWindow(ui->widget_VTK_3->GetRenderWindow()); break; case 4: viewer -> SetRenderWindow(ui->widget_VTK_4->GetRenderWindow()); break; case 5: viewer -> SetRenderWindow(ui->widget_VTK_5->GetRenderWindow()); break; case 6: viewer -> SetRenderWindow(ui->widget_VTK_6->GetRenderWindow()); break; case 7: viewer -> SetRenderWindow(ui->widget_VTK_7->GetRenderWindow()); break; case 8: viewer -> SetRenderWindow(ui->widget_VTK_8->GetRenderWindow()); break; default: break; } viewer -> Render(); } 3.3 BMP图片实现void MainWindow::renderBmprImage(int index, const char *temp) { /** * @brief 读取本地图片 * 1. 获取本地资源地址 * 2. 新建渲染对象 * 3. 设置图像名称 * 4. 更新 */ vtkSmartPointer<vtkBMPReader> render = vtkSmartPointer<vtkBMPReader>::New(); render -> SetFileName(temp); render -> Update(); /** * @brief 设置图片视图 * 1. 新建视图 * 2. 设置视图输入 * 3. 设置视图窗口 * 4. 视图渲染 */ vtkSmartPointer<vtkImageViewer2> viewer = vtkSmartPointer<vtkImageViewer2>::New(); viewer -> SetInputData(render -> GetOutput()); switch (index) { case 1: viewer -> SetRenderWindow(ui->widget_VTK_1->GetRenderWindow()); break; case 2: viewer -> SetRenderWindow(ui->widget_VTK_2->GetRenderWindow()); break; case 3: viewer -> SetRenderWindow(ui->widget_VTK_3->GetRenderWindow()); break; case 4: viewer -> SetRenderWindow(ui->widget_VTK_4->GetRenderWindow()); break; case 5: viewer -> SetRenderWindow(ui->widget_VTK_5->GetRenderWindow()); break; case 6: viewer -> SetRenderWindow(ui->widget_VTK_6->GetRenderWindow()); break; case 7: viewer -> SetRenderWindow(ui->widget_VTK_7->GetRenderWindow()); break; case 8: viewer -> SetRenderWindow(ui->widget_VTK_8->GetRenderWindow()); break; default: break; } viewer -> Render(); } 3.4 TIFF图片实现void MainWindow::renderTiffImage(int index, const char *temp) { /** * @brief 读取本地图片 * 1. 获取本地资源地址 * 2. 新建渲染对象 * 3. 设置图像名称 * 4. 更新 */ vtkSmartPointer<vtkTIFFReader> render = vtkSmartPointer<vtkTIFFReader>::New(); render -> SetFileName(temp); render -> Update(); /** * @brief 设置图片视图 * 1. 新建视图 * 2. 设置视图输入 * 3. 设置视图窗口 * 4. 视图渲染 */ vtkSmartPointer<vtkImageViewer2> viewer = vtkSmartPointer<vtkImageViewer2>::New(); viewer -> SetInputData(render -> GetOutput()); switch (index) { case 1: viewer -> SetRenderWindow(ui->widget_VTK_1->GetRenderWindow()); break; case 2: viewer -> SetRenderWindow(ui->widget_VTK_2->GetRenderWindow()); break; case 3: viewer -> SetRenderWindow(ui->widget_VTK_3->GetRenderWindow()); break; case 4: viewer -> SetRenderWindow(ui->widget_VTK_4->GetRenderWindow()); break; case 5: viewer -> SetRenderWindow(ui->widget_VTK_5->GetRenderWindow()); break; case 6: viewer -> SetRenderWindow(ui->widget_VTK_6->GetRenderWindow()); break; case 7: viewer -> SetRenderWindow(ui->widget_VTK_7->GetRenderWindow()); break; case 8: viewer -> SetRenderWindow(ui->widget_VTK_8->GetRenderWindow()); break; default: break; } viewer -> Render(); } 3.5 DICOM图片实现void MainWindow::renderDicomImage(int index, const char *temp) { /** * @brief 读取本地图片 * 1. 获取本地资源地址 * 2. 新建渲染对象 * 3. 设置图像名称 * 4. 更新 */ vtkSmartPointer<vtkDICOMImageReader> render = vtkSmartPointer<vtkDICOMImageReader>::New(); render -> SetFileName(temp); render -> Update(); /** * @brief 设置图片视图 * 1. 新建视图 * 2. 设置视图输入 * 3. 设置视图窗口 * 4. 视图渲染 */ vtkSmartPointer<vtkImageViewer2> viewer = vtkSmartPointer<vtkImageViewer2>::New(); viewer -> SetInputData(render -> GetOutput()); switch (index) { case 1: viewer -> SetRenderWindow(ui->widget_VTK_1->GetRenderWindow()); break; case 2: viewer -> SetRenderWindow(ui->widget_VTK_2->GetRenderWindow()); break; case 3: viewer -> SetRenderWindow(ui->widget_VTK_3->GetRenderWindow()); break; case 4: viewer -> SetRenderWindow(ui->widget_VTK_4->GetRenderWindow()); break; case 5: viewer -> SetRenderWindow(ui->widget_VTK_5->GetRenderWindow()); break; case 6: viewer -> SetRenderWindow(ui->widget_VTK_6->GetRenderWindow()); break; case 7: viewer -> SetRenderWindow(ui->widget_VTK_7->GetRenderWindow()); break; case 8: viewer -> SetRenderWindow(ui->widget_VTK_8->GetRenderWindow()); break; default: break; } viewer -> Render(); } 3.6 3D Cube实现Cube基本就是照抄了官方的Demovoid MainWindow::drawVtkCube(int index) { vtkNew <vtkNamedColors> colors; std::array<std::array<double, 3>, 8> pts = {{{{0, 0, 0}}, {{0.2, 0, 0}}, {{0.2, 0.2, 0}}, {{0, 0.2, 0}}, {{0, 0, 0.2}}, {{0.2, 0, 0.2}}, {{0.2, 0.2, 0.2}}, {{0, 0.2, 0.2}}}}; std::array<std::array<vtkIdType,4>,6> ording = {{{{0, 1, 2, 3}}, {{4, 5, 6, 7}}, {{0, 1, 5, 4}}, {{1, 2, 6, 5}}, {{2, 3, 7, 6}}, {{3, 0, 4, 7}}}}; vtkNew <vtkPolyData> cube; vtkNew <vtkPoints> points; vtkNew <vtkCellArray> polys; vtkNew <vtkFloatArray> scalars; for (auto i = 0ul;i < pts.size();++i) { points -> InsertPoint(i,pts[i].data()); scalars -> InsertTuple1(i,i); } for (auto &&i : ording) polys -> InsertNextCell(vtkIdType(i.size()),i.data()); cube -> SetPoints(points); cube -> SetPolys(polys); cube -> GetPointData() -> SetScalars(scalars); vtkNew<vtkPolyDataMapper> cubeMapper; cubeMapper->SetInputData(cube); cubeMapper->SetScalarRange(cube->GetScalarRange()); vtkNew<vtkActor> cubeActor; cubeActor->SetMapper(cubeMapper); vtkNew<vtkCamera> camera; camera->SetPosition(1, 1, 1); camera->SetFocalPoint(0, 0, 0); vtkNew<vtkRenderer> render; render -> AddActor(cubeActor); render -> SetActiveCamera(camera); render -> SetBackground(colors -> GetColor3d("Cornsilk").GetData()); ui->widget_VTK_6->GetRenderWindow()->AddRenderer(render); } 关闭VTK调试窗口这里有小伙伴在运行的时候,可以能会发如下图的调试窗口存在
文章目录Qt Qml 下使用QtCharts1.1 引入文档1.2 在pro中包含 charts1.3 运行官方例子1.4 修改main文件1.5 手动拷贝 相关文件Qt Qml 下使用QtCharts先说场景,项目中需要用到QtCharts,所以就得搞一下了,最简单的方式还是直接看Qt的帮助文档。1.1 引入文档根据帮助文档显示,我们只需要引入对应的包就可以了,在项目中引入QtCharts模块,如下import QtCharts 2.14 但是呢,如果仅仅是按照文档中那样,是不性的,这是我第一次引入后的编译的结果。1.2 在pro中包含 charts在pro文件中加入charts,如下QT += quick core network widgets charts 这个时候你就要开始怀疑你Qt是不是安装有问题了,因为QtCharts模块确实是需要你在安装的时候选择安装的,不过一般都是全选安装,不会是这个原因。1.3 运行官方例子我们找一个官方的实例看一下,是没有问题的,那么我们的出在哪里了。1.4 修改main文件对比我们就可以发现有问题,如下修改我们的文件,把QGuiApplication替换为QApplication,至于为什么,可以百度。1.5 手动拷贝 相关文件完成上面的内容后,我们再次编译,你会发现,还有问题,还是报没有安装问题,但是我们运行官网demo是没有问题的,那证明我们是安装了QtCharts模块的。到这里,我也没有办法了,真的是想不到原因出来哪里,不过还好有万能的百度,我找的下面这个文章,链接在这里:https://blog.csdn.net/my393661/article/details/104892689关键信息如下:
文章目录1 效果2 关键内容2.1 显示时间2.2 隐藏标题栏2.3 隐藏标题栏可拖动3 全部代码1 效果今天闲来无事,来搞搞最近比较火的 华为太空人仪表盘 效果如下:2 关键内容2.1 显示时间onSceneGraphInitialized: { mTimer.start(); } property string peopleurl : "qrc:/people/Image/human (" property int peopleindex : 2; Timer { id:mTimer repeat: true interval: 25 onTriggered: { peopleindex = peopleindex + 1 if(peopleindex === 61) { peopleindex = 2 } mPeople.source = peopleurl + peopleindex + ").jpg" mTime.text = Qt.formatDateTime(new Date(),"hh:mm") mTimess.text = Qt.formatDateTime(new Date(),"ss") } } Text { id: mTime y:120 x:90 text: Qt.formatDateTime(new Date(),"hh:mm") font.family: "DigifaceWide" font.letterSpacing: -5 font.weight: Font.Light font.pointSize: 60 } Text { id: mTimess anchors.bottom: mTime.bottom anchors.bottomMargin: 10 anchors.left: mTime.right anchors.leftMargin: 5 text: Qt.formatDateTime(new Date(),"ss") font.family: "DigifaceWide" font.letterSpacing: -2 font.weight: Font.Light font.pointSize: 26 } Text { id: mYear x:340 y:285 text: Qt.formatDateTime(new Date(),"dddd\r\nMM-dd") font.family: "黑体" font.weight: Font.Light font.pointSize: 15 } 显示时间主要是定时器,每25毫秒获取一次。2.2 隐藏标题栏flags: Qt.FramelessWindowHint | Qt.Window隐藏标题栏就这一句代码,注意后面的Qt.Window,这个是让程序在隐藏标题栏后依附任务栏的,不需要的可以去掉。2.3 隐藏标题栏可拖动MouseArea { anchors.fill: parent property int m_x : 0; property int m_y : 0; onPressed: { m_x = mouse.x; m_y = mouse.y; } onPositionChanged: { /* 实现窗口拖船,移动 */ root.x = root.x + mouse.x - m_x root.y = root.y + mouse.y - m_y } } 这个没啥可以说的,比Qwidget下简单多了3 全部代码import QtQuick 2.12 import QtQuick.Window 2.12 Window { id:root visible: true width: 480 height: 480 flags: Qt.FramelessWindowHint | Qt.Window color: "transparent" Image { id: back source: "qrc:/image/Image/back.png" } Image { id: mPeople x:186 y:213 width: 108 height: 120 source: "qrc:/people/Image/human (2).jpg" } onSceneGraphInitialized: { mTimer.start(); } property string peopleurl : "qrc:/people/Image/human (" property int peopleindex : 2; Timer { id:mTimer repeat: true interval: 25 onTriggered: { peopleindex = peopleindex + 1 if(peopleindex === 61) { peopleindex = 2 } mPeople.source = peopleurl + peopleindex + ").jpg" mTime.text = Qt.formatDateTime(new Date(),"hh:mm") mTimess.text = Qt.formatDateTime(new Date(),"ss") } } Text { id: mTime y:120 x:90 text: Qt.formatDateTime(new Date(),"hh:mm") font.family: "DigifaceWide" font.letterSpacing: -5 font.weight: Font.Light font.pointSize: 60 } Text { id: mTimess anchors.bottom: mTime.bottom anchors.bottomMargin: 10 anchors.left: mTime.right anchors.leftMargin: 5 text: Qt.formatDateTime(new Date(),"ss") font.family: "DigifaceWide" font.letterSpacing: -2 font.weight: Font.Light font.pointSize: 26 } Text { id: mYear x:340 y:285 text: Qt.formatDateTime(new Date(),"dddd\r\nMM-dd") font.family: "黑体" font.weight: Font.Light font.pointSize: 15 } Text { id: mHeart x:118 y:326 text:"93" font.family: "黑体" font.weight: Font.Light font.pointSize: 18 } Text { id: mHeartHL x:75 y:300 text:"66-123" font.family: "黑体" font.weight: Font.Light font.pointSize: 14 } Text { id: mHFoot x:340 y:328 text:"8869" font.family: "黑体" font.weight: Font.Light font.pointSize: 18 } Text { id: mSleep x:180 y:368 font.bold: true font.wordSpacing: 10 font.letterSpacing: 1 text:"8h36m" font.family: "黑体" font.weight: Font.Light font.pointSize: 18 } Text { id: mDistance x:200 y:410 font.bold: true font.wordSpacing: 10 font.letterSpacing: 1 text:"9.36Km" font.family: "黑体" font.weight: Font.Light font.pointSize: 18 } Text { id: mAir x:215 y:50 font.bold: true text:"空气优质" font.family: "黑体" font.weight: Font.Light font.pointSize: 12 } Text { id: mWeather anchors.left: mAir.left anchors.top: mAir.bottom anchors.topMargin: 5 font.bold: true text:"晴天" font.family: "黑体" font.weight: Font.Light font.pointSize: 12 } Image { id: mWeatherpic x:318 y:75 width: 40 height: 40 source: "qrc:/image/Image/other2.png" } Text { id: mTemperatureH x:260 y:72 font.bold: true text:"26℃" font.family: "黑体" font.weight: Font.Light font.pointSize: 12 } Text { id: mTemperatureL x:260 y:95 font.bold: true text:"17℃" font.family: "黑体" font.weight: Font.Light font.pointSize: 12 } Text { id: mTemperatureCurrent anchors.left: mWeather.left anchors.bottom: mTemperatureL.bottom font.bold: true text:"22℃" font.family: "黑体" font.weight: Font.Light font.pointSize: 12 } Text { id: mRocket x:120 y:85 font.bold: true text:"88%" font.family: "黑体" font.weight: Font.Normal font.pointSize: 20 } MouseArea { anchors.fill: parent property int m_x : 0; property int m_y : 0; onPressed: { m_x = mouse.x; m_y = mouse.y; } onPositionChanged: { /* 实现窗口拖船,移动 */ root.x = root.x + mouse.x - m_x root.y = root.y + mouse.y - m_y } } }
文章目录1 需求背景2 解决方法2.1 注意事项一2.2 注意事项二3 效果1 需求背景本次项目计划成为一个较为正式版本的程序,参考大公司的程序信息如下图所示,这么对比下来,一下显示我们的软件是小制作方生产数来的了,所以决定研究一下,给我们的程序也加上详细信息。。2 解决方法参考资料:https://blog.csdn.net/zuoweijie_/article/details/100063965按照前辈慢的分享,开干就可以新建一个文件DataSeerverInfo.rc,填充内容如下#if defined(UNDER_CE) #include <winbase.h> #else #include <winver.h> #endif VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "080404b0" BEGIN VALUE "CompanyName", "BeiJing NewJJ Co., Ltd." VALUE "FileDescription", "数据服务器\0" VALUE "FileVersion", "1.0.0.0" VALUE "InternalName", "DataServer.exe" VALUE "LegalCopyright", "Copyright (C)2021-2023" VALUE "OriginalFilename", "DataServer.exe" VALUE "ProductName", "DataServer" VALUE "ProductVersion", "1.0.0.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x804, 1200 END END 在pro文件中加入RC_FILE += DataSeerverInfo.rc ,如下图所示2.1 注意事项一在新版本的Qt中,如果仅仅是给程序添加图标,仅需要在pro文件加入代码RC_ICONS = ./Images/logo.ico,如果这时我们引入了我们的文件后会使这个失效,需要把在这个实现也放到我们的文件中,如下:#if defined(UNDER_CE) #include <winbase.h> #else #include <winver.h> #endif IDI_ICON1 ICON DISCARDABLE "./Images/logo.ico" VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,0 PRODUCTVERSION 1,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "080404b0" BEGIN VALUE "CompanyName", "BeiJing NewJJ Co., Ltd." VALUE "FileDescription", "数据服务器\0" VALUE "FileVersion", "1.0.0.0" VALUE "InternalName", "DataServer.exe" VALUE "LegalCopyright", "Copyright (C)2021-2023" VALUE "OriginalFilename", "DataServer.exe" VALUE "ProductName", "DataServer" VALUE "ProductVersion", "1.0.0.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x804, 1200 END END 2.2 注意事项二如果我们正在文件中有中文,例如我的文件描述为“数据服务器”,那么需要更改我们的编码格式为ANSI即可,默认可能是UTF-83 效果效果那肯定是杠杠的,如下
1 需求背景还是原来的网络关机助手项目“PowerControl”,目前他有了一个新的运行环境,就是在我们的某个带有电脑的显示设备上面,可以理解为带有触摸功能的一体机,本来原生设计是无法触发这个需求的,但是由于信号的干扰没有很好的解决,导致整个屏幕下沉,屏幕的四周没法触摸,这就导致了Windows无法关机,也无法打开系统托盘。所以,关机就需要使用我的关机助手的界面来关机。但是我的程序图标点击默认是启动程序,而我的程序有没有限制,而且默认还是最小化的,点再多也没有用,指示多开 了一堆程序而已。所以本次需要增加以下功能程序启动只能有一个进程,不能多开双击桌面图标,如果程序启动,则显示程序,如果没有,则创建程序。2 解决方案要实现上面的功能,我先想到的就是寻找进程,程序启动的时候看看有没有这个的东西,但是呢,有没有搞过,这都21世纪了,百度一下,发现一个有很多种方法大致有一下几种参考链接,这里只做搬运 https://blog.csdn.net/robertkun/article/details/8518576#2.1共享内存据说这种方法在Linux系统下会有一个内存释放的问题,在某种情况下会引起程序的异常或崩溃核心代码如下 // 确保只运行一次 QSystemSemaphore sema("JAMKey",1,QSystemSemaphore::Open); sema.acquire();// 在临界区操作共享内存 SharedMemory QSharedMemory mem("SystemObject");// 全局对象名 if (!mem.create(1))// 如果全局对象以存在则退出 { QMessageBox::information(0, MESSAGEBOXTXT,"An instance has already been running."); sema.release();// 如果是 Unix 系统,会自动释放。 return 0; } sema.release();// 临界区 2.2使用QLocalServer和QLocalSocker这种也是我使用的版本,参考链接找不到,不过代码都是找搬过来的,连接:https://blog.csdn.net/sunflover454/article/details/50426639头文件代码#ifndef SINGLEAPPLICATION_H #define SINGLEAPPLICATION_H #include <QApplication> #include <QObject> class QWidget; class QLocalServer; class SingleApplication : public QApplication { Q_OBJECT public: SingleApplication(int &argc,char **argv); bool isRuning(); QWidget *mainWindow; private slots: void newLocalConnectioin(); private: void initLocalConnection(); void newLocalServer(); bool bRunning; QLocalServer *localServer; QString serverName; }; #endif // SINGLEAPPLICATION_H 原文件代码#include "singleapplication.h" #include <QWidget> #include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalServer> #include <QFileInfo> #include <QLibrary> SingleApplication::SingleApplication(int &argc, char **argv) :QApplication(argc,argv),bRunning(false),localServer(nullptr),mainWindow(nullptr) { serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); initLocalConnection(); } bool SingleApplication::isRuning() { return bRunning; } void SingleApplication::newLocalConnectioin() { QLocalSocket *socket = localServer->nextPendingConnection(); if(!socket) return; socket->waitForReadyRead(1000); QTextStream stream(socket); delete socket; if(mainWindow != NULL) { mainWindow->raise(); mainWindow->activateWindow(); mainWindow->setWindowState((mainWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); mainWindow->show(); } } void SingleApplication::initLocalConnection() { bRunning = false; QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(500)) { bRunning = true; QTextStream stream(&socket); QStringList args = QCoreApplication::arguments(); if(args.count() > 1) stream << args.last(); else stream << QString(); stream.flush(); socket.waitForBytesWritten(); return; } newLocalServer(); } void SingleApplication::newLocalServer() { localServer = new QLocalServer(this); connect(localServer,SIGNAL(newConnection()),this,SLOT(newLocalConnectioin())); if(!localServer->listen(serverName)) { if(localServer->serverError() == QAbstractSocket::AddressInUseError) { QLocalServer::removeServer(serverName); localServer->listen(serverName); } } } main 调用#include "mainwindow.h" #include <QApplication> #include <singleapplication.h> void autoStart() { QString appName = QApplication::applicationName(); QString appPath = QApplication::applicationFilePath(); appPath = appPath.replace("/","\\"); QSettings *reg=new QSettings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",QSettings::NativeFormat); QString val = reg->value(appName).toString(); if(val != appPath) reg->setValue(appName,appPath); reg->deleteLater(); } //int main(int argc, char *argv[]) //{ // QApplication a(argc, argv); // autoStart(); // MainWindow w; w.show(); // return a.exec(); //} int main(int argc, char *argv[]) { SingleApplication a(argc, argv); if(!a.isRuning()) { autoStart(); MainWindow w; a.mainWindow = &w; // w.show(); return a.exec(); } return 0; } 2.3使用官方的QSignalApplication官方类,但是默认不在Qt中,需要自己下载安装:参考链接https://blog.csdn.net/bloke_come/article/details/106319236
1. 场景描述还是用开机助手这个软件来举例,软件在编译打包完成后,正常启动后,可以正常读取到与其同级目录下BAT文件中的关机脚本的,如下图经过测试,是没有问题,但是呢,当我们把程序设置为开机启动,在程序开机自启动后,无法读取程序的关机脚本。2. 查找原因2.1 权限原因在开始部署的时候,把程序安装到了C盘,开始怀疑是不是因为给的权利不够,在给了全部权限后,还是不可以。排除权限问题。2.2 在部署目录运行在部署目录手动启动,程序可以正常执行,可以读取到关机脚本。2.3 文件路径问题经过百度后,才明白,如果我们把程序设置为开机启动后,因为开机启动的指令其实也是CMD的指令,所以,如果我们在代码中使用以下代码获取程序路径,其实获取到的是CMD程序的运行路径,也就是“C:\Windows\System32”,所以会发现找不到文件QString appPath = QApplication::applicationFilePath(); 3. 解决方法解决方案也很简单,就是把获取程序路径的代码修改一下,如下:QString curPath = QCoreApplication::applicationDirPath(); 问题解决附上源码#include "mainwindow.h" #include "./ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QWidget(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); this->setWindowTitle("网络关机助手"); this->setWindowFlag(Qt::FramelessWindowHint); ui->label_mainBack->setStyleSheet("QLabel{border-image:url(:/images/images/mainBack.png);}"); ui->label_logo->setStyleSheet("QLabel{border-image:url(:/images/images/logo_W.png);}"); ui->pushButton_poweroff->setToolTip("关闭所有在线计算机"); ui->pushButton_close->setToolTip("最小化到任务栏"); ui->pushButton_poweroff->setStyleSheet("QPushButton{border-image:url(:/images/images/pw_n.png);}QPushButton:hover{border-image:url(:/images/images/pw_h.png);}QPushButton:pressed{border-image:url(:/images/images/pw_p.png);}"); ui->label_title->setText("网络关机助手"); readConfig(); initUDPSocket(); initMySystemTrayIcon(); initGetTimeTimer(); getSystemInfor(); } MainWindow::~MainWindow() { if(m_getTimeTimer) { m_getTimeTimer->stop(); delete m_getTimeTimer; m_getTimeTimer = nullptr; } delete ui; } void MainWindow::powerOffBat() { QString strinfo; QProcess p(NULL); QString curPath = QCoreApplication::applicationDirPath(); QString toolPath; toolPath = "/BAT"; curPath.append(toolPath); p.setWorkingDirectory(curPath); toolPath = "/poweroff.bat"; curPath.append(toolPath); p.start(curPath); if(p.waitForFinished()) { qDebug() << "成功"; } else { QMessageBox::warning(this,"警告","执行关机脚本失败\r\n请检查程序根目录下BAT文件中是否存在‘poweroff.bat’"); } } void MainWindow::sentConmad() { m_Socket->writeDatagram(QString::number(1,16).toLatin1(),QHostAddress::Broadcast,8088); } void MainWindow::on_pushButton_poweroff_clicked() { /* * 关机指令需要测试,UDP广播应该是自己也可以收到,所以这里应该不需要单独执行关机指令 */ sentConmad(); } void MainWindow::getUDPDate() { while (m_Socket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_Socket->pendingDatagramSize()); m_Socket->readDatagram(datagram.data(),datagram.size()); if(datagram.toInt() == 0x01) { if(this->isHidden()) { this->show(); } powerOffBat(); } } } void MainWindow::on_pushButton_close_clicked() { // this->close(); //最后注释 this->hide(); } void MainWindow::initMySystemTrayIcon() { /* * 设置系统托盘内容 */ m_trayIcon = new QSystemTrayIcon(this); m_trayIcon->setIcon(QIcon(":/images/images/logo.ico")); m_trayIcon->setToolTip("关机助手"); m_trayIcon->show(); connect(m_trayIcon,&QSystemTrayIcon::activated,this,[=](QSystemTrayIcon::ActivationReason temp){ switch (temp) { case QSystemTrayIcon::Trigger: { //单击图标时间 break; } case QSystemTrayIcon::DoubleClick: { if(this->isHidden()) { this->showNormal(); } else { this->hide(); } break; } } }); initMySystemTrayIconAction(); initMySystemTrayIconMenu(); // m_trayIcon->showMessage("Tip","PowerControl is running",QSystemTrayIcon::MessageIcon::Information,3); } void MainWindow::initMySystemTrayIconAction() { m_showWindowAction = new QAction(QIcon(":/images/images/logo.ico"),"显示界面",this); connect(m_showWindowAction,&QAction::triggered,this,[=](){this->show();}); m_exitAppAction = new QAction(QIcon(":/images/images/exit.ico"),"退出程序",this); connect(m_exitAppAction,&QAction::triggered,this,[=](){this->close();}); m_powerOffAppAction = new QAction(QIcon(":/images/images/logo.ico"),"一键关机",this); connect(m_powerOffAppAction,&QAction::triggered,this,&MainWindow::on_pushButton_poweroff_clicked); } void MainWindow::initMySystemTrayIconMenu() { m_trayIconMenu = new QMenu(this); m_trayIconMenu->addAction(m_powerOffAppAction); m_trayIconMenu->addSeparator(); m_trayIconMenu->addAction(m_showWindowAction); m_trayIconMenu->addAction(m_exitAppAction); m_trayIcon->setContextMenu(m_trayIconMenu); } void MainWindow::initUDPSocket() { m_Socket = new QUdpSocket(); m_Socket->bind(8088,QUdpSocket::ShareAddress); connect(m_Socket,&QUdpSocket::readyRead,this,&MainWindow::getUDPDate); } static QPoint last(0,0); //保存坐标 const int TITLE_HEIGHT = 50; //这里也可以使用宏定义,保存标题高度,也就是鼠标点击区域的高度 void MainWindow::mousePressEvent(QMouseEvent *event) { if(event->position().y()<TITLE_HEIGHT) { last = event->globalPosition().toPoint(); } } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if(event->position().y()<TITLE_HEIGHT) { int dx = event->globalPosition().x() - last.x(); int dy = event->globalPosition().y() - last.y(); last = event->globalPosition().toPoint(); this->move(this->x()+dx,this->y()+dy); } } void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if(event->position().y()<TITLE_HEIGHT) { int dx = event->globalPosition().x() - last.x(); int dy = event->globalPosition().y() - last.y(); this->move(this->x()+dx,this->y()+dy); } } QString MainWindow::getTime(QString format) { QTime mTime = QTime::currentTime(); if(ui->checkBox_isTimerOff->isChecked()) if(mTime.hour() == mTimeOff.hour() && mTime.minute() == mTimeOff.minute()) { ui->checkBox_isTimerOff->setChecked(false); QSettings *config = new QSettings("CONFIG.ini",QSettings::IniFormat); config->setValue("TimerOff/HH",mTime.hour()); config->setValue("TimerOff/MM",mTime.minute()); sentConmad(); } return mTime.toString(format); } void MainWindow::initGetTimeTimer() { if(!m_getTimeTimer) { m_getTimeTimer = new QTimer(this); } connect(m_getTimeTimer,&QTimer::timeout,this,[=](){ ui->pushButton_close->setText(getTime("hh:mm")); }); m_getTimeTimer->start(500); } void MainWindow::getSystemInfor() { m_systemName = QHostInfo::localHostName(); QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); for (int i = 0; i < ipAddressesList.size(); ++i) { if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) { m_systemIp = ipAddressesList.at(i).toString(); break; } } if (m_systemIp.isEmpty()) m_systemIp = QHostAddress(QHostAddress::LocalHost).toString(); ui->label_sysInfor->setText(QString("设备名称:%1\r\nI P 地址:%2").arg(m_systemName).arg(m_systemIp)); } void MainWindow::readConfig() { QString curPath = QCoreApplication::applicationDirPath(); curPath.append("/CONFIG.ini"); QSettings *config = new QSettings(curPath,QSettings::IniFormat); ui->timeEdit_off->setTime(QTime(config->value("TimerOff/HH").toInt(),config->value("TimerOff/MM").toInt(),0,0)); if(config->value("TimerOff/FLAG").toInt()) { ui->checkBox_isTimerOff->setChecked(true); } } void MainWindow::on_timeEdit_off_userTimeChanged(const QTime &time) { mTimeOff = time; } void MainWindow::on_checkBox_isTimerOff_clicked(bool checked) { QString curPath = QCoreApplication::applicationDirPath(); curPath.append("/CONFIG.ini"); QSettings *config = new QSettings(curPath,QSettings::IniFormat); if(checked) { config->setValue("TimerOff/FLAG",1); config->setValue("TimerOff/HH",ui->timeEdit_off->time().hour()); config->setValue("TimerOff/MM",ui->timeEdit_off->time().minute()); } else config->setValue("TimerOff/FLAG",0); }
Qt 解决程序动态库必须和可执行文件放同一文件夹1 背景最近项目开发需要调用多个外部的动态库,以前一般也就是调用一两个,无所谓,现在需要调用很多个,就想给多个动态库分分类,已方便以后项目的迭代 ,尝试了才发现,只能在同级目录才能调用。所以,决定研究研究。2 使用场景描述2.1 添加动态库我习惯使用相对路径来调用动态库,如下 INCLUDEPATH += $$PWD/CANCore/X64 DEPENDPATH += $$PWD/CANCore/X64 unix|win32: LIBS += -L$$PWD/GECore/Lib/ -lrfm2gdll_stdc_64 INCLUDEPATH += $$PWD/GECore/Inc DEPENDPATH += $$PWD/GECore/Inc 2.2 更改编译目录我编译的时候,使用的Qt自带的“Shadow build“,目录也是自己定义的,如下2.3 复制库文件到编译目录并运行程序复制库文件到编译目录,运行,可以看到程序运行失败了,如下2.4 复制库文件到程序根目录如果把动态库文件复制到程序根目录,那么这里及可以运行了运行程序,如下图到这里大致问题应该就描述明白了,还有最后一个需要试一下,那就是Release以后的程序,是不是同样需要把动态库复制到程序更目录2.5 Release下测试下图是Release下的原始目录,这里我们还需要把我们的必要的Qt库文件搬过来,使用工具即可执行如下指令,便可以吧Qt库搬运到我们的目录中,如下尝试运行一下程序,如下,默认Qt的搬运能力是没法办搬运我们自己库的,需要自己手动搬运一下把对应的GE库和CAN总线库搬运到程序目录,这是我们理想的目录结构如下图,现在尝试能否运行运行结果如下,还是不可以,那么在试试吧库搬出来到与程序同级目录结果证明,Release下还是同样,需要把库文件拷贝到统计目录在可以,那么别人的可以分类的文件夹是怎么做到的呢,我们来搞一下3 实现动态库文件夹分类3.1 需求需求就是希望我们的库文件可以放在一个我们自定义的文件家中,程序调用,不用将所有的库文件都放在程序的同级目录。3.2 实现3.2.1 查看项目运行配置如下图,通过查看项目运行设置,我们已经把库文件目录放到了程序的搜索目录了。但是为什么还是不可以呢。这里是看不错出啥新奇玩意了,还是找百度吧。
絮叨UG8安装今天又折腾了一上午,好歹是成功了,特地记录一下,以防止以后用到了再去麻烦别人。自己动手,丰衣足食。[video(video-BsSLTgx0-1615994098893)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=844649266)(image-https://ucc.alicdn.com/images/user-upload-01/img_convert/4dc6d79d2def5621daf5f0b6dbee4776.png)(title-UG8安装指南)]解压文件在我理解看来,这个软件对文件夹目录比较敏感,不要有中文路径空格等特殊字符。文件夹加压后由如下图三个子文件,其中我们的安装程序就是中间的UG8.5的文件夹,这里为了保险起见,还是要给他把和面的中文去掉。总结这里一直参考文件中的安装说明,只是实现方式不同,按照我的这种方式,只要每一步都没有问题,那就是可以的。祝好运。
制作高度计高度计是通过对大气压强的测量来确定高度的。目的最终效果图配置工作环境 创建一个名为”_altimeter”的工程,将GL Studio安装目录教程内的_altimeter教程下的testures文件夹拷贝到当前文件夹。Object的设计 Step 1: 在创建的工程目录下,找到”_altimeter.gls”,并打开。后在”Geometry”选项卡窗口中删除默认生成的group。 Step 2: 打开”Application” tab, 为window title改名为”altimeter”, 然后设置窗口的初始尺寸为390x395。 Step 3: 在工具栏找到右侧的下拉箭头,在弹出的对话框中按下图内容进行设置:创建背光板(Bezel) 背景遮光板由多边形object和其纹理组成。 Step 1: 选择工具栏中的工具; Step 2: 绘制一个390x395的矩形; Step 3: 为其重命名为”altimeter_panel”; Step 4: 在”Object Properties” tab中,将”altimeter_panel”的Draw Mode设置为Filled; Step 5: 同样在”Object Properties” tab中,点击Texture ->Texture Chooser上的 按钮,进入纹理选择对话框,将纹理添加进来,并选中”sltimeter.png”纹理;\1. // Clamp the value of the odometer from 0 to 99999.\2. _altitude = CLAMP_VALUE(value, 0.0f, 99999.9f);\3. // Set the odometer readout to the actual incoming clamped value\4. alt_digits->Value(_altitude);\5. // Calculate the digits less than 1000 to set the needle position\6. float alt_100 = (float)fmod(_altitude, 1000.0f)/100.0f;\7. // Set the needle rotation using DynamicRotate, converting 100’s of feet to degrees.\8. needle->DynamicRotate(-(alt_100 * (360/10)), Z_AXIS);这段代码实现仪表表针绕Z轴的动态旋转,同时该值也会在显示在高度里程表上。 Step 3: 新建属性”float Barometer = 0.0f”, Step 4: 为该属性的Set函数添加实现函数如下:\1. _barometer = value;\2. baro_digits->Value(_barometer);本段代码将实现气压计表盘的显示。Initialize 在geometry创建之后,Initialize()函数就开始执行了。 Step 1: 在”Code” tab中找到Initialize()函数,在代码输入框添加如下代码:\1. Barometer(28.6f);Calculate Calculate()函数的调用发生在每帧的渲染之后。由于每帧循环都会调用该函数,故而切勿在函数体执行过多的内容。 Step 1: 找到Calculate()函数,在代码输入框中追加上下述代码:\1. if (Testing())\2. {\3. // Generate ramping values from 0.0f to 12000.0f\4. Altitude( RampFloat( time * .07, 0.0f, 12000.0f ) );\5. }本段代码使用效用函数RampFloat()在一个正弦波上值测试高度计的显示。添加效用函数的头文件. 效用函数不包含在run-time库中,隐使用到了效用函数RampFloat(), 故需要添加对应的头文件”glsutil.h”。 Step 1: 在”Code” tab内选中”file _altimeterApp.h”, 在其代码输入框中输入以下内容:\1. #include Object的回调 GL Studio允许回调,回调一般发生在用户输入(鼠标,键盘,或其他),并且回调允许programmers定义与object相关的特定功能。 在该教程内需要定义两个回调函数,一个用于处理和气压读数相关的旋钮输入事件,另一个用于处理和ELEC/PNEU flag相关的开关。 Step 1: 首先先在”Geometry” tab中选中”baro_knob” object, 而后在”Code” tab中找到Object Callbacks->Selected Object Callbacks(#), 参考下图 点击代码输入框为所选择的object(这里是刚选中的baro_kbob)创建回调功能。 回调函数要求返回0或1,而这取决于该回调函数的event是否需要向上遍历该object的父节点的回调,更多information参考User’s Manual。 Step 2: 旋钮需要完成气压的读数显示功能,所以在回调函数中完成的正是此事。将下述代码添加到代码输入框:(Warning: 直接插入的话,会清除掉插入位置之后的内容)\1. int handled = 0;\2.\3. if (ObjectEventIs(ev,“PositionVal”))\4. {\5. // If the knob is turned, we change the value[外链图片转存中…(img-tjNZjQJY-1615698474939)] 点击代码输入框为所选择的object(这里是刚选中的baro_kbob)创建回调功能。 回调函数要求返回0或1,而这取决于该回调函数的event是否需要向上遍历该object的父节点的回调,更多information参考User’s Manual。 Step 2: 旋钮需要完成气压的读数显示功能,所以在回调函数中完成的正是此事。将下述代码添加到代码输入框:(Warning: 直接插入的话,会清除掉插入位置之后的内容)\1. int handled = 0;\2.\3. if (ObjectEventIs(ev,“PositionVal”))\4. {\5. // If the knob is turned, we change the value// of the Baro
什么是GLSGLS全称GL Studio,是一款独立于平台的快速原型工具,用来创建实时的、二维的或三维的、照片级的、交互式的图形界面软件。它可以与HLA/DIS仿真软件相连,它生成的C++和OpenGL源代码可以单独运行,也可以嵌入到其他的应用程序中。它运行于Windows NT、IRIX和Linux操作系统上。更为详细的信息,大家自行百度就可以。GLS是开发实时的、交互的2/3维对象的一种工具,它的设计工具维用户提供了制作各种仪表和物理装置的能力,可用于虚拟仪表系统中的维修仿真。程序训练仿真,或用于完全嵌入式的交互仿真。一个GLS图形对象一旦完成,用户就可以将已植入的行为代码与对象连接。当用户需要将这个GLS文件植入到C++预研是,它将会生成Open GL 对应的源代码,对象设计器能帮助用户创建复杂的仪表或装置,这个仿真设计能被创建为:可单独执行的文件动态连接库ActiveX文件,它可单独被应用,也可以与第三方OpenGl设计联合应用,或通过Web植入到幻灯片PPT中。GLS 编辑器介绍GLS 编辑器可以分为三大部分,设计窗口、主控制窗口和对象属性窗口同时GLS提供两种方式来呈现设计结果,树形层次结构图(Geometry)和多样的绘图画板(设计窗口)工具栏就是和PS的工具栏差不多,画布就是也是PS的画布,可以立刻看到效果,下面的视图控制栏就是预制了几个视角,还有一个就是可以自己随便调整的视角。属性栏就是每个控件对应的属性,后面可以慢慢熟悉,树就是我们整个项目的一个结构,可以清晰的看到整个项目的逻辑结构。大致的结构就是这样的,和面更详细的需要在使用的时候慢慢研究,其实程序不是什么高级的东西,感觉也是需要练习的。其他在详细的我也介绍不来了,和面在有了更好的了解了,在好好说到说到。后面我见尝试制作一个地平仪,来尝试一下,敬请期待。后面我见尝试制作一个地平仪,来尝试一下,敬请期待。
关键字介绍TyporaTypora 是一款优秀的本地Markdown编辑器。目前我也在学习MD阶段,还在适应中。PicGoPicGo 是一款优秀的图床工具,所谓图床工具,就是自动把本地图片转换成链接的一款工具。这个工具是第一次接触,第一次安装,不做评价,先用起来再说吧。GitHubGitHub 是代码管理平台,之前是搞过,不过现在在回头看当初搞得那些,渣渣,就都删除了,目前仅保留了汽车仪表和网易云的代码。网易云源码: https://github.com/DreamLife-Jianwei/MCloudMusic汽车仪表源码:https://github.com/DreamLife-Jianwei/Carmeter为什么要这么搞这个需要说明一下,我之前写博客用的都是有道云笔记普通文本模式,CSDN用的也是富文本编辑器,没有用MD,但是不管使用富文本,还是MD,都存在一个图片无法上传的问题,以前我每次写博客的时候,都只能复制有道云中的文本(标题都不支持)完了图片需要将有道云笔记中的每一张图片另存为,在重新上传。这一个来回下来,那是要累死的节奏。这不,年也过完了,工资也没有涨,跳槽吧,感觉这一年技术也没啥大的长进,平跳也不是一个是,加上自己年纪也不小了,总不能总是跳来跳去,总得想的多一点。所以决定还是重新提升一下技能,正式Qt6发布,可以准备一个小项目练手一下,这个项目需要具备一下几点自己感兴趣,不然会写不下去与公司利益不能产生冲突对公司技术有一定的支撑,不然我周报也没法写(嘿嘿嘿)在结合我自身情况,综合考虑下,决定重启我的汽车仪表项目,上个版本的项目是基于QWidget的项目,新的汽车仪表项目将准备使用Quick,新项目代号“CAR_HMI2”希望小伙伴们多多支持。获取Typora可以根据自身系统版本自行下载对应的版本,最好下载最新的版本,以前的版本是不支持图床的。Typora下载地址:https://www.typora.io/如上图所示,选择自己合适的版本下载即可,安装就是傻瓜式下一步。安装图床工具获取picgo地址:https://github.com/PicGo/Awesome-PicGo同理,根据自己系统版本,自行下载对应的版本安装也是傻瓜式一步一步建立仓库在GitHub上建立仓库,这里不展开,需要的自行百度。这里就是图床的设置了,详细操作看这里:https://blog.csdn.net/yefcion/article/details/88412025Typora设置Typora设置如下设置完成或,记得点击验证图片上传选项测试一下,成功就可以愉快的使用了,这里肯定有很多人会失败,因为图床的仓库名是名字/仓库,而从GitHub上复制下来的名称是名字 / 仓库,记得修正一下就可以了。写的不咋地,大家凑合看吧。觉有用就点个大拇指,嘿嘿嘿2021年3月12月更新之前用的github,总是有很多图片出现连接失败的情况,这次切换gitee试试。基本设置和github差不多。在这里添加插件,配置的时候,网上大部分不可都是错误的,简直误人子弟。这里需要注意下,看图这个才是正确的方式,其他的,参照网上的设置就可以了。祝好运。一晚上就浪费了,哎。这里需要注意下,看图[外链图片转存中…(img-jk3rdF7d-1615558903963)]这个才是正确的方式,其他的,参照网上的设置就可以了。祝好运。一晚上就浪费了,哎。
* * 鼠标按下操作 * 记录当前坐标 */ static QPoint last(0,0); //保存坐标 const int TITLE_HEIGHT = 50; //这里也可以使用宏定义,保存标题高度,也就是鼠标点击区域的高度 void MainWindow::mousePressEvent(QMouseEvent *event) { if(event->y()<TITLE_HEIGHT) { last = event->globalPos(); } } /* * 鼠标移动函数 * 这里实时修改窗口的坐标 */ void MainWindow::mouseMoveEvent(QMouseEvent *event) { if(event->y()<TITLE_HEIGHT) { int dx = event->globalX() - last.x(); int dy = event->globalY() - last.y(); last = event->globalPos(); this->move(this->x()+dx,this->y()+dy); } } /* * 鼠标释放函数 */ void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if(event->y()<TITLE_HEIGHT) { int dx = event->globalX() - last.x(); int dy = event->globalY() - last.y(); this->move(this->x()+dx,this->y()+dy); } }在Qt6中有部分变化,如下,当时,沿用Qt5中的代码除了警告是没有其他问题的。 static QPoint last(0,0); //保存坐标 const int TITLE_HEIGHT = 50; //这里也可以使用宏定义,保存标题高度,也就是鼠标点击区域的高度 void MainWindow::mousePressEvent(QMouseEvent *event) { if(event->position().y()<TITLE_HEIGHT) { last = event->globalPosition().toPoint(); } } void MainWindow::mouseMoveEvent(QMouseEvent *event) { if(event->position().y()<TITLE_HEIGHT) { int dx = event->globalPosition().x() - last.x(); int dy = event->globalPosition().y() - last.y(); last = event->globalPosition().toPoint(); this->move(this->x()+dx,this->y()+dy); } } void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if(event->position().y()<TITLE_HEIGHT) { int dx = event->globalPosition().x() - last.x(); int dy = event->globalPosition().y() - last.y(); this->move(this->x()+dx,this->y()+dy); } }
关键字介绍TyporaTypora 是一款优秀的本地Markdown编辑器。目前我也在学习MD阶段,还在适应中。PicGoPicGo 是一款优秀的图床工具,所谓图床工具,就是自动把本地图片转换成链接的一款工具。这个工具是第一次接触,第一次安装,不做评价,先用起来再说吧。GitHubGitHub 是代码管理平台,之前是搞过,不过现在在回头看当初搞得那些,渣渣,就都删除了,目前仅保留了汽车仪表和网易云的代码。网易云源码: https://github.com/DreamLife-Jianwei/MCloudMusic汽车仪表源码:https://github.com/DreamLife-Jianwei/Carmeter为什么要这么搞这个需要说明一下,我之前写博客用的都是有道云笔记普通文本模式,CSDN用的也是富文本编辑器,没有用MD,但是不管使用富文本,还是MD,都存在一个图片无法上传的问题,以前我每次写博客的时候,都只能复制有道云中的文本(标题都不支持)完了图片需要将有道云笔记中的每一张图片另存为,在重新上传。这一个来回下来,那是要累死的节奏。这不,年也过完了,工资也没有涨,跳槽吧,感觉这一年技术也没啥大的长进,平跳也不是一个是,加上自己年纪也不小了,总不能总是跳来跳去,总得想的多一点。所以决定还是重新提升一下技能,正式Qt6发布,可以准备一个小项目练手一下,这个项目需要具备一下几点自己感兴趣,不然会写不下去与公司利益不能产生冲突对公司技术有一定的支撑,不然我周报也没法写(嘿嘿嘿)在结合我自身情况,综合考虑下,决定重启我的汽车仪表项目,上个版本的项目是基于QWidget的项目,新的汽车仪表项目将准备使用Quick,新项目代号“CAR_HMI2”希望小伙伴们多多支持。获取Typora可以根据自身系统版本自行下载对应的版本,最好下载最新的版本,以前的版本是不支持图床的。Typora下载地址:https://www.typora.io/如上图所示,选择自己合适的版本下载即可,安装就是傻瓜式下一步。安装图床工具获取picgo地址:https://github.com/PicGo/Awesome-PicGo同理,根据自己系统版本,自行下载对应的版本安装也是傻瓜式一步一步建立仓库在GitHub上建立仓库,这里不展开,需要的自行百度。这里就是图床的设置了,详细操作看这里:https://blog.csdn.net/yefcion/article/details/88412025Typora设置Typora设置如下设置完成或,记得点击验证图片上传选项测试一下,成功就可以愉快的使用了,这里肯定有很多人会失败,因为图床的仓库名是名字/仓库,而从GitHub上复制下来的名称是名字 / 仓库,记得修正一下就可以了。写的不咋地,大家凑合看吧。觉有用就点个大拇指,嘿嘿嘿
接上一个版本,这个版本中新增了定时关机功能。同时已更换成了公司的LOGO,如下图所示下面分享一下主要核心代码void MainWindow::readConfig() { QString curPath = QCoreApplication::applicationDirPath(); curPath.append("/CONFIG.ini"); QSettings *config = new QSettings(curPath,QSettings::IniFormat); ui->timeEdit_off->setTime(QTime(config->value("TimerOff/HH").toInt(),config->value("TimerOff/MM").toInt(),0,0)); if(config->value("TimerOff/FLAG").toInt()) { ui->checkBox_isTimerOff->setChecked(true); } }首先需要有读取配置文件功能,定时关机的功能开关机时间都保存在本地的config文件中,每次程序启动都去读取文件其次要有写入功能,每次修改时间后,可以回写到config文件中,这里有两部分,一种是功能开关了,一种就是自动执行了如下void MainWindow::on_checkBox_isTimerOff_clicked(bool checked) { QString curPath = QCoreApplication::applicationDirPath(); curPath.append("/CONFIG.ini"); QSettings *config = new QSettings(curPath,QSettings::IniFormat); if(checked) { config->setValue("TimerOff/FLAG",1); config->setValue("TimerOff/HH",ui->timeEdit_off->time().hour()); config->setValue("TimerOff/MM",ui->timeEdit_off->time().minute()); } else config->setValue("TimerOff/FLAG",0); }执行就是在获取时间函数里面更新,这里等于重写了上个版本中的获取时间函数,如下QString MainWindow::getTime(QString format) { QTime mTime = QTime::currentTime(); if(ui->checkBox_isTimerOff->isChecked()) if(mTime.hour() == mTimeOff.hour() && mTime.minute() == mTimeOff.minute()) { ui->checkBox_isTimerOff->setChecked(false); QSettings *config = new QSettings("CONFIG.ini",QSettings::IniFormat); config->setValue("TimerOff/HH",mTime.hour()); config->setValue("TimerOff/MM",mTime.minute()); sentConmad(); } return mTime.toString(format); }这样就可以完成了
2021年12月