Presentation is loading. Please wait.

Presentation is loading. Please wait.

3D Slicer Qt Port Julien Finet Kitware Inc. Dec. 16 th 2009.

Similar presentations

Presentation on theme: "3D Slicer Qt Port Julien Finet Kitware Inc. Dec. 16 th 2009."— Presentation transcript:

1 3D Slicer Qt Port Julien Finet Kitware Inc. Dec. 16 th 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/ /16/2011

3 Qt – How to get Qt Required version: Qt 4.6Qt 4.6 Building Slicer with Qt – 3:Developers:Projects:QtSlicer/Tutorials/Com pileWithQt 3:Developers:Projects:QtSlicer/Tutorials/Com pileWithQt Links: –Doc: –Tutorials:

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 1.Fire event 2.Connect 3.Process void vtkSlicerCamerasGUI::AddGUIObservers() { … this->ViewSelectorWidget->AddObserver( vtkSlicerNodeSelectorWidget::NodeSelectedEvent, (vtkCommand *)this->GUICallbackCommand ); … } void vtkSlicerCamerasGUI::ProcessGUIEvents( vtkObject *caller, unsigned long event, void *callData ) { if (vtkSlicerNodeSelectorWidget::SafeDownCast(caller)) { if (event == vtkSlicerNodeSelectorWidget::NodeSelectedEvent) { … } void vtkSlicerNodeSelectorWidget::ProcessCommand(char *selectedID) { … this->InvokeEvent(vtkSlicerNodeSelectorWidget::NodeSelectedEvent, NULL); … } vtkSlicerNodeSelectorWidget.cxx vtkSlicerCamerasGUI.cxx

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

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

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 Slicer: Qt only Slicer: KWWidgets + Qt Executable: Slicer3 Executable: SlicerQT

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 frameworkQT Plugins … class Q_SLICER_QTMODULES_VOLUMES_EXPORT qSlicerVolumesModule : public qSlicerAbstractLoadableModule { Q_INTERFACES(qSlicerAbstractLoadableModule); public: … }; … Q_EXPORT_PLUGIN2(qSlicerVolumesModule, qSlicerVolumesModule); … QPluginLoader loader; loader.setFileName(pluginPath); loader.load(); QObject * object = this->Loader.instance(); qSlicerAbstractLoadableModule* module = qobject_cast (object); Plugin Loader Plugin implementation Plugin header

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

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 –More info on evelopers: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 importantQt 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 Icons/MyIcon.png … 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 QString helpText()const; virtual QString acknowledgementText()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 // 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 #include "qSlicerMyModuleWin32Header.h" class qSlicerMyModuleWidgetPrivate; class Q_SLICER_QTMODULES_MYMODULE_EXPORT qSlicerMyModuleWidget : public qSlicerAbstractModuleWidget { Q_OBJECT public: typedef qSlicerAbstractModuleWidget Superclass; 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 #include "qSlicerMyModuleWidget.h" #include "ui_qSlicerMyModule.h" // struct qSlicerMyModuleWidgetPrivate: public qCTKPrivate, 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 Creates the QWidgets … 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); … } Ui_qSlicerMyModule.h qSlicerMyModuleWidget.cxx

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 Panel here MyModule Slicer3

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

26 Widgets LibraryQTVTKMRML qCTKWidgetsYes qVTKWidgetsYes qMRMLWidgetsYes qSlicerBaseQTGUIYes

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

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

29 qCTKPimpl Hide the implementation details of an interface r // qCTK includes #include "qCTKPimpl.h" // QT includes #include class qCTKCollapsibleButtonPrivate; class QCTK_WIDGETS_EXPORT qCTKCollapsibleButton : public QAbstractButton { Q_OBJECT public: qCTKCollapsibleButton(QWidget *parent = 0); … private: QCTK_DECLARE_PRIVATE(qCTKCollapsibleButton); }; #endif friend class qCTKCollapsibleButtonPrivate; qCTKPrivateInterface qctk_d; Dont forget to declare the private class

30 qCTKPimpl // class qCTKCollapsibleButtonPrivate : public qCTKPrivate { 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; } // 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; } … } friend class qCTKCollapsibleButton qctk_d.setPublic(this) qCTKCollapsibleButtonPrivate* d = qctk_d() qCTKCollapsibleButton* p = qctk_p()

31 Widgets in Qt Designer A plugin must be created –Slicer3/Libs/qCTKWidgets/Plugins/qMRMLNo deSelectorPlugin.[h|cxx] –Slicer3/Libs/qMRMLWidgets/Plugins/qMRML NodeSelectorPlugin.[h|cxx] More info on – 3:Developers:Projects:QtSlicer/Tutorials/Widg etWriting

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

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

34 QTCLI: Example … Registration Parameters Parameters used for registration HistogramBins b histogrambins Number of histogram bins to use for Mattes Mutual Information. Histogram Bins … 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))); … UI panel in Slicer Xml description Generated code

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

36 Whats coming soon ? CLI modules Node tree widgets 3D view widget Lookup table editor Slice view widget …

37 Whats in the Pipeline ? Wizards Python More widgets –help from the CTK community – bin/trac.cgi/wiki/WidgetPlans bin/trac.cgi/wiki/WidgetPlans

38 Questions ?

Download ppt "3D Slicer Qt Port Julien Finet Kitware Inc. Dec. 16 th 2009."

Similar presentations

Ads by Google