Преглед на файлове

ENH: Added editable, minimum, maximum, decimal and singleStep properties to ctkMatrixWidget

- editable: If true, user can edit matrix elements (uses spinbox to edit each QTableWidgetItem).
- minimum: The minimum allowed value for a matrix element.
- maximum: The maximum allowed value for a matrix element.
- decimal: The precision of the spinbox used to edit matrix elements.
- singleStep: The single step value of the spinbox used to edit matrix elements.
Danielle Pace преди 14 години
родител
ревизия
f8457da0ed
променени са 2 файла, в които са добавени 199 реда и са изтрити 8 реда
  1. 149 6
      Libs/Widgets/ctkMatrixWidget.cpp
  2. 50 2
      Libs/Widgets/ctkMatrixWidget.h

+ 149 - 6
Libs/Widgets/ctkMatrixWidget.cpp

@@ -27,13 +27,47 @@
 #include <QVariant>
 #include <QTableWidgetItem>
 #include <QResizeEvent>
+#include <QDoubleSpinBox>
+#include <QItemEditorFactory>
+#include <QStyledItemDelegate>
 #include <QDebug>
 
 //-----------------------------------------------------------------------------
+// Custom item editors
+
+namespace
+{
+//-----------------------------------------------------------------------------
+  class CustomDoubleSpinBox : public QDoubleSpinBox
+  {
+  public:
+    CustomDoubleSpinBox(QWidget * newParent):QDoubleSpinBox(newParent)
+    {
+      // We know that the parentWidget of newParent will be a ctkMatrixWidget because this object is
+      // created by the QItemEditorFactory
+      ctkMatrixWidget* matrixWidget = qobject_cast<ctkMatrixWidget*>(newParent->parentWidget());
+      Q_ASSERT(matrixWidget);
+      
+      this->setMinimum(matrixWidget->minimum());
+      this->setMaximum(matrixWidget->maximum());
+      this->setDecimals(matrixWidget->decimals());
+      this->setSingleStep(matrixWidget->singleStep());
+    }
+  };
+}
+
+//-----------------------------------------------------------------------------
 class ctkMatrixWidgetPrivate: public ctkPrivate<ctkMatrixWidget>
 {
 public:
   void init();
+  void validateElements();
+
+  // Parameters for the spinbox used to change the value of matrix elements
+  double Minimum;
+  double Maximum;
+  int Decimals;
+  double SingleStep;
 };
 
 //-----------------------------------------------------------------------------
@@ -41,7 +75,13 @@ void ctkMatrixWidgetPrivate::init()
 {
   CTK_P(ctkMatrixWidget);
   // Set Read-only
-  p->setEditTriggers(ctkMatrixWidget::NoEditTriggers);
+  p->setEditable(false);
+
+  // Set parameters for the spinbox
+  this->Minimum = -100;
+  this->Maximum = 100;
+  this->Decimals = 2;
+  this->SingleStep = 0.01;
 
   // Hide headers
   p->verticalHeader()->hide();
@@ -57,6 +97,15 @@ void ctkMatrixWidgetPrivate::init()
   // Disable the frame by default
   p->setFrameStyle(QFrame::NoFrame);
 
+  // Register custom editors
+  QItemEditorFactory *editorFactory = new QItemEditorFactory;
+  editorFactory->registerEditor(QVariant::Double, new QStandardItemEditorCreator<CustomDoubleSpinBox>);
+
+  QStyledItemDelegate* defaultItemDelegate =
+    qobject_cast<QStyledItemDelegate*>(p->itemDelegate());
+  Q_ASSERT(defaultItemDelegate);
+  defaultItemDelegate->setItemEditorFactory(editorFactory);
+
   // Define prototype item
   QTableWidgetItem* _item = new QTableWidgetItem();
   _item->setData(Qt::DisplayRole, QVariant(0.0));
@@ -70,6 +119,27 @@ void ctkMatrixWidgetPrivate::init()
 }
 
 // --------------------------------------------------------------------------
+void ctkMatrixWidgetPrivate::validateElements()
+{
+  CTK_P(ctkMatrixWidget);
+  for (int i=0; i < p->rowCount(); i++)
+    {
+    for (int j=0; j < p->columnCount(); j++)
+      {
+      double value = p->item(i, j)->data(Qt::DisplayRole).toDouble();
+      if (value < this->Minimum)
+        {
+        p->item(i,j)->setData(Qt::DisplayRole, QVariant(this->Minimum));
+        }
+      if (value > this->Maximum)
+        {
+        p->item(i,j)->setData(Qt::DisplayRole, QVariant(this->Maximum));
+        }
+      }
+    }
+}
+
+// --------------------------------------------------------------------------
 ctkMatrixWidget::ctkMatrixWidget(QWidget* _parent) : Superclass(4, 4, _parent)
 {
   CTK_INIT_PRIVATE(ctkMatrixWidget);
@@ -87,7 +157,59 @@ ctkMatrixWidget::ctkMatrixWidget(int rows, int columns, QWidget* _parent)
 }
 
 // --------------------------------------------------------------------------
-QSize ctkMatrixWidget::minimumSizeHint () const
+bool ctkMatrixWidget::editable()const
+{
+  return this->editTriggers();
+}
+
+// --------------------------------------------------------------------------
+void ctkMatrixWidget::setEditable(bool newEditable)
+{
+  if (newEditable)
+    {
+    this->setEditTriggers(ctkMatrixWidget::DoubleClicked);
+    }
+  else
+    {
+    this->setEditTriggers(ctkMatrixWidget::NoEditTriggers);
+    }
+}
+
+// --------------------------------------------------------------------------
+CTK_GET_CXX(ctkMatrixWidget, double, minimum, Minimum);
+CTK_GET_CXX(ctkMatrixWidget, double, maximum, Maximum);
+CTK_GET_CXX(ctkMatrixWidget, double, singleStep, SingleStep);
+CTK_SET_CXX(ctkMatrixWidget, double, setSingleStep, SingleStep);
+CTK_GET_CXX(ctkMatrixWidget, int, decimals, Decimals);
+CTK_SET_CXX(ctkMatrixWidget, int, setDecimals, Decimals);
+
+// --------------------------------------------------------------------------
+void ctkMatrixWidget::setMinimum(double newMinimum)
+{
+  CTK_D(ctkMatrixWidget);
+  d->Minimum = newMinimum;
+  d->validateElements();
+}
+
+// --------------------------------------------------------------------------
+void ctkMatrixWidget::setMaximum(double newMaximum)
+{
+  CTK_D(ctkMatrixWidget);
+  d->Maximum = newMaximum;
+  d->validateElements();
+}
+
+// --------------------------------------------------------------------------
+void ctkMatrixWidget::setRange(double newMinimum, double newMaximum)
+{
+  CTK_D(ctkMatrixWidget);
+  d->Minimum = newMinimum;
+  d->Maximum = newMaximum;
+  d->validateElements();
+}
+
+// --------------------------------------------------------------------------
+QSize ctkMatrixWidget::minimumSizeHint() const
 {
   int maxWidth = this->sizeHintForColumn(0);
   for (int j = 1; j < this->columnCount(); ++j)
@@ -103,7 +225,7 @@ QSize ctkMatrixWidget::minimumSizeHint () const
 }
 
 // --------------------------------------------------------------------------
-QSize ctkMatrixWidget::sizeHint () const
+QSize ctkMatrixWidget::sizeHint() const
 {
   return this->minimumSizeHint();
 }
@@ -142,6 +264,7 @@ void ctkMatrixWidget::updateGeometries()
 // --------------------------------------------------------------------------
 void ctkMatrixWidget::reset()
 {
+  CTK_D(ctkMatrixWidget);
   // Initialize 4x4 matrix
   for (int i=0; i < this->rowCount(); i++)
     {
@@ -150,7 +273,18 @@ void ctkMatrixWidget::reset()
       this->setItem(i, j, this->itemPrototype()->clone());
       if (i == j)
         {
-        this->setValue(i, j, 1);
+        if (d->Maximum < 1.0)
+          {
+          this->setValue(i, j, d->Maximum);
+          }
+        else if (d->Minimum > 1.0)
+          {
+          this->setValue(i, j, d->Minimum);
+          }
+        else
+          {
+          this->setValue(i, j, 1.0);
+          }
         }
       }
     }
@@ -168,20 +302,29 @@ double ctkMatrixWidget::value(int i, int j)const
 // --------------------------------------------------------------------------
 void ctkMatrixWidget::setValue(int i, int j, double _value)
 {
+  CTK_D(ctkMatrixWidget);
   Q_ASSERT( i>=0 && i<this->rowCount() &&
             j>=0 && j<this->columnCount());
 
-  this->item(i, j)->setData(Qt::DisplayRole, QVariant(_value));
+  if (_value >= d->Minimum && _value <= d->Maximum)
+    {
+    this->item(i, j)->setData(Qt::DisplayRole, QVariant(_value));
+    }
 }
 
 // --------------------------------------------------------------------------
 void ctkMatrixWidget::setVector(const QVector<double> & vector)
 {
+  CTK_D(ctkMatrixWidget);
   for (int i=0; i < this->rowCount(); i++)
     {
     for (int j=0; j < this->columnCount(); j++)
       {
-      this->item(i,j)->setData(Qt::DisplayRole, QVariant(vector.at(i * this->columnCount() + j)));
+      double value = vector.at(i * this->columnCount() + j);
+      if  (value >= d->Minimum && value <= d->Maximum)
+        {
+        this->item(i,j)->setData(Qt::DisplayRole, QVariant(value));
+        }
       }
     }
 }

+ 50 - 2
Libs/Widgets/ctkMatrixWidget.h

@@ -32,13 +32,18 @@ class ctkMatrixWidgetPrivate;
 
 ///
 /// ctkMatrixWidget is the base class of matrix widgets.
-/// \todo Add a property to handle wether the user can edit values
 /// \todo Wrap model signals to emit signals when the matrix is changed.
 /// Right now you can connect to the signal:
 /// matrixWidget->model()->dataChanged(...)
 class CTK_WIDGETS_EXPORT ctkMatrixWidget : public QTableWidget
 {
   Q_OBJECT
+  Q_PROPERTY(bool editable READ editable WRITE setEditable)
+  Q_PROPERTY(double minimum READ minimum WRITE setMinimum)
+  Q_PROPERTY(double maximum READ maximum WRITE setMaximum)   
+  Q_PROPERTY(int decimals READ decimals WRITE setDecimals)
+  Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep)
+
 public:
   /// Superclass typedef
   typedef QTableWidget Superclass;
@@ -52,13 +57,56 @@ public:
   ///
   /// Set / Get values of the matrix
   /// \li i is the row index, \li j is the column index
-  /// \warning there is no check that the indexes are inside their
+  /// \warning There is no check that the indexes are inside their
   /// valid range
+  /// \warning The value of a matrix element will not be changed on an attempt to set it to a value
+  /// that is less than the minimum or greater than the maximum.
   double value(int i, int j)const;
   void setValue(int i, int j, double value);
   void setVector(const QVector<double> & vector);
 
   ///
+  /// This property determines whether the user can edit values
+  bool editable()const;
+  void setEditable(bool newEditable);
+
+  /// 
+  /// This property holds the minimum value of matrix elements.
+  ///
+  /// Any matrix elements whose values are less than the new minimum value will be reset to equal
+  /// the new minimum value.
+  double minimum()const;
+  void setMinimum(double newMinimum);
+  
+  /// 
+  /// This property holds the maximum value of matrix elements.
+  ///
+  /// Any matrix elements whose values are greater than the new maximum value will be reset to equal
+  /// the new maximum value.
+  double maximum()const;
+  void setMaximum(double newMaximum);
+
+  /// Description
+  /// Utility function that sets the min/max at once.
+  void setRange(double newMinimum, double newMaximum);
+
+  /// 
+  /// This property holds the step value of the spinbox.
+  ///
+  /// When the user uses the arrows to change the value of the spinbox used to adjust the value of
+  /// a matrix element, the value will be incremented/decremented by the amount of the singleStep.
+  double singleStep()const;
+  void setSingleStep(double step);
+
+  /// 
+  /// This property holds the precision of the spinbox, in decimals.
+  ///
+  /// Dictates how many decimals will be used for displaying and interpreting doubles by the spinbox
+  /// used to adjust the value of a matrix element.
+  int decimals()const;
+  void setDecimals(int decimals);
+
+  ///
   /// Reimplemented from QAbstractScrollArea
   virtual QSize minimumSizeHint () const;
   virtual QSize sizeHint () const;