QStyledItemDelegate - Как работает updateEditorGeometry? - PullRequest
5 голосов
/ 28 марта 2011

Я использую Qt 4.7.

У меня есть модель, которую я отображаю в QTableView в двух столбцах, и моя цель - обеспечить встроенное редактирование этой модели в моем QTableView.

+-----------------+----------------+
|  Axis position  |  Axis range    |
+-----------------+----------------+
|      Left       | Fixed [0,1]    |
|      Left       | Source: SRC1   |
|      Right      | Source: SRC2   |
|      Left       | Fixed [5,10]   |
+-----------------+----------------+

Первый столбец редактируется с помощью простого QComboxBox для переключения между правым и левым, и он работает довольно хорошо. Проблема в моем втором столбце, который можно редактировать с помощью пользовательского виджета.

Этот виджет довольно прост, он описывает диапазон. Таким образом, есть QComboBox для выбора типа диапазона («Фиксированный»: значения задаются пользователем, «Источник»: значение корректируется динамически от минимального / максимального значения источника).

Вот исходный код моего пользовательского виджета:

class RangeEditor : public QWidget
{
  Q_OBJECT

public:
  RangeEditor( ... );
  ~RangeEditor();

public:
  CurveView::ConfigAxes::Range range  () const;
  QVariant                     minimum() const;
  QVariant                     maximum() const;
  DataModel*                   model  () const;

  void range  ( CurveView::ConfigAxes::Range range );
  void minimum( QVariant minimum );
  void maximum( QVariant maximum );
  void model  ( DataModel* model );

public slots:
  void rangeTypeChanged( int type );

private: // --- External editors
  QComboBox* editRange_;
  QSpinBox*  editMinimum_;
  QSpinBox*  editMaximum_;
  QComboBox* editModel_;
};

RangeEditor::RangeEditor( ... ) : QWidget(parent)
{
  editRange_   = new QComboBox(this);
  editMinimum_ = new QSpinBox (this);
  editMaximum_ = new QSpinBox (this);
  editModel_   = new QComboBox(this);

  QHBoxLayout* layout = new QHBoxLayout();
  setLayout(layout);

  layout->addWidget( editRange_   );
  layout->addWidget( editMinimum_ );
  layout->addWidget( editMaximum_ );
  layout->addWidget( editModel_   );

  editRange_->addItem( "Fixed"  );
  editRange_->addItem( "Source" );

  editModel_->setCurrentIndex(0);    
  editModel_->hide();

  QObject::connect( editRange_, SIGNAL(currentIndexChanged(int)),
                    this,       SLOT  (rangeTypeChanged(int)) );
}

void RangeEditor::rangeTypeChanged( int type )
{
  if ( type==CurveView::ConfigAxes::FIXED )
  {
    editMinimum_->show();
    editMaximum_->show();
    editModel_->hide();
  }
  else if ( type==CurveView::ConfigAxes::SOURCE )
  {
    editMinimum_->hide();
    editMaximum_->hide();
    editModel_->show();
  }
}

Хорошо, теперь я создал QStyledItemDelegate, чтобы обеспечить представление пользовательского редактора для моих столбцов. Вот как я это сделал:

class ConfigAxesDelegate : public QStyledItemDelegate
{
public:
  ConfigAxesDelegate( ... );
  ~ConfigAxesDelegate();

public:
  virtual QWidget* createEditor        ( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
  virtual void     setEditorData       ( QWidget* editor, const QModelIndex& index ) const;
  virtual void     setModelData        ( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const;
  virtual void     updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
};

QWidget* ConfigAxesDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
  if ( index.column()==0 ) // Position
  {
    PositionEditor* editor = new PositionEditor(parent);
    return editor;
  }
  else if ( index.column()==1 ) // Range
  {
    RangeEditor* editor = new RangeEditor(parent);   
    return editor;
  }
  else
  {
    return QStyledItemDelegate::createEditor(parent,option,index);
  }
}

void ConfigAxesDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
  // WHAT TO DO HERE?
  editor->setGeometry( option.rect );
}

По сути, я получаю редактор высоты в один пиксель.

Вот скриншот с результатом: Screenshot1

Я пытался изменить updateEditorGeometry на следующее:

void ConfigAxesDelegate::updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
  QRect r = option.rect;
  r.setSize( editor->sizeHint() );
  editor->setGeometry( r );
}

Что, похоже, решает проблему размера, но не позиции: enter image description here

Я чувствую себя немного растерянным, так как я не знаю, происходит ли проблема из моего пользовательского виджета (не предоставляющего достаточно информации для Qt, чтобы правильно рассчитать его позицию) или из вида (возможно, некоторые поля, которые могут повлиять на размер редактора) или метод updateEditorGeometry().

Любая помощь с благодарностью, спасибо за чтение!

1 Ответ

11 голосов
/ 29 марта 2011

Я бы сказал, установив геометрию редактора, вызвав:

editor->setGeometry(rect);

должно работать правильно; В вашем случае происходит то, что ваш редактор построен с использованием QHBoxLayout, который имеет поля по умолчанию и интервалы. Высота по умолчанию для ваших строк табличного представления меньше высоты редактора, и это заставляет ваш редактор изменять размер; одна строка пикселей на снимке экрана будет выглядеть так: верхнее поле + то, что осталось от элементов управления + нижнее поле.

Включив вертикальный заголовок для таблицы, вы сможете изменить высоту строки, чтобы сделать элементы управления редактора полностью видимыми.

Что вы могли бы сделать:

1.Удалить \ уменьшить интервалы и поля для макета:

QHBoxLayout* layout = new QHBoxLayout();
layout->setSpacing(1);
layout->setMargin(1);
setLayout(layout);

в этом случае, обновляя геометрию редактора следующим образом:

QRect rect = option.rect;
QSize sizeHint = editor->sizeHint();

if (rect.width()<sizeHint.width()) rect.setWidth(sizeHint.width());
if (rect.height()<sizeHint.height()) rect.setHeight(sizeHint.height());

editor->setGeometry(rect);

или просто

editor->setGeometry(rect);

должен нормально работать для вас

2.Вы также можете использовать всплывающие редакторы для значений строк \ ячеек

3. Измените высоту строк виджета, чтобы они соответствовали редакторам ячеек.

надеюсь, это поможет, с уважением

...