So what I have here is my delegate code for a QAbstractTableModel
. The 2nd column (index = 1), is always a comboBox
. That comboBox
has a list of actions that a given Unit in my simulation can perform. Upon clicking certain actions like Build or Train, I want a Dialog to pop up giving the user a set of choices. After making there choice, the delegate is supposed to update the model's data and move on.
Here is the snag I've run into. If I try to call a dialog from setModelData()
, setEditorData()
, those functions are const
so I can't assign the r开发者_如何学Goesults of the dialog to anything.
What I have tried to do is to connect the signal indexChanged(QString)
from the QComboBox
created in createEditor()
. This at least allowed me to assign the result and call the dialog only when the appropriate choice was made. However I keep getting a seggy fault and the trace in QTCreator
will not land on C code (33 calls of assembly). I'm unsure as to why I got that seggy.
When I tried that approach, the table no longer had the combobox
once the dialog appeared. It reverted to its previous state and as soon as the program left the slot I made for QComboBox::indexChanged(QString)
, the seggy happened.
DelegateAction.h
#ifndef DELEGATEACTION_H
#define DELEGATEACTION_H
#include <QVariant>
#include <QStyledItemDelegate>
#include <QString>
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QComboBox>
#include <QProgressBar>
#include <QMouseEvent>
#include <JECMessageTable.h>
#include <UnitBase.h>
#include <ModelListUnit.h>
class DelegateAction : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit DelegateAction(QObject *parent = 0);
~DelegateAction();
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
public slots:
void setUnits(QList<Unit*>* units);
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
//bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
private slots:
void comboChanged(QString string);
void comboDestroyed();
private:
bool comboUpdated;
const UnitBase* selectedUnit;
ModelListUnit *model; // The model for the JECMessageTable.
QList<Unit*>* units; // The current list of units.
};
#endif // DELEGATEACTION_H
DelegateAction.cpp
#include "DelegateAction.h"
DelegateAction::DelegateAction(QObject *parent) :
QStyledItemDelegate(parent),
selectedUnit(0),
model(0)
{
}
DelegateAction::~DelegateAction()
{
delete model;
}
QWidget * DelegateAction::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QWidget* editor = 0;
switch (index.column())
{
case 0:
default:
{
editor = new QLabel();
break;
}
case 1:
{
QComboBox* combo = new QComboBox(parent);
combo->addItem("Idle");
combo->addItem("Gather");
combo->addItem("Train");
combo->addItem("Build");
combo->addItem("Upgrade");
editor = combo;
// connect(combo, SIGNAL(currentIndexChanged(QString)), this, SLOT(comboChanged(QString)));
// connect(combo, SIGNAL(destroyed()), this, SLOT(comboDestroyed()));
break;
}
case 4:
{
editor = new QProgressBar(parent);
break;
}
}
editor->installEventFilter(const_cast<DelegateAction*>(this));
return editor;
}
void DelegateAction::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QVariant value = index.model()->data(index, Qt::DisplayRole);
switch (index.column())
{
case 0:
default:
{
QLabel* label = static_cast<QLabel*>(editor);
label->setText(value.toString());
break;
}
case 1:
{
QComboBox* combo = static_cast<QComboBox*>(editor);
combo->setCurrentIndex(combo->findText(value.toString()));
break;
}
case 4:
{
QProgressBar* progress = static_cast<QProgressBar*>(editor);
progress->setValue(value.toInt());
break;
}
}
}
void DelegateAction::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QVariant value;
switch (index.column())
{
case 0:
default:
{
value = static_cast<QLabel*>(editor)->text();
break;
}
case 1:
{
QString string = static_cast<QComboBox*>(editor)->currentText();
switch (Action::getType(string))
{
case Action::INVALID:
{
return;
}
case Action::IDLE:
{
return;
}
case Action::GATHER:
{
return;
}
case Action::BUILD:
{
return;
}
case Action::TRAIN:
{
// Summon the build choice dialog.
if (units == 0)
{
return;
}
JECMessageTable messageBox(this->model, "Test");
messageBox.exec();
if (messageBox.result() == QDialog::Accepted)
{
//selectedUnit = this->model->getSelectedUnit();
}
else
{
//selectedUnit = 0;
}
return;
}
case Action::MORPH:
{
return;
}
case Action::UPGRADE:
{
}
}
break;
}
case 4:
{
value = static_cast<QProgressBar*>(editor)->value();
break;
}
}
model->setData(index, value);
}
void DelegateAction::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
editor->setGeometry(option.rect);
}
QSize DelegateAction::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (index.column() == 4)
{
return QSize(option.rect.width(), option.rect.height());
}
else
{
return QStyledItemDelegate::sizeHint(option, index);
}
}
void DelegateAction::paint(QPainter *painter, const QStyleOptionViewItem &item, const QModelIndex &index) const
{
if (index.column() == 4 && index.isValid() == true)
{
QStyleOptionProgressBarV2 progress;
progress.minimum = 0;
progress.maximum = 100;
progress.progress = index.data().toInt();
progress.rect = QRect(item.rect.x(), item.rect.y(), item.rect.width(), item.rect.height());
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progress, painter);
}
else
{
// Painting the cells normally.
QStyledItemDelegate::paint(painter, item, index);
}
}
void DelegateAction::setUnits(QList<Unit*> *units)
{
this->units = units;
if (units != 0)
{
if (units->length() > 0)
{
model = new ModelListUnit(&units->at(0)->getUnitBase()->getOptionUnit());
}
}
}
void DelegateAction::comboChanged(QString string)
{
// comboUpdated = true;
// switch (Action::getType(string))
// {
// case Action::INVALID:
// {
// return;
// }
// case Action::IDLE:
// {
// return;
// }
// case Action::GATHER:
// {
// return;
// }
// case Action::BUILD:
// {
// return;
// }
// case Action::TRAIN:
// {
// // Summon the build choice dialog.
// if (units == 0)
// {
// return;
// }
// JECMessageTable messageBox(model, "Test");
// messageBox.exec();
// if (messageBox.result() == QDialog::Accepted)
// {
// selectedUnit = model->getSelectedUnit();
// }
// else
// {
// selectedUnit = 0;
// }
// return;
// }
// case Action::MORPH:
// {
// return;
// }
// case Action::UPGRADE:
// {
// }
// }
}
void DelegateAction::comboDestroyed()
{
disconnect(this, SLOT(comboChanged(QString)));
disconnect(this, SLOT(comboDestroyed()));
}
//bool DelegateAction::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
//{
// QStyledItemDelegate::editorEvent(event, model, option, index);
// if (comboUpdated == true && index.isValid() == true)
// {
// comboUpdated = false;
// if (selectedUnit != 0)
// {
// units->at(index.row());
// }
// }
//}
I figured this out. If anyone is interested in something similar, I sub classed QTableView
.
Inside QTableView
i used QTableView::setIndexWidget()
to use QComboBox
es and QProgressBar
s. Basically my subclass had a QList
of both types of widgets and they corresponded to a particular row in the table.
- derive
ComboBoxEditor
fromQComboBox
- keep a Action object in ComboBoxEditor (data stored in model index)
- when delegate's
comboChanged()
is called, you can access the Action via sender(), that isComboBoxEditor
.
Please refer to the official example, StarDelegate
.
http://doc.qt.io/qt-5/qtwidgets-itemviews-stardelegate-example.html
精彩评论