1 / 38

3D Slicer Qt Port

3D Slicer Qt Port. Julien Finet Kitware Inc. Dec. 16 th 2009. Background. 3D Slicer version 3.x use KWWidgets VTK-style interface to Tk 3D Slicer 1.x, 2.x used Tk directly Qt 4.6 Embedded Linux, Mac OS X, Windows, Linux/X11, Windows CE/Mobile, Symbian , Maemo LGPL 600+ classes

joey
Télécharger la présentation

3D Slicer Qt Port

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 3D Slicer Qt Port JulienFinet Kitware Inc. Dec. 16th 2009

  2. Background • 3D Slicer version 3.x use KWWidgets • VTK-style interface to Tk • 3D Slicer 1.x, 2.x used Tk directly • Qt 4.6 • Embedded Linux, Mac OS X, Windows, Linux/X11, Windows CE/Mobile, Symbian, Maemo • LGPL • 600+ classes • Tens of thousands of applications • 15+ millions of users • NIH Supplement to help with port • 9/17/2009 - 9/16/2011

  3. Qt – How to get Qt • Required version: Qt 4.6 • Building Slicer with Qt • http://wiki.slicer.org/slicerWiki/index.php/Slicer3:Developers:Projects:QtSlicer/Tutorials/CompileWithQt • Links: • Doc: http://qt.nokia.com/doc/4.6/index.html • Tutorials: http://qt.nokia.com/doc/4.6/tutorials.html

  4. Qt – First steps • Hello World • Signals / Slots • Events vs Signals/Slots • Layouts • What QObject does for you ? • Parent / child relationship • Designer • Not only GUI widgets in Qt

  5. Qt in Slicer • Events with KWWidgets • Fire event • Connect • Process void vtkSlicerNodeSelectorWidget::ProcessCommand(char *selectedID) { … this->InvokeEvent(vtkSlicerNodeSelectorWidget::NodeSelectedEvent, NULL); … } vtkSlicerNodeSelectorWidget.cxx void vtkSlicerCamerasGUI::AddGUIObservers() { … this->ViewSelectorWidget->AddObserver( vtkSlicerNodeSelectorWidget::NodeSelectedEvent, (vtkCommand *)this->GUICallbackCommand ); … } vtkSlicerCamerasGUI.cxx void vtkSlicerCamerasGUI::ProcessGUIEvents( vtkObject *caller, unsigned long event, void *callData ) { if (vtkSlicerNodeSelectorWidget::SafeDownCast(caller)) { if (event == vtkSlicerNodeSelectorWidget::NodeSelectedEvent) { … } vtkSlicerCamerasGUI.cxx

  6. Qt in Slicer • Events with Qt • Fire event • Connect • Process void qMRMLNodeSelector::nodeIdSelected(int index) { … emit currentNodeChanged(d->MRMLCurrentNode); } qMRMLNodeSelector.cxx void qSlicerCamerasModuleWidget::setup() { … connect(d->ViewNodeSelector, SIGNAL(currentNodeChanged(vtkMRMLNode*)), this, SLOT(onCurrentViewNodeChanged(vtkMRMLNode*))); … } qSlicerCamerasModuleWidget.cxx void qSlicerCamerasModuleWidget::onCurrentViewNodeChanged(vtkMRMLNode* mrmlNode) { vtkMRMLViewNode* currentViewNode = vtkMRMLViewNode::SafeDownCast(mrmlNode); … } qSlicerCamerasModuleWidget.cxx

  7. Qt and VTK • qVTKConnect() • Based on VTK/GUISupport/Qt/vtkEventQtSlotConnect // qVTK includes #include <qVTKObject.h> … class QMRML_WIDGETS_EXPORT qMRMLNodeSelector : public qCTKAddRemoveComboBox { Q_OBJECT QVTK_OBJECT public: … qMRMLNodeSelector.h QVTK_OBJECT adds the function qvtkConnect() void qMRMLNodeSelector::addNode(vtkMRMLNode* mrmlNode) { … this->qvtkConnect(mrmlNode, vtkCommand::ModifiedEvent, this, SLOT(onMRMLNodeModified(vtkObject*, void*))); … } qMRMLNodeSelector.cxx

  8. Porting Slicer to Qt • Create Qt/KWW co-existence layer (done!) • Prototype a few modules (done!) • Create an architecture for Qt based modules (in process) • Train developers (first session at January 2010 Project Week) • Port modules (ongoing through 2010…) • Turn off KWW (by end of 2010?) • Continual Improvement (through end of supplement and beyond…)

  9. Porting Slicer to Qt Executable: SlicerQT • Slicer: Qt only Executable: Slicer3 • Slicer: KWWidgets + Qt

  10. Modules • Core Modules: Slicer3/Base/QTCoreModules • qSlicerTransformsModule • Loadable Modules: Slicer3/QTModules • Measurements • Volumes • CLI Modules

  11. Plugin Mechanism • Previously: itksys::DynamicLoader(dlopen) • Now: Use the QT Plugins framework … class Q_SLICER_QTMODULES_VOLUMES_EXPORT qSlicerVolumesModule : public qSlicerAbstractLoadableModule { Q_INTERFACES(qSlicerAbstractLoadableModule); public: … }; Plugin header … Q_EXPORT_PLUGIN2(qSlicerVolumesModule, qSlicerVolumesModule); … Plugin implementation QPluginLoader loader; loader.setFileName(pluginPath); loader.load(); QObject * object = this->Loader.instance(); qSlicerAbstractLoadableModule* module = qobject_cast<qSlicerAbstractLoadableModule*>(object); Plugin Loader

  12. Modules: Logic + UI Module (qSlicerAbstractModule) QObject create() create() UI (qSlicerAbstractModuleWidget) Logic (qSlicerAbstractModuleLogic) QWidget vtkMRMLScene

  13. How to write a loadable module • Create directories in Slicer3/QTModules • MyModule • MyModule/Resources • MyModule/Resources/UI • MyModule/Resources/Icons (optional) • Create the files • MyModule/CMakeLists.txt • MyModule/qSlicerMyModule.[h/cxx] • MyModule/qSlicerMyModuleWidget.[h/cxx] • MyModule/qSlicerMyModuleLogic.[h/cxx] (optional) • MyModule/Resources/qSlicerMyModule.qrc (optional) • MyModule/Resources/UI/qSlicerMyModule.ui

  14. MyModule UI – 1 / 4 • Open Qt Designer with QT_PLUGIN_PATH set to “Slicer3-build/bin” • Designing a module UI requires the plugins: qCTKWidgets, qVTKWidgets, qMRMLWidgets and qSlicerBaseQTGUI • Warning: plugins must be compiled under the same mode than Qt (Release vs. Debug) • On Linux: cd Slicer3-build; python Designer.py • More info on http://wiki.slicer.org/slicerWiki/index.php/Slicer3:Developers:Projects:QtSlicer/Tutorials/QtDesigner

  15. My Module UI – 2 / 4 • Create a UI form: • MyModule/Resources/UI/qSlicerMyModule.ui • qSlicerWidget has the signal mrmlSceneChanged() Qt Designer

  16. MyModule UI – 3 / 4 Drag widgets on the form Names are important Qt Designer

  17. My Module UI – 4 / 4 Connect widgets together with the signals/slots Here the MRMLScene of the module is propagated to the NodeSelector Qt Designer

  18. MyModule Resources • If icons are used, they should be in • MyModule/Resources/Icons/ • Update the resource .qrc file • MyModule/Resources/qSlicerMyModule.qrc <!DOCTYPE RCC> <RCC version="1.0"> <qresource> <file>Icons/MyIcon.png</file> … </qresource> </RCC> qSlicerMyModule.qrc

  19. qSlicerMyModule.h #ifndef __qSlicerMyModule_h #define __qSlicerMyModule_h // SlicerQT includes #include "qSlicerAbstractLoadableModule.h“ #include "qSlicerMyModuleWin32Header.h“ // generated by CMake class qSlicerMyModulePrivate; class Q_SLICER_QTMODULES_MYMODULE_EXPORT qSlicerMyModule : public qSlicerAbstractLoadableModule { Q_OBJECT public: qSlicerTransformsModule(QObject *parent=0); virtual QString title()const { return “Transforms”; } virtual QStringhelpText()const; virtual QStringacknowledgementText()const; protected: // Create and return a widget representation of the object virtual qSlicerAbstractModuleWidget * createWidgetRepresentation(); virtual qSlicerAbstractModuleLogic* createLogic(); }; #endif qSlicerMyModule.h

  20. qSlicerMyModule.cxx #include "qSlicerMyModule.h" // SlicerQT includes #include "qSlicerMyModuleWidget.h" // QT includes #include <QtPlugin> //----------------------------------------------------------------------------- Q_EXPORT_PLUGIN2(qSlicerMyModule, qSlicerMyModule); //----------------------------------------------------------------------------- qSlicerWelcomeModule(QObject* parent) :public qSlicerAbstractLoadableModule(parent) {} //----------------------------------------------------------------------------- qSlicerAbstractModuleWidget * qSlicerWelcomeModule::createWidgetRepresentation() { return new qSlicerWelcomeModuleWidget; } //----------------------------------------------------------------------------- qSlicerAbstractModuleWidget * qSlicerTransformsModule::createWidgetRepresentation() { return new qSlicerMyModuleWidget; } //----------------------------------------------------------------------------- qSlicerAbstractModuleLogic* qSlicerTransformsModule::createLogic() { return 0; } Instantiate the UI widget qSlicerMyModule.cxx

  21. qSlicerMyModuleWidget.h #ifndef __qSlicerMyModuleWidget_h #define __qSlicerMyModuleWidget_h // SlicerQT includes #include "qSlicerAbstractModuleWidget.h" // qCTK includes #include <qCTKPimpl.h> #include "qSlicerMyModuleWin32Header.h" class qSlicerMyModuleWidgetPrivate; class Q_SLICER_QTMODULES_MYMODULE_EXPORT qSlicerMyModuleWidget : public qSlicerAbstractModuleWidget { Q_OBJECT public: typedefqSlicerAbstractModuleWidgetSuperclass; qSlicerMyModuleWidget(QWidget *parent=0); protected: virtual void setup(); private: QCTK_DECLARE_PRIVATE(qSlicerMyModuleWidget); }; #endif Generated by CMake Setup the UI qSlicerMyModuleWidget.h

  22. qSlicerMyModuleWidget.cxx qSlicerMyModuleWidget.cxx #include "qSlicerMyModuleWidget.h" #include "ui_qSlicerMyModule.h" //----------------------------------------------------------------------------- structqSlicerMyModuleWidgetPrivate: public qCTKPrivate<qSlicerMyModuleWidget>, public Ui_qSlicerMyModule { }; //----------------------------------------------------------------------------- qSlicerMyModuleWidget ::qSlicerMyModuleWidget( QWidget* parent) :qSlicerAbstractModuleWidget(parent) { QCTK_INIT_PRIVATE(qSlicerMyModuleWidget);} //----------------------------------------------------------------------------- void qSlicerWelcomeModuleWidget::setup() { QCTK_D(qSlicerWelcomeModuleWidget); d->setupUi(this); } Generated by CMake (via uic) from qSlicerMyModule.ui … void setupUi(qSlicerWidget *qSlicerMyModule) { … verticalLayout = new QVBoxLayout(qSlicerMyModule); CTKCollapsibleButton = new qCTKCollapsibleButton(qSlicerMyModule); CTKCollapsibleButton->setCollapsed(true); horizontalLayout = new QHBoxLayout(CTKCollapsibleButton); label = new QLabel(CTKCollapsibleButton); horizontalLayout->addWidget(label); horizontalSlider = new QSlider(CTKCollapsibleButton); … } Creates the QWidgets Ui_qSlicerMyModule.h

  23. MyModule project • Create a CMakeLists.txt in MyModule • Add your module name in QTModules/CMakeLists.txt SET(qt_module_SRCS qSlicerMyModule.cxx qSlicerMyModule.h qSlicerMyModuleWidget.cxx qSlicerMyModuleWidget.h ) Slicer3_build_qtmodule( NAME “MyModule” TITLE “My Module” EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_MYMODULE_EXPORT“ SRCS ${qt_module_SRCS} MOC_SRCS qSlicerMyModuleWidget.h UI_SRCS Resources/UI/qSlicerMyModule.ui TARGET_LIBRARIES ${qt_module_target_libraries} RESOURCES Resources/qSlicerMyModule.qrc ) QTModules/MyModule/CMakeLists.txt

  24. Tadam ! MyModule MyModule Panel here Slicer3

  25. Module: with a logic and slots:qSlicerTransformsModuleWidget class … qSlicerTransformsModuleWidget : public qSlicerAbstractModuleWidget { Q_OBJECT … public slots: void loadTransform(); … }; structqSlicerTransformsModuleWidgetPrivate: public qCTKPrivate<qSlicerTransformsModuleWidget>, publicUi_qSlicerTransformsModule { qSlicerTransformsModuleLogic* logic() const; }; void qSlicerTransformsModuleWidget::setup() { QCTK_D(qSlicerTransformsModuleWidget); d->setupUi(this); … this->connect(d->LoadTransformPushButton, SIGNAL(clicked()), SLOT(loadTransform())); } Called by the “Load Transform” pushbutton void qSlicerTransformsModuleWidget::loadTransform() { QCTK_D(qSlicerTransformsModuleWidget); QStringfileName = QFileDialog::getOpenFileName(this); d->logic()->AddTransform(fileName); }

  26. Widgets

  27. qCTKWidgets • Common Toolkit (CTK) • Currently hosted on the Slicer repository qCTKFixedTitleComboBox qCTKCollapsibleGroupBox qCTKCollapsibleButton qCTKTreeComboBox qCTKColorPickerButton

  28. qMRMLWidgets • Depends on QT and MRML • Usually contains the slot setMRMLScene(vtkMRMLScene*) qMRMLNodeSelector qMRMLListWidget qMRMLMatrixWidget qMRMLTreeWidget

  29. qCTKPimpl • Hide the implementation details of an interface • http://en.wikipedia.org/wiki/Opaque_pointer // qCTK includes #include "qCTKPimpl.h" // QT includes #include <QAbstractButton> class qCTKCollapsibleButtonPrivate; class QCTK_WIDGETS_EXPORT qCTKCollapsibleButton : public QAbstractButton { Q_OBJECT public: qCTKCollapsibleButton(QWidget *parent = 0); … private: QCTK_DECLARE_PRIVATE(qCTKCollapsibleButton); }; #endif Don’t forget to declare the private class friend class qCTKCollapsibleButtonPrivate; qCTKPrivateInterface<qCTKCollapsibleButton, qCTKCollapsibleButtonPrivate> qctk_d;

  30. qCTKPimpl //----------------------------------------------------------------------------- class qCTKCollapsibleButtonPrivate : public qCTKPrivate<qCTKCollapsibleButton> { public: QCTK_DECLARE_PUBLIC(qCTKCollapsibleButton); void init(); bool Collapsed; … }; //----------------------------------------------------------------------------- void qCTKCollapsibleButtonPrivate::init() { QCTK_P(qCTKCollapsibleButton); p->setCheckable(true); // checked and Collapsed are synchronized: checked != Collapsed p->setChecked(true); this->Collapsed = false; } friend class qCTKCollapsibleButton qctk_d.setPublic(this) //----------------------------------------------------------------------------- qCTKCollapsibleButton::qCTKCollapsibleButton(QWidget* parent) :QAbstractButton(parent) { QCTK_INIT_PRIVATE(qCTKCollapsibleButton); qctk_d()->init(); } //----------------------------------------------------------------------------- void qCTKCollapsibleButton::collapse(bool c) { QCTK_D(qCTKCollapsibleButton); if (c == d->Collapsed) { return; } … } qCTKCollapsibleButton* p = qctk_p() qCTKCollapsibleButtonPrivate* d = qctk_d()

  31. Widgets in Qt Designer • A plugin must be created • Slicer3/Libs/qCTKWidgets/Plugins/qMRMLNodeSelectorPlugin.[h|cxx] • Slicer3/Libs/qMRMLWidgets/Plugins/qMRMLNodeSelectorPlugin.[h|cxx] • More info on • http://wiki.slicer.org/slicerWiki/index.php/Slicer3:Developers:Projects:QtSlicer/Tutorials/WidgetWriting

  32. Widget Example class QCTK_WIDGETS_EXPORT qCTKCollapsibleButton : public QAbstractButton { Q_OBJECT Q_PROPERTY(bool collapsed READ collapsed WRITE setCollapsed) Q_PROPERTY(intcollapsedHeight READ collapsedHeight WRITE setCollapsedHeight) … public: void setCollapsed(bool); bool collapsed()const; void setCollapsedHeight(int); intcollapsedHeight()const; Qt Designer qCTKCollapsibleButton.h 10 = default value void qCTKCollapsibleButtonPrivate::init() { QCTK_P(qCTKCollapsibleButton); … this->Collapsed = false; … this->CollapsedHeight = 10; … } qCTKCollapsibleButton.cxx

  33. QTCLI • Same idea than KWWidgets • Parse XML to build UI • Support • Shared Libraries • Executables • Python UI panel in Slicer

  34. QTCLI: Example … <parameters> <label>Registration Parameters</label> <description>Parameters used for registration</description> <integer> <name>HistogramBins</name> <flag>b</flag> <longflag>histogrambins</longflag> <description>Number of histogram bins to use for Mattes Mutual Information. </description> <label>Histogram Bins</label> <default>30</default> <constraints> <minimum>1</minimum> <maximum>500</maximum> <step>5</step> </constraints> </integer> … UI panel in Slicer Xml description … qCTKCollapsibleButton* registrationParameters = new qCTKCollapsibleButton(“Registration Parameters”, this); QLabel* histogramBinLabel = new QLabel(“Histogram Bins”, registrationParameters); QSlider* histogramBin = new QSlider(registrationParameters); histogramBin->setMinimum(1); histogramBin->setMaximum(500); histogramBin->setStep(5); histogramBin->setValue(30); QObject::connect(histogramBin, SIGNAL(valueChanged(int)), this, SIGNAL(onHistogramValueChanged(int))); … Generated code

  35. Slicer Architecture QTCLI qSlicerCLIModule QTCoreModules qSlicerCamerasModules, qSlicerTransformsModule QTGUI qSlicerModulePanel, qSlicerApplication, qSlicerIOManager QTCore qSlicerModuleFactory QTBase qSlicerAbstractModule, qSlicerIOManager

  36. What’s coming soon ? • CLI modules • Node tree widgets • 3D view widget • Lookup table editor • Slice view widget • …

  37. What’s in the Pipeline ? • Wizards • Python • More widgets • help from the CTK community • http://www.commontk.org/cgi-bin/trac.cgi/wiki/WidgetPlans

  38. Questions ?

More Related