QTableView可以使用QItemDelegate设置整行整列的编辑行为模式。
在createEditor中返回重新设计的widget就可以在表格进入编辑状态时在单元格中使用该widget。表格编辑状态的进入方式由editTriggers控制。
想在表格中加入一列可弹出下拉列表的选项框,效果如下图所示。显示多选框,单击单元格弹出下拉选项。
直接添加QComboBox作为editor返回的情况是,平常是正常显示表格,不会出现ComboBox,要点击相应的单元格,进入编辑状态,ComboBox才会出现,然后再点击ComboBox才会出现下拉框选项。
要一直显示ComboBox必须在paint函数中绘制出来,显示静态的样式文字信息。
要实现进入编辑模式就弹出下拉框选项,在updateEditorGeometry函数中手动弹出。在updateEditorGeometry之前,控件并没有关联对应的表格单元格,所以如果在createEditor时就弹出下拉框,其位置是不会跟随单元格的。
// delegate.h
class itemdelegate_combo : public QItemDelegate
{
Q_OBJECT
public:
explicit itemdelegate_combo(QObject *parent = nullptr);
QWidget *createEditor(QWidget *, const QStyleOptionViewItem &, const QModelIndex &) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void set_items(QStringList strl){m_sItemList = strl;}
protected:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
QStringList m_sItemList; //下拉框列表项
};
// delegate.cpp
itemdelegate_combo::itemdelegate_combo(QObject *parent):
QItemDelegate(parent)
{
}
QWidget *itemdelegate_combo::createEditor(QWidget *parent,const QStyleOptionViewItem &/*option*/,const QModelIndex &index) const
{
QComboBox *item_w = new QComboBox(parent);
item_w->setStyle(new combo_style());
item_w->addItems(m_sItemList);
return item_w;
}
void itemdelegate_combo::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &/*index*/) const
{
editor->setGeometry(option.rect);
if (QComboBox *editor_combo = static_cast<QComboBox *>(editor))
{
editor_combo->showPopup();
}
}
void itemdelegate_combo::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
combo_style combostyle;
QStyleOptionComboBox combooption;
combooption.rect = option.rect;
combostyle.drawComplexControl(QStyle::CC_ComboBox,&combooption, painter);
}
ComboBox的样式由QStyle设定。
// combo_style.h
class combo_style : public QProxyStyle
{
Q_OBJECT
public:
combo_style(){}
void drawComplexControl(ComplexControl which,const QStyleOptionComplex *option,QPainter *painter,const QWidget *widget = nullptr) const override;
QRect subControlRect(ComplexControl whichControl,const QStyleOptionComplex *option,SubControl whichSubControl,const QWidget *widget = nullptr) const override;
void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override;
void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p, const QWidget *widget) const override;
};
// combo_style.cpp
void combo_style::drawComplexControl(ComplexControl which,const QStyleOptionComplex *option,QPainter *painter,const QWidget *widget) const
{
if (which == CC_ComboBox)
{
if(const QStyleOptionComboBox * cbOption = qstyleoption_cast<const QStyleOptionComboBox *>(option))
{
painter->save();
QRect rect = subControlRect(CC_ComboBox, option,SC_ComboBoxFrame).adjusted(+1, +1, -1, -1);
painter->translate(option->rect.x(),option->rect.y());
// painter->setBrush(QColor("#128bf1"));
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::NoBrush);
painter->drawRect(rect);
rect = subControlRect(CC_ComboBox, option,SC_ComboBoxEditField).adjusted(+2, +2, -2, -2);
painter->setPen(Qt::NoPen);
painter->setBrush(Qt::white);
painter->drawRect(rect);
rect = subControlRect(CC_ComboBox, option,SC_ComboBoxArrow).adjusted(+1, +1, -1, -1);
QLinearGradient gradient2(rect.topLeft(),rect.bottomRight());
gradient2.setColorAt(0.0, QColor("#84fab0"));
gradient2.setColorAt(1.0, QColor("#8fd3f4"));
painter->setBrush(gradient2);
painter->setPen(Qt::NoPen);
painter->drawRect(rect);
painter->restore();
QStyleOption arrowOpt(*cbOption);
arrowOpt.rect = rect.adjusted(+rect.width() * 0.3, +rect.height() * 0.3,
-rect.width() * 0.3, -rect.height() * 0.3);
arrowOpt.rect = arrowOpt.rect.adjusted(+option->rect.x(), +option->rect.y(),
+option->rect.x(), +option->rect.y());
drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, painter,widget);
}
}
else
{
QProxyStyle::drawComplexControl(which, option, painter,widget);
}
}
QRect combo_style::subControlRect(ComplexControl whichControl,const QStyleOptionComplex *option,SubControl whichSubControl,const QWidget *widget) const
{
if (whichControl == CC_ComboBox)
{
switch (whichSubControl)
{
case SC_ComboBoxEditField:
return QRect(0,0,option->rect.width() * 0.5,option->rect.height()).adjusted(+2, +2, -2, -2);
case SC_ComboBoxFrame:
return QRect(0,0,option->rect.width() * 0.5,option->rect.height());
case SC_ComboBoxArrow:
return QRect(int(option->rect.width() * 0.5), 0, int(option->rect.width() * 0.5), int(option->rect.height()));
default:
return QProxyStyle::subControlRect(whichControl, option,whichSubControl, widget);
}
}
else
{
return QProxyStyle::subControlRect(whichControl, option,whichSubControl, widget);
}
}
void combo_style::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
switch (element)
{
case PE_IndicatorArrowDown:
{
qDebug() << "arrow draw" << option->rect;
painter->save();
painter->translate(option->rect.x(),option->rect.y());
QPainterPath drawtriangle; //画三角形
drawtriangle.moveTo(0,0);
drawtriangle.lineTo(option->rect.width()/2,option->rect.height());
drawtriangle.lineTo(option->rect.width(),0);
drawtriangle.lineTo(0,0);
painter->setPen(QPen(QColor("#128bf1"), 2));
painter->drawPath(drawtriangle); //绘制出图形
painter->restore();
}
break;
default:
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
}
ComboBox绘制参考自:
QT风格(QStyle):绘制一个自定义QComboBox