C++ Qt 为 QTableView 使用自定义 QItemDelegate
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16660292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Qt Using Custom QItemDelegate for QTableView
提问by arnm
I followed the Spin Box Delegate tutorial, which Qt provides, to try to implement my own QItemDelegate. It would be used to specify a QComboBoxto represent data in a QTableViewcell but it is not working.
我按照 Qt 提供的 Spin Box Delegate 教程尝试实现我自己的QItemDelegate. 它将用于指定 aQComboBox来表示QTableView单元格中的数据,但它不起作用。
My biggest problem is that I don't know when my QItemDelegateis going to be utilized.
我最大的问题是我不知道我什么时候QItemDelegate会被利用。
when
itemModel->setData()is used or whenitemModel->setItem(). I would suspectsetItem()because I reimplemented aQItemDelegate(emphasis on the "Item") but the tutorial usessetData()and it works fine.I know that if the specified
QItemDelegatedoes not work it uses the default one but how do I now that the one I specified did not work?when should I suspect for
QTableViewto use my delegate. I would like to specify which delegates to use for each cell. Is this possible or does theQTableViewonly use one delegate throughout?How would I specify the items to populate the
QComboBoxonce it gets displayed by theQTableView?
何时
itemModel->setData()使用或何时使用itemModel->setItem()。我会怀疑setItem()是因为我重新实现了一个QItemDelegate(强调“项目”),但本教程使用setData()并且工作正常。我知道如果指定的
QItemDelegate不起作用,它会使用默认的,但是现在我指定的不起作用怎么办?我什么时候应该怀疑
QTableView使用我的委托。我想指定每个单元格使用哪些委托。这是可能的还是QTableView整个过程中唯一使用一个代表?QComboBox一旦它被 显示,我将如何指定要填充的项目QTableView?
I implemented QItemDelegatehere:
我QItemDelegate在这里实施:
- the part where I try to add the cell which is suppose to use the
QComboBoxis under the comment "Enabled" in mainwindow.cpp further down this post.
- 我尝试添加假设使用的单元格的部分
QComboBox在 mainwindow.cpp 中的注释“已启用”下,在这篇文章的下方。
qcomboboxitemdelegate.h
qcomboboxitemdelegate.h
#ifndef QCOMBOBOXITEMDELEGATE_H
#define QCOMBOBOXITEMDELEGATE_H
#include <QItemDelegate>
#include <QComboBox>
class QComboBoxItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
explicit QComboBoxItemDelegate(QObject *parent = 0);
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index);
void setEditorData(QWidget *editor, const QModelIndex &index);
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index);
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index);
signals:
private:
};
#endif // QCOMBOBOXITEMDELEGATE_H
qcomboboxitemdelegate.cpp
qcomboboxitemdelegate.cpp
#include "qcomboboxitemdelegate.h"
#include <QDebug>
QComboBoxItemDelegate::QComboBoxItemDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget* QComboBoxItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) {
// create widget for use
QComboBox* comboBox = new QComboBox(parent);
return comboBox;
}
void QComboBoxItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) {
// update model widget
QString value = index.model()->data(index, Qt::EditRole).toString();
qDebug() << "Value:" << value;
QComboBox* comboBox = static_cast<QComboBox*>(editor);
comboBox->setCurrentIndex(comboBox->findText(value));
}
void QComboBoxItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) {
// store edited model data to model
QComboBox* comboBox = static_cast<QComboBox*>(editor);
QString value = comboBox->currentText();
model->setData(index, value, Qt::EditRole);
}
void QComboBoxItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) {
editor->setGeometry(option.rect);
}
mainwindow.cpp : this is where I initialize the QStandardItemModel
mainwindow.cpp :这是我初始化 QStandardItemModel
void MainWindow::init() {
itemModel = new QStandardItemModel(this);
}
void MainWindow::setupUi() {
this->setWindowTitle("QAlarmClock");
QStringList labelList;
labelList << "Alarm Name" << "Time" << "Enabled";
itemModel->setHorizontalHeaderLabels(labelList);
ui->tableView->setModel(itemModel);
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableView->setItemDelegate(comboBoxItemDelegate);
}
void MainWindow::on_actionNew_triggered() {
alarmDialog = new AlarmDialog(this);
connect(alarmDialog, SIGNAL(on_close()), this, SLOT(on_alarmDialog_close()));
alarmDialog->exec();
}
mainwindow.cpp : this is where I update QStandardItemModel
mainwindow.cpp :这是我更新的地方 QStandardItemModel
void MainWindow::on_alarmDialog_close() {
QString alarmName = alarmDialog->getAlarmName();
QDateTime alarmDateTime = alarmDialog->getDateTime();
itemModel->insertRow(itemModel->rowCount());
int rowCount = itemModel->rowCount();
// Alarm Name
QStandardItem* alarmItem = new QStandardItem(QIcon("res/alarmclock.ico"), alarmName);
itemModel->setItem(rowCount - 1 , 0, alarmItem);
// Date Time
QStandardItem* dateTimeItem = new QStandardItem();
dateTimeItem->setText(alarmDateTime.toString());
dateTimeItem->setEditable(false);
itemModel->setItem(rowCount - 1, 1, dateTimeItem);
// Enabled
QStandardItem* enabledItem = new QStandardItem();
QList<QStandardItem*> optionList;
optionList << new QStandardItem("Enabled") << new QStandardItem("Disabled");
enabledItem->appendRows(optionList);
itemModel->setItem(rowCount - 1, 2, enabledItem);
}
Edit 1
编辑 1
qcomboboxdelegate.cpp
qcomboboxdelegate.cpp
QWidget* QComboBoxItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) {
// create widget for use
qDebug() << "Column: " << index.column();
if (index.column() == 2) {
QComboBox* comboBox = new QComboBox(parent);
QStringList values;
values << "Enabled" << "Disabled";
comboBox->addItems(values);
return comboBox;
} else {
return QItemDelegate::createEditor(parent, option, index);
}
}
mainwindow.cpp
主窗口.cpp
void MainWindow::on_alarmDialog_close() {
QList<QStandardItem*> row;
QString alarmName = alarmDialog->getAlarmName();
QDateTime alarmDateTime = alarmDialog->getDateTime();
QString status = "Enabled";
// Alarm Name
QStandardItem* alarmItem = new QStandardItem(QIcon("res/alarmclock.ico"), alarmName);
row << alarmItem;
// Date Time
QStandardItem* dateTimeItem = new QStandardItem();
dateTimeItem->setText(alarmDateTime.toString());
dateTimeItem->setEditable(false);
row << dateTimeItem;
// Enabled
QStandardItem* statusItem = new QStandardItem(status);
row << statusItem;
itemModel->appendRow(row);
}
采纳答案by hank
First, you should have a description of your model columns:
首先,您应该对模型列进行描述:
enum Columns
{
COL_NAME,
COL_TIME,
COL_STATUS
}
Your delegate should only work for the last column.
您的委托应该只适用于最后一列。
Here is an example of how you can populate your model:
以下是如何填充模型的示例:
for (int i = 0; i < 5; ++i)
{
QStandardItem *itemName = new QStandardItem(QString("name %1").arg(i));
QStandardItem *itemTime = new QStandardItem(QString("time %1").arg(i));
QString status;
if (i % 2 == 0)
{
status = "Enabled";
}
else
{
status = "Disabled";
}
QStandardItem *itemStatus = new QStandardItem(status);
QList<QStandardItem*> row;
row << itemName << itemTime << itemStatus;
model->appendRow(row);
}
As I said, your delegate should only work for the last column. So all methods you have reimplemented should have a column check like this:
正如我所说,您的委托应该只适用于最后一列。所以你重新实现的所有方法都应该有一个这样的列检查:
QWidget* QComboBoxItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index)
{
if (index.column() == COL_STATUS)
{
QStringList values;
values << "Enabled" << "Disabled";
QComboBox* comboBox = new QComboBox(parent);
comboBox->addItems(values);
return comboBox;
}
else
{
return QItemDelegate::createEditor(parent, option, index);
}
}
You should add this check to the other methods: if the current column is not the status column, the base class (QItemDelegate) implementation should be used.
您应该将此检查添加到其他方法:如果当前列不是状态列,QItemDelegate则应使用基类 ( ) 实现。
Then you set your delegate to your view:
然后您将委托设置为您的视图:
ui->tableView->setItemDelegate(new ComboBoxDelegate);
If you do everything right, a combo Box will appear in the last column if you try to edit its values.
如果一切顺利,当您尝试编辑其值时,最后一列将出现一个组合框。
回答by arnm
So I figured out that I did not override the correct function prototypes..! I forgot that they had const in the prototype meaning that I was not overriding any functions so it was using the default ones. Here are the correct virtual functions that have to be re-implemented: http://qt-project.org/doc/qt-5.0/qtwidgets/qitemdelegate.html
所以我发现我没有覆盖正确的函数原型..!我忘了他们在原型中有 const 意味着我没有覆盖任何函数,所以它使用的是默认函数。以下是必须重新实现的正确虚拟功能:http: //qt-project.org/doc/qt-5.0/qtwidgets/qitemdelegate.html
回答by CodeLurker
Even more simply; I found QTableView::setItemDelegateForColumn() to work admirably for a column. For example, in your MainWindow, you could make a member:
更简单;我发现 QTableView::setItemDelegateForColumn() 非常适合用于列。例如,在您的 MainWindow 中,您可以创建一个成员:
QComboBoxItemDelegate dgtComboDelegate;
Then, in your ctor, or init(), you could have
然后,在您的 ctor 或 init() 中,您可以拥有
ui->tableView->setItemDelegateForColumn(2, dgtComboDelegate);
If you wanted that to happen for a single cell, that's when you need to test on the index.column() and index.row().
如果您希望单个单元格发生这种情况,那么您需要在 index.column() 和 index.row() 上进行测试。
You know, you don't have to create a QTableView to do this either. E.g., see the ?:
您知道,您也不必创建 QTableView 来执行此操作。例如,看到?:
Qt - Centering a checkbox in a QTable
The OP doesn't give the declaration for a table widget or view; but it does have the QTableView tag. It should work equally well for either.
OP 没有给出表格小部件或视图的声明;但它确实有 QTableView 标签。它应该同样适用于任何一个。
In the latter case, you can do ui->tableWidget->setItemDelegateForColumn(2, dgtComboDelegate);and never have to make your own model. Just use setData() on the items you create (or even later, for that matter,) to initialize their values.
在后一种情况下,您可以ui->tableWidget->setItemDelegateForColumn(2, dgtComboDelegate);并且永远不必制作自己的模型。只需在您创建的项目上使用 setData()(或者甚至稍后,就此而言)来初始化它们的值。


