Documentation/Nightly/Developers/Tutorials/MigrationGuide/VTK7-Qt4-to-VTK8-Qt5
Contents
- 1 Transition from VTK7-Qt4 to VTK8-Qt5
- 1.1 Slicer SuperBuild Extension: Enable C++11 in external projects
- 1.2 Qt5: Update loadable modules to use new plugin macros
- 1.3 Qt5: Update DesignerPlugin to use QtUiPlugin/QDesignerCustomWidgetInterface
- 1.4 Qt5: Update DesignerPlugin to use QtUiPlugin/QDesignerCustomWidgetCollectionInterface
- 1.5 Qt5: any use of QWebKit needs to switch to QWebEngine
- 1.6 Qt5: QVTKOpenGLWidget
- 1.7 Qt5: Fix error: 'class QString' has no member named 'toAscii'
- 1.8 Qt5: Fix error: ‘class QHeaderView’ has no member named ‘setResizeMode’
- 1.9 VTK8: Use hierarchy files for VTK Python wrapping
- 1.10 VTK8: Use of vtkTypeMacro requires to use the correct base class
- 1.11 VTK8: Copy constructor and equal operator should be disabled
- 1.12 VTK8: Call InitializeObjectBase() in vtkObject New() methods
- 1.13 VTK8: Add C++11 keywords
- 1.14 VTK8: vtkWindowToImageFilter::SetMagnification() is deprecated
- 1.15 VTK8: vtkInstantiator is deprecated
- 1.16 VTK 8.2: Signature of vtkFSLookupTable::MapValue updated
- 1.17 Slicer scripted module initialization steps after application startup
Transition from VTK7-Qt4 to VTK8-Qt5
This section lists categories of code changes necessary to build and run Slicer with VTK 8.0 and Qt5. Each category has a short description, a suggested upgrade path, and references to relevant commits (TBD once merged).
Slicer SuperBuild Extension: Enable C++11 in external projects
SuperBuild extensions may have to enable C++11 for their external projects. Add the following lines to CMAKE_CACHE_ARGS in ExternalProject_Add
-DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED} -DCMAKE_CXX_EXTENSIONS:BOOL=${CMAKE_CXX_EXTENSIONS}
Suggested commit message:
COMP: Enable C++11 in external projects See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/VTK7-Qt4-to-VTK8-Qt5#Slicer_SuperBuild_Extension:_Enable_C.2B.2B11_in_external_projects
Error message similar to:
/path/to/Slicer-build/ITKv4-build/Modules/Core/Common/itkConfigure.h:59:6: warning: #warning "WARNING: The current project is configured to use a C++ standard version older than the C++ standard used for this build of ITK" [-Wcpp] #warning "WARNING: The current project is configured to use a C++ standard version older than the C++ standard used for this build of ITK" ^
Qt5: Update loadable modules to use new plugin macros
In Qt5, the Q_EXPORT_PLUGIN
, Q_EXPORT_PLUGIN2
macros have been deprecated in favor of the new Q_PLUGIN_METADATA
macro.
Error message similar to:
error: static assertion failed: Old plugin system used
Suggested commit message:
COMP: Qt5: Fix error: static assertion failed: Old plugin system used See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/VTK7-Qt4-to-VTK8-Qt5#Qt5:_Update_loadable_modules_to_use_new_plugin_macros
Solution (part 1):
In qSlicer<NameOfModule>Module.h, replace lines like:
Q_OBJECT Q_INTERFACES(qSlicerLoadableModule);
with:
Q_OBJECT #ifdef Slicer_HAVE_QT5 Q_PLUGIN_METADATA(IID "org.slicer.modules.loadable.qSlicerLoadableModule/1.0"); #endif Q_INTERFACES(qSlicerLoadableModule);
Solution (part 2):
In qSlicer<NameOfModule>Module.cxx, Replace lines like:
Q_EXPORT_PLUGIN2(qSlicer<NameOfModule>Module, qSlicer<NameOfModule>Module);
with:
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) #include <QtPlugin> Q_EXPORT_PLUGIN2(qSlicer<NameOfModule>Module, qSlicer<NameOfModule>Module); #endif
References:
Qt5: Update DesignerPlugin to use QtUiPlugin/QDesignerCustomWidgetInterface
In Qt5, the QtDesigner/QDesignerCustomWidgetInterface
header have been deprecated in favor of the new QtUiPlugin/QDesignerCustomWidgetInterface
header.
Error message similar to:
/path/to/include/QtDesigner/QDesignerCustomWidgetInterface:4:4: warning: #warning Header <QtDesigner/QDesignerCustomWidgetInterface> is deprecated. Please include <QtUiPlugin/QDesignerCustomWidgetInterface> instead. [-Wcpp] # warning Header <QtDesigner/QDesignerCustomWidgetInterface> is deprecated. Please include <QtUiPlugin/QDesignerCustomWidgetInterface> instead. ^
Suggested commit message:
COMP: Update designer plugin to support Qt5 See https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MigrationGuide/VTK7-Qt4-to-VTK8-Qt5#Qt5:_Update_DesignerPlugin_to_use_QtUiPlugin.2FQDesignerCustomWidgetInterface
Solution (part 1):
In Widgets/DesignerPlugins/qSlicer<NameOfModule>ModuleWidgetsAbstractPlugin.h, replace lines like:
#include <QDesignerCustomWidgetInterface>
with:
#include <QtGlobal> #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) #include <QDesignerCustomWidgetInterface> #else #include <QtUiPlugin/QDesignerCustomWidgetInterface> #endif
Solution (part 2):
In Widgets/DesignerPlugins/qSlicer<NameOfModule>ModuleWidgetsAbstractPlugin.h, replace lines like:
Q_INTERFACES(QDesignerCustomWidgetInterface);
with:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface") #endif Q_INTERFACES(QDesignerCustomWidgetInterface);
Qt5: Update DesignerPlugin to use QtUiPlugin/QDesignerCustomWidgetCollectionInterface
Error message similar to:
/path/to/5.9.1/gcc_64/include/QtDesigner/QDesignerCustomWidgetCollectionInterface:4:4: warning: #warning Header <QtDesigner/QDesignerCustomWidgetCollectionInterface> is deprecated. Please include <QtUiPlugin/QDesignerCustomWidgetCollectionInterface> instead. [-Wcpp] # warning Header <QtDesigner/QDesignerCustomWidgetCollectionInterface> is deprecated. Please include <QtUiPlugin/QDesignerCustomWidgetCollectionInterface> instead. ^
Solution (part 1):
In Widgets/DesignerPlugins/qSlicer<NameOfModule>ModuleWidgetsPlugin.h, replace lines like:
#include <QDesignerCustomWidgetCollectionInterface>
with:
#include "vtkSlicerConfigure.h" // For Slicer_HAVE_QT5 // Qt includes #ifdef Slicer_HAVE_QT5 #include <QtUiPlugin/QDesignerCustomWidgetCollectionInterface> #else #include <QDesignerCustomWidgetCollectionInterface> #endif
Solution (part 2):
In Widgets/DesignerPlugins/qSlicer<NameOfModule>ModuleWidgetsPlugin.h, replace lines like:
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface);
with:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidgetInterface") #endif Q_INTERFACES(QDesignerCustomWidgetCollectionInterface);
Qt5: any use of QWebKit needs to switch to QWebEngine
TBD
Qt5: QVTKOpenGLWidget
When using Qt5, QVTKOpenGLWidget should be used in place of QVTKGLWidget.
To ensure that QVTKOpenGLWidget receives a properly configured OpenGL context it's necessary to call QSurfaceFormat::setDefaultFormat() before constructing the QApplication instance. QVTKOpenGLWidget::defaultFormat() supplies a suitable format, although it's recommended to disable multisampling for full compatibility with advanced rendering techniques. See http://doc.qt.io/qt-5/qopenglwidget.html.
Error message similar to:
error: no matching function for call to ‘QVTKWidget::QVTKWidget(QWidget*&)’ scalarsToColorsView = new QVTKWidget(ctkVTKDiscretizableColorTransferWidget); ^
Solution (part 1):
In NameOfClass.h file, replace lines like:
#include <QVTKWidget.h>
with:
#if CTK_USE_QVTKOPENGLWIDGET #include <QVTKOpenGLWidget.h> #else #include <QVTKWidget.h> #endif
Solution (part 2):
In NameOfClass.h file, replace lines like:
QVTKWidget* View;
with:
#if CTK_USE_QVTKOPENGLWIDGET QVTKOpenGLWidget* View; #else QVTKWidget* View; #endif
Solution (part 3):
In NameOfClass.cpp file, replace lines like:
this->View = new QVTKWidget;
with:
#if CTK_USE_QVTKOPENGLWIDGET this->View = new QVTKOpenGLWidget; #else this->View = new QVTKWidget; #endif
Qt5: Fix error: 'class QString' has no member named 'toAscii'
Replace call to toAscii().data()
with toLatin1().data()
References:
Qt5: Fix error: ‘class QHeaderView’ has no member named ‘setResizeMode’
Error message similar to:
error: ‘class QHeaderView’ has no member named ‘setResizeMode’ headerView->setResizeMode(FileColumn, QHeaderView::Stretch);
Solution:
Replace lines like:
headerView->setResizeMode(FileColumn, QHeaderView::Stretch);
with:
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) headerView->setResizeMode(FileColumn, QHeaderView::Stretch); #else headerView->setSectionResizeMode(FileColumn, QHeaderView::Stretch); #endif
Solution for Python:
from packaging import version ... def _setSectionResizeMode(header, *args, **kwargs): """ To be compatible with Qt4 and Qt5 """ if version.parse(qt.Qt.qVersion()) < version.parse("5.0.0"): header.setResizeMode(*args, **kwargs) else: header.setSectionResizeMode(*args, **kwargs) ... _setSectionResizeMode(horizontalHeader, 1, qt.QHeaderView.ResizeToContents)
VTK8: Use hierarchy files for VTK Python wrapping
In VTK8 it's necessary to generate hierarchy files for proper wrapping VTK classes in Python. Without the information provided by the hierarchy files, the Python wrapping tool lacks complete information about classes and types. In this case, the generated classes contain methods that shouldn't be wrapped and fail to compile, and include references to types such as vtkTypeBool. Once the hierarchy files are generated and provided to the Python wrapping tool, the generated classes compile and typedefs like vtkTypeBool are correctly resolved.
Once the VTK8 changes are merged, generating hierarchy files is handled by https://github.com/Slicer/Slicer/blob/master/CMake/vtkMacroKitPythonWrap.cmake.
References:
VTK8: Use of vtkTypeMacro requires to use the correct base class
Error message similar to:
error: expected unqualified-id before 'protected'
This error is usually a symptom of an incorrect base class when using vtkTypeMacro.
Solution:
Assuming the class vtkIGTLToMRMLPoint derives from vtkIGTLToMRMLBase,
Replace lines like:
vtkTypeMacro(vtkIGTLToMRMLPoint,vtkObject);
with:
vtkTypeMacro(vtkIGTLToMRMLPoint,vtkIGTLToMRMLBase);
References:
VTK8: Copy constructor and equal operator should be disabled
Error message similar to:
error: use of deleted function 'vtkMyClass::vtkMyClass(const vtkMyClass&)'
This error is usually a symptom of not disabling the copy constructor and equal operator.
Solution:
Replace lines like:
protected: vtkMyClass(); ~vtkMyClass();
with:
protected: vtkMyClass(); ~vtkMyClass(); vtkMyClass(const vtkMyClass&); void operator=(const vtkMyClass&);
VTK8: Call InitializeObjectBase() in vtkObject New() methods
In VTK8 it's necessary for vtkObject New() methods to call InitializeObjectBase() on the new object for proper tracking with vtkDebugLeaks. The standard macros (vtkStandardNewMacro, vtkObjectFactoryNewMacro) handle this. For those classes that don't use the macros, add a call to InitializeObjectBase() immediately after constructing the object by new vtkXXX().
Additionally, vtkObjectFactory::CreateInstance() now doesn't register the class name with vtkDebugLeaks if the factory fails to create the object. Therefore, it's no longer necessary to unregister the class name with vtkDebugLeaks. Remove calls to vtkDebugLeaks::DestructClass(className) following vtkObjectFactory::CreateInstance().
To support both VTK8 and earlier versions of VTK, wrap these changes in preprocessor checks for whether VTK_HAS_INITIALIZE_OBJECT_BASE is defined.
References:
- https://github.com/Kitware/VTK/commit/e5c793dbdf87e838bb2b60c6a5905ced0e5548f9
- http://public.kitware.com/pipermail/vtk-developers/2016-September/034332.html
VTK8: Add C++11 keywords
VTK8 requires C++11. Subclasses of VTK classes must mark overridden methods with VTK_OVERRIDE.
VTK8: vtkWindowToImageFilter::SetMagnification() is deprecated
VTK8.1 deprecated vtkWindowToImageFilter::SetMagnification() and vtkWindowToImageFilter::GetMagnification(). Replace calls to those methods with SetScale() and GetScale(). See https://github.com/Kitware/VTK/commit/af0a95fa7dd4e25ef869a0bc6077e547f18baa29.
VTK8: vtkInstantiator is deprecated
VTK8.1 deprecated vtkInstantiator. See https://github.com/Kitware/VTK/commit/11bb6a4d395e877847355a63de2e2e8f8d9e1d91
Error message similar to:
/path/to/SlicerIGT-Release/ToolWatchdog/MRMLDM/WatchdogInstantiator.cxx:10:1: error: expected constructor, destructor, or type conversion before ‘void’ void WatchdogInstantiator::ClassInitialize() ^ /path/to/SlicerIGT-Release/ToolWatchdog/MRMLDM/WatchdogInstantiator.cxx: In static member function ‘static void WatchdogInstantiator::ClassFinalize()’: /path/to/SlicerIGT-Release/ToolWatchdog/MRMLDM/WatchdogInstantiator.cxx:21:3: error: ‘vtkInstantiator’ has not been declared vtkInstantiator::UnRegisterInstantiator("vtkMRMLWatchdogDisplayableManager", vtkInstantiatorvtkMRMLWatchdogDisplayableManagerNew); ^ /path/to/SlicerIGT-Release/ToolWatchdog/MRMLDM/WatchdogInstantiator.cxx:21:80: error: ‘vtkInstantiatorvtkMRMLWatchdogDisplayableManagerNew’ was not declared in this scope vtkInstantiator::UnRegisterInstantiator("vtkMRMLWatchdogDisplayableManager", vtkInstantiatorvtkMRMLWatchdogDisplayableManagerNew); ^
Solution (part 1):
Update associated CMakeLists.txt replacing lines like:
set(VTK_USE_INSTANTIATOR_NEW 1) if(${VTK_VERSION_MAJOR} GREATER 5) include(${VTK_CMAKE_DIR}/vtkMakeInstantiator.cmake) endif() VTK_MAKE_INSTANTIATOR3("${MODULE_NAME}Instantiator" displayable_manager_instantiator_SRCS "${displayable_manager_SRCS}" "${${KIT}_EXPORT_DIRECTIVE}" ${CMAKE_CURRENT_BINARY_DIR} "${KIT}Export.h" )
with:
SlicerConfigureDisplayableManagerObjectFactory( TARGET_NAME ${KIT} SRCS "${displayable_manager_SRCS}" EXPORT_MACRO "${${KIT}_EXPORT_DIRECTIVE}" EXPORT_HEADER "${KIT}Export.h" OUTPUT_SRCS_VAR displayable_manager_instantiator_SRCS )
Solution (part 2):
Update associated qSlicer<NameOfModule>Module.h (or any test requiring displayable manager) adding lines like:
// DisplayableManager initialization #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkSlicer<NameOfModule>ModuleMRMLDisplayableManager)
Solution (part 2 - maintaining backward compatibility with Slicer 4.8):
#include <vtkSlicerVersionConfigure.h> // For Slicer_VERSION_MAJOR, Slicer_VERSION_MINOR [...] // DisplayableManager initialization #if Slicer_VERSION_MAJOR == 4 && Slicer_VERSION_MINOR >= 9 #include <vtkAutoInit.h> VTK_MODULE_INIT(vtkSlicer<NameOfModule>ModuleMRMLDisplayableManager) #endif
For example, see https://github.com/SlicerIGT/SlicerIGT/pull/155/commits/2f866ea8872435b9a3a7382dd0549231da00406f
VTK 8.2: Signature of vtkFSLookupTable::MapValue updated
The signature of the function was updated in Kitware/VTK@43f6ee3
Error message similar to:
error: invalid conversion from ‘const unsigned char*’ to ‘unsigned char*’ [-fpermissive]
overriding virtual function return type differs and is not covariant from 'vtkLookupTable::MapValue'
Solution:
Update code to use `const` keyword. For example, see r26708
Slicer scripted module initialization steps after application startup
In Slicer 4.8 and earlier versions, those module initialization steps that required application startup completed, often were called using a singleshot timer, because timer events were only processed after the application startup was completed. In Slicer 4.9, some event processing is performed before the application startup is completed, therefore instead of relying on a timer, the application's startupCompleted() signal must be used.
Replace line like:
qt.QTimer.singleShot(0, self.myAdditionalInitializationSteps)
with:
slicer.app.connect("startupCompleted()", self.myAdditionalInitializationSteps)