diff --git a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/ExampleViewControls.ui b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/ExampleViewControls.ui
index 37427f6..f96e7ee 100644
--- a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/ExampleViewControls.ui
+++ b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/ExampleViewControls.ui
@@ -1,106 +1,110 @@
ExampleViewControls
0
0
- 220
- 160
+ 227
+ 356
Example View
-
-
-
-
-
-
- Please select an image.
-
-
-
- -
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Offset
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 9999
-
-
-
-
-
-
- -
-
-
- Process selected image
-
-
- Add Offset
-
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 9999
+
+
+
+ -
+
+
+ Process selected image
+
+
+ Add Offset
+
+
+
+ -
+
+
+ Offset
+
+
+
+ -
+
+
+
+
+
+ Image
+
+
+
+ -
+
+
+
+ 0
+ 40
+
+
+
+
+
-
CTRL-click in result images to paint.
true
-
Qt::Vertical
QSizePolicy::Expanding
20
220
+
+
+ QmitkSingleNodeSelectionWidget
+ QWidget
+ QmitkSingleNodeSelectionWidget.h
+ 1
+
+
diff --git a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.cpp b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.cpp
index 9c2fcbe..8b03ff0 100644
--- a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.cpp
+++ b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.cpp
@@ -1,176 +1,151 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include
#include
+#include
+#include
+#include
+#include
+#include
+
#include
#include
#include
#include
#include "QmitkExampleView.h"
namespace
{
// Helper function to create a fully set up instance of our
// ExampleImageInteractor, based on the state machine specified in Paint.xml
// as well as its configuration in PaintConfig.xml. Both files are compiled
- // into ExtExampleModule as resources.
+ // into MitkExampleModule as resources.
static ExampleImageInteractor::Pointer CreateExampleImageInteractor()
{
auto exampleModule = us::ModuleRegistry::GetModule("MitkExampleModule");
if (nullptr != exampleModule)
{
auto interactor = ExampleImageInteractor::New();
interactor->LoadStateMachine("Paint.xml", exampleModule);
interactor->SetEventConfig("PaintConfig.xml", exampleModule);
return interactor;
}
return nullptr;
}
}
// Don't forget to initialize the VIEW_ID.
const std::string QmitkExampleView::VIEW_ID = "org.mitk.views.exampleview";
void QmitkExampleView::CreateQtPartControl(QWidget* parent)
{
// Setting up the UI is a true pleasure when using .ui files, isn't it?
m_Controls.setupUi(parent);
+ m_Controls.selectionWidget->SetDataStorage(this->GetDataStorage());
+ m_Controls.selectionWidget->SetSelectionIsOptional(true);
+ m_Controls.selectionWidget->SetEmptyInfo(QStringLiteral("Select an image"));
+ m_Controls.selectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New(
+ mitk::TNodePredicateDataType::New(),
+ mitk::NodePredicateNot::New(mitk::NodePredicateOr::New(
+ mitk::NodePredicateProperty::New("helper object"),
+ mitk::NodePredicateProperty::New("hidden object")))));
+
// Wire up the UI widgets with our functionality.
+ connect(m_Controls.selectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkExampleView::OnImageChanged);
connect(m_Controls.processImageButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedImage()));
+
+ // Make sure to have a consistent UI state at the very beginning.
+ this->OnImageChanged(m_Controls.selectionWidget->GetSelectedNodes());
}
void QmitkExampleView::SetFocus()
{
m_Controls.processImageButton->setFocus();
}
-void QmitkExampleView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& dataNodes)
+void QmitkExampleView::OnImageChanged(const QmitkSingleNodeSelectionWidget::NodeList&)
{
- for (const auto& dataNode : dataNodes)
- {
- // Write robust code. Always check pointers before using them. If the
- // data node pointer is null, the second half of our condition isn't
- // even evaluated and we're safe (C++ short-circuit evaluation).
- if (dataNode.IsNotNull() && nullptr != dynamic_cast(dataNode->GetData()))
- {
- m_Controls.selectImageLabel->setVisible(false);
- return;
- }
- }
+ this->EnableWidgets(m_Controls.selectionWidget->GetSelectedNode().IsNotNull());
+}
- // Nothing is selected or the selection doesn't contain an image.
- m_Controls.selectImageLabel->setVisible(true);
+void QmitkExampleView::EnableWidgets(bool enable)
+{
+ m_Controls.processImageButton->setEnabled(enable);
}
void QmitkExampleView::ProcessSelectedImage()
{
- // Before we even think about processing something, we need to make sure
- // that we have valid input. Don't be sloppy, this is a main reason
- // for application crashes if neglected.
-
- auto selectedDataNodes = this->GetDataManagerSelection();
-
- if (selectedDataNodes.empty())
- return;
+ auto selectedDataNode = m_Controls.selectionWidget->GetSelectedNode();
+ auto data = selectedDataNode->GetData();
- auto firstSelectedDataNode = selectedDataNodes.front();
+ // We don't use the auto keyword here, which would evaluate to a native
+ // image pointer. Instead, we want a smart pointer to ensure that
+ // the image isn't deleted somewhere else while we're using it.
+ mitk::Image::Pointer image = dynamic_cast(data);
- if (firstSelectedDataNode.IsNull())
- {
- QMessageBox::information(nullptr, "Example View", "Please load and select an image before starting image processing.");
- return;
- }
-
- auto data = firstSelectedDataNode->GetData();
-
- // Something is selected, but does it contain data?
- if (data != nullptr)
- {
- // We don't use the auto keyword here, which would evaluate to a native
- // image pointer. Instead, we want a smart pointer in order to ensure that
- // the image isn't deleted somewhere else while we're using it.
- mitk::Image::Pointer image = dynamic_cast(data);
+ auto imageName = selectedDataNode->GetName();
+ auto offset = m_Controls.offsetSpinBox->value();
- // Something is selected and it contains data, but is it an image?
- if (image.IsNotNull())
- {
- auto imageName = firstSelectedDataNode->GetName();
- auto offset = m_Controls.offsetSpinBox->value();
-
- MITK_INFO << "Process image \"" << imageName << "\" ...";
-
- // We're finally using the ExampleImageFilter from ExtExampleModule.
- auto filter = ExampleImageFilter::New();
- filter->SetInput(image);
- filter->SetOffset(offset);
+ MITK_INFO << "Process image \"" << imageName << "\" ...";
- filter->Update();
+ // We're finally using the ExampleImageFilter from MitkExampleModule.
+ auto filter = ExampleImageFilter::New();
+ filter->SetInput(image);
+ filter->SetOffset(offset);
- mitk::Image::Pointer processedImage = filter->GetOutput();
+ filter->Update();
- if (processedImage.IsNull() || !processedImage->IsInitialized())
- return;
+ mitk::Image::Pointer processedImage = filter->GetOutput();
- MITK_INFO << " done";
+ if (processedImage.IsNull() || !processedImage->IsInitialized())
+ return;
- // Stuff the resulting image into a data node, set some properties,
- // and add it to the data storage, which will eventually display the
- // image in the application.
- auto processedImageDataNode = mitk::DataNode::New();
- processedImageDataNode->SetData(processedImage);
+ MITK_INFO << " done";
- QString name = QString("%1 (Offset: %2)").arg(imageName.c_str()).arg(offset);
- processedImageDataNode->SetName(name.toStdString());
+ // Stuff the resulting image into a data node, set some properties,
+ // and add it to the data storage, which will eventually display the
+ // image in the application.
+ auto processedImageDataNode = mitk::DataNode::New();
+ processedImageDataNode->SetData(processedImage);
- // We don't really need to copy the level window, but if we wouldn't
- // do it, the new level window would be initialized to display the image
- // with optimal contrast in order to capture the whole range of pixel
- // values. This is also true for the input image as long as one didn't
- // modify its level window manually. Thus, the images would appear
- // identical unless you compare the level window widget for both images.
- mitk::LevelWindow levelWindow;
+ QString name = QString("%1 (Offset: %2)").arg(imageName.c_str()).arg(offset);
+ processedImageDataNode->SetName(name.toStdString());
- if (firstSelectedDataNode->GetLevelWindow(levelWindow))
- processedImageDataNode->SetLevelWindow(levelWindow);
+ // We don't really need to copy the level window, but if we wouldn't
+ // do it, the new level window would be initialized to display the image
+ // with optimal contrast in order to capture the whole range of pixel
+ // values. This is also true for the input image as long as one didn't
+ // modify its level window manually. Thus, the images would appear
+ // identical unless you compare the level window widget for both images.
+ mitk::LevelWindow levelWindow;
- // We also attach our ExampleImageInteractor, which allows us to paint
- // on the resulting images by using the mouse as long as the CTRL key
- // is pressed.
- auto interactor = CreateExampleImageInteractor();
+ if (selectedDataNode->GetLevelWindow(levelWindow))
+ processedImageDataNode->SetLevelWindow(levelWindow);
- if (interactor.IsNotNull())
- interactor->SetDataNode(processedImageDataNode);
+ // We also attach our ExampleImageInteractor, which allows us to paint
+ // on the resulting images by using the mouse as long as the CTRL key
+ // is pressed.
+ auto interactor = CreateExampleImageInteractor();
- this->GetDataStorage()->Add(processedImageDataNode);
- }
- }
+ if (interactor.IsNotNull())
+ interactor->SetDataNode(processedImageDataNode);
- // Now it's your turn. This class/method has lots of room for improvements,
- // for example:
- //
- // - What happens when multiple items are selected but the first one isn't
- // an image? - There isn't any feedback for the user at all.
- // - What's the front item of a selection? Does it depend on the order
- // of selection or the position in the Data Manager? - Isn't it
- // better to process all selected images? Don't forget to adjust the
- // titles of the UI widgets.
- // - In addition to the the displayed label, it's probably a good idea to
- // enable or disable the button depending on the selection.
+ this->GetDataStorage()->Add(processedImageDataNode);
}
diff --git a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.h b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.h
index f84d5df..658f7e3 100644
--- a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.h
+++ b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/QmitkExampleView.h
@@ -1,65 +1,63 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef QmitkExampleView_h
#define QmitkExampleView_h
#include
#include
+#include
// There's an item "ExampleViewControls.ui" in the UI_FILES list in
// files.cmake. The Qt UI Compiler will parse this file and generate a
// header file prefixed with "ui_", which is located in the build directory.
// Use Qt Creator to view and edit .ui files. The generated header file
// provides a class that contains all of the UI widgets.
#include
// All views in MITK derive from QmitkAbstractView. You have to override
// at least the two methods CreateQtPartControl() and SetFocus().
class QmitkExampleView : public QmitkAbstractView
{
// As ExampleView derives from QObject and we want to use the Qt
// signal and slot mechanism, we must not forget the Q_OBJECT macro.
// This header file also has to be listed in MOC_H_FILES in files.cmake
// so that the Qt Meta-Object compiler can find and process this
// class declaration.
Q_OBJECT
public:
// This is a tricky one and will give you some headache later on in
// your debug sessions if it has been forgotten. Also, don't forget
// to initialize it in the implementation file.
static const std::string VIEW_ID;
// In this method we initialize the GUI components and connect the
// associated signals and slots.
void CreateQtPartControl(QWidget* parent) override;
private slots:
+ void OnImageChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes);
void ProcessSelectedImage();
private:
// Typically a one-liner. Set the focus to the default widget.
void SetFocus() override;
- // This method is conveniently called whenever the selection of Data Manager
- // items changes.
- void OnSelectionChanged(
- berry::IWorkbenchPart::Pointer source,
- const QList& dataNodes) override;
+ void EnableWidgets(bool enable);
// Generated from the associated UI file, it encapsulates all the widgets
// of our view.
Ui::ExampleViewControls m_Controls;
};
#endif