QStyledItemDelegate - updateEditorGeometry如何工作?

7

我正在使用Qt 4.7。

我有一个模型,我将其在两列中显示在QTableView中,我的目标是在QTableView中提供此模型的内联编辑。

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

第一列可以使用简单的 QComboxBox 切换 Right 和 Left 来进行编辑,这种方式非常有效。但是我出现了问题,因为我的第二列使用了自定义小部件来进行编辑。
这个小部件有点简单,它描述了一个范围。所以有一个 QComboBox 来选择范围类型 ("Fixed": 值由用户给定, "Source": 值根据源的最小值和最大值动态调整)。
以下是我自定义小部件的源代码:
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个回答

13
我会建议通过调用以下方式来设置编辑器的几何形状:

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.调整小部件的行高以适合单元格编辑器。

希望这能帮到您,祝好。


清晰的答案,附带源代码。非常有效(我使用了你的解决方案1)。你真的救了我的一天,非常感谢! - NewbiZ
大家好,我有一段类似的代码,但是如果矩形比之前的矩形更大,则不起作用。我的编辑器是一个简单的行编辑器,但它只会水平缩小而不会扩展。有什么想法吗? - mhstnsc
@mhstnsc请将其作为一个新问题打开。 - eric
@neuronet 嗯,这个项目已经解决了这个问题,现在我不需要答案了。我们试图尽可能远离Qt Gui,因为我认为它很邪恶。我们将核心逻辑保留在Qt中,但使用C#显示UI。 - mhstnsc
我认为需要注意的是,如果你有一个布局,那么边距可能是问题的原因,正如我在这里发现的:http://www.qtcentre.org/threads/53772-How-to-create-a-QStyledItemDelegate-made-of-two-QDoubleSpinBox-widgets - eTHP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接