在 Qt 中,可以通过自定义代理(QAbstractItemDelegate、
QStyledItemDelegate 或其派生类)的方式,将 QTableView
中的指定项扩展为自定义类型控件。下面以将指定列的单元格扩展为 QComboBox
为例,详细介绍实现步骤和示例代码。
实现思路
- 自定义代理类:继承自
QStyledItemDelegate
,重写其关键虚函数,如createEditor
、setEditorData
和setModelData
。 - 设置代理:将自定义代理应用到
QTableView
的指定列或行;
#include <QApplication>
#include <QTableView>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QComboBox>
#include <QWidget>
#include <QVBoxLayout>
class ComboBoxModel;
// 自定义代理类
class ComboBoxDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
ComboBoxDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
// 创建编辑器
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
QComboBox *editor = new QComboBox(parent);
//接下来可以向editor中添加项,可以通过index传入的数据进行添加,这样更灵活;
//此处先以较简单的方式进行添加(通过组态模型的方式进行添加)
ComboBoxModel *config = new ComboBoxModel();
config->addItem(QString("Option 1"));
config->addItem(QString("Option 2"));
config->addItem(QString("Option 3"));
config->setCheckable();
QComboBox *editor = new QComboBox(parent);
editor->setModel(config);
return editor;
}
// 将模型中的数据设置到编辑器中
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
QComboBox *comboBox = static_cast<QComboBox*>(editor);
QString value = index.model()->data(index, Qt::EditRole).toString();
int comboIndex = comboBox->findText(value);
if (comboIndex != -1) {
comboBox->setCurrentIndex(comboIndex);
}
}
// 将编辑器中的数据保存到模型中,通过设置模型数据的方式可以修改QTableView对应(row,col)中的值
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override {
ComboBoxModel *modelMy = qobject_cast<ComboBoxModel*>(editor->model());
QStringList list = modelMy->getCheckedItems();
QString value = list.join(',');
model->setData(index, value, Qt::EditRole);
}
};
class ComboBoxModel : public QStandardItemModel
{
Q_OBJECT
public:
ComboBoxModel(QObject *parent = nullptr){};
void addItem(QString &name)
{
QStandardItem *item = new QStandardItem(name);
appendRow(item);
}
void addItems(QStringList &list)
{
for(const auto &text : list)
{
QStandardItem *item = new QStandardItem(text);
appendRow(item);
}
}
void setCheckable()
{
int rows = rowCount();
for (int i = 0; i < rows; ++i)
{
QStandardItem *item = takeItem(i);
item ->setData(Qt::Unchecked, Qt::CheckStateRole);
item ->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
}
}
QStringList getCheckedItems()
{
QStringList options;
int rows = rowCount();
for (int i = 0; i < rows; ++i)
{
QStandardItem *item = takeItem(i);
if(item->data(Qt::CheckStateRole) == Qt::Checked)
{
options.append(item->text());
}
}
return options;
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建模型
QStandardItemModel model(4, 2);
model.setHorizontalHeaderLabels({"Column 1", "Column 2"});
// 创建表格视图
QTableView tableView;
tableView.setModel(&model);
// 创建并设置代理
ComboBoxDelegate delegate;
// 将代理应用到第二列
tableView.setItemDelegateForColumn(1, &delegate);
// 显示表格视图
tableView.show();
return app.exec();
}
#include "main.moc"
代码解释
createEditor
函数:当用户开始编辑指定列的单元格时,该函数会被调用,用于创建并返回一个QComboBox
作为编辑器。在函数中,为QComboBox
添加了几个选项。setEditorData
函数:此函数将模型中的数据设置到编辑器中。通过index.model()->data(index, Qt::EditRole)
获取模型中的数据,然后使用comboBox->findText
查找该数据在QComboBox
中的索引,并设置当前索引。setModelData
函数:当用户完成编辑后,该函数会被调用,用于将编辑器中的数据保存到模型中。通过comboBox->currentText
获取当前选择的文本,然后使用model->setData
将其保存到模型中。- 创建模型和表格视图:使用
QStandardItemModel
创建一个模型,并设置水平表头标签。然后创建一个QTableView
并将模型设置给它。 - 创建并设置代理:创建
ComboBoxDelegate
实例,并使用tableView.setItemDelegateForColumn
将其设置为表格视图第二列的代理。 - ComboBoxModel类: 是实现QComboBox的组态模型类,可以通过此类为QComboBox进行初始化赋值,及相关属性参数设置。