在经典的 MVC 模型中,view用于向用户展示 model 的数据。但是,Qt提供的不是 MVC 三层架构,而是一个 model/view 设计。这种设计并没有包含一个完整而独立的组件用于管理用户的交互。在这种结构中,为了获得对用户输入控制的灵活性,这种交互工作交给了delegate,也就是“委托”,去完成。简单来说,就像它们的名字一样,view 将用户输入委托给 delegate 处理,而自己不去处理这种输入。这些组件提供一种输入能力,并且能够在某些 view 中提供这种交互情形下的渲染,比如在 table 中通过双击单元格即可编辑内容等。对这种控制委托的标准接口被定义在 QAbstractItemDelegate 类中。
Qt提供的标准组件使用 QItemDelegate 提供编辑功能的支持。这种默认的实现被用在 QListView,QTableView 和 QTreeView 之中。view 实用的delegate可以通过 itemDelegate() 函数获得。setItemDelegate() 函数则可以为一个标准组件设置自定义的 delegate。
delegate 可以用于渲染内容,这是通过 paint() 和 sizeHint() 函数来完成的。这个例子中,我们继承了QItemDelegate,重写了里面的createEditor(),setModelData()和paint()三个函数。给view 组件提供绘制和编辑的功能,来实现在TableView中添加Combobox、Spainbox、CheckBox控件。
下载地址:https://download.csdn.net/download/sakuya__/11072748
一个自定义的delegate可以直接提供一个编辑器,而不是使用内置的编辑器工厂(editor item factory)。如果你需要这种功能,那么需要重新实现一下几个函数:
下面来看代码:
controldelegate.h文件
#define CONTROLDELEGATE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class SpinboxDelegate : public QItemDelegate
{
Q_OBJECT
public:
SpinboxDelegate(int column);
//重写QItemDelegate里的函数
//const修饰引用传递,"引用传递"仅借用一下参数的别名,不需要产生临时对象,所以可以提高效率.使用const可以确保引用的参数不被修改
//const加在最后,函数的数据成员mColumn不可被修改
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
//void setEditorData(QWidget *editor, const QModelIndex &index) const ; //为editor提供编辑的原始数据
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const ;
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
//void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; //保证editor显示在 item view 的合适位置以及大小
private slots:
void commitAndCloseEditor();
private:
int mColumn;
};
class CheckBoxDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
CheckBoxDelegate(QObject *parent = 0);
protected:
void paint(QPainter* painter,const QStyleOptionViewItem& option,const QModelIndex& index) const;
bool editorEvent(QEvent *event,QAbstractItemModel *model,const QStyleOptionViewItem &option,const QModelIndex &index);
};
class ComboboxDelegate : public QItemDelegate
{
Q_OBJECT
public:
ComboboxDelegate();
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
private slots:
void commitAndCloseEditor();
};
#endif // CONTROLDELEGATE_H
controldelegate.cpp文件
#include "controldelegate.h"
//spinbox控件部分
SpinboxDelegate::SpinboxDelegate(int column)
{
mColumn = column;
}
//返回修改数据的组件,为指定的列或者行创建部件
QWidget *SpinboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const
{
if(index.column() == 3)
{
QSpinBox *editor = new QSpinBox(parent);
editor->setRange(0 , 1000);
connect(editor,SIGNAL(editingFinished()),SLOT(commitAndCloseEditor()));
return editor;
}
else if( index.column() == 4)
{
QSpinBox *editor = new QSpinBox(parent);
editor->setRange(0,1000);
connect(editor,SIGNAL(editingFinished()),SLOT(commitAndCloseEditor()));
return editor;
}
else
{
return QItemDelegate::createEditor(parent,option,index);
}
}
//根据editor 的数据更新model的数据
void SpinboxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
//显示格式控制
void SpinboxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 3) {
int warehouseAmount = index.model()->data(index,Qt::DisplayRole).toInt();
QString text = QString("%1").arg(warehouseAmount, 3, 10, QChar(' '));
QStyleOptionViewItem myOption = option;
//设置显示在item的中间
myOption.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
drawDisplay(painter, myOption, myOption.rect, text);
drawFocus(painter, myOption, myOption.rect);
}
else if(index.column() == 4) {
int amount = index.model()->data(index,Qt::DisplayRole).toInt();
QString text = QString("%1").arg(amount, 3, 10, QChar(' '));
QStyleOptionViewItem myOption = option;
myOption.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
drawDisplay(painter, myOption, myOption.rect, text);
drawFocus(painter, myOption, myOption.rect);
}
}
void SpinboxDelegate::commitAndCloseEditor()
{
QSpinBox *editor = qobject_cast(sender());
emit commitData(editor); //当编辑器小部件完成数据编辑并希望将其写入模型时,必须发出此信号
emit closeEditor(editor); //当用户使用指定的编辑器完成对项目的编辑时,将发出此信号
}
//checkbox部分
static QRect CheckBoxRect(const QStyleOptionViewItem &viewItemStyleOptions)/*const*/
{
//绘制按钮所需要的参数
QStyleOptionButton checkBoxStyleOption;
//按照给定的风格参数 返回元素子区域
QRect checkBoxRect = QApplication::style()->subElementRect( QStyle::SE_CheckBoxIndicator, &checkBoxStyleOption);
//返回QCheckBox坐标
QPoint checkBoxPoint(viewItemStyleOptions.rect.x() + viewItemStyleOptions.rect.width() / 2 - checkBoxRect.width() / 2,
viewItemStyleOptions.rect.y() + viewItemStyleOptions.rect.height() / 2 - checkBoxRect.height() / 2);
//返回QCheckBox几何形状
return QRect(checkBoxPoint, checkBoxRect.size());
}
CheckBoxDelegate::CheckBoxDelegate(QObject *parent):
QStyledItemDelegate(parent)
{
}
void CheckBoxDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,const QModelIndex& index)const
{
bool checked = index.model()->data(index, Qt::DisplayRole).toBool();
if(index.column() == 5) {
//按钮的风格选项
QStyleOptionButton checkBoxStyleOption;
//|=为复合赋值语句,a|=b等价于a=a|b,对a和b进行位或运算
checkBoxStyleOption.state |= QStyle::State_Enabled;
//根据值判断是否选中
checkBoxStyleOption.state |= checked? QStyle::State_On : QStyle::State_Off;
//返回QCheckBox几何形状
checkBoxStyleOption.rect = CheckBoxRect(option);
//绘制QCheckBox
QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxStyleOption, painter);
}
else {
//否则调用默认委托
QStyledItemDelegate::paint(painter, option, index);
}
}
bool CheckBoxDelegate::editorEvent(QEvent *event,
QAbstractItemModel *model,
const QStyleOptionViewItem &option,
const QModelIndex &index) {
if(index.column() == 5){
if((event->type() == QEvent::MouseButtonRelease) ||
(event->type() == QEvent::MouseButtonDblClick)){
QMouseEvent *mouseEvent = static_cast(event);
if(mouseEvent->button() != Qt::LeftButton ||
!CheckBoxRect(option).contains(mouseEvent->pos())){
return true;
}
if(event->type() == QEvent::MouseButtonDblClick){
return true;
}
}else if(event->type() == QEvent::KeyPress){
if(static_cast(event)->key() != Qt::Key_Space &&
static_cast(event)->key() != Qt::Key_Select){
return false;
}
}else{
return false;
}
bool checked = index.model()->data(index, Qt::DisplayRole).toBool();
return model->setData(index, !checked, Qt::EditRole);
}else{
return QStyledItemDelegate::editorEvent(event, model, option, index);
}
}
//combobox控件部分
ComboboxDelegate::ComboboxDelegate()
{
}
QWidget *ComboboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QComboBox *editor = new QComboBox(parent);
if(index.column() == 2){
editor->addItem(QString::fromLocal8Bit("boy"));
editor->addItem(QString::fromLocal8Bit("girl"));
editor->setCurrentIndex(0);
connect(editor,SIGNAL(editingFinished()),SLOT(commitAndCloseEditor()));
return editor;
}
else
{
QItemDelegate::createEditor(parent,option,index);
}
}
void ComboboxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.column() == 2)
{
QString text = index.model()->data(index , Qt::DisplayRole).toString();
QStyleOptionViewItem myOption = option;
myOption.displayAlignment = Qt::AlignHCenter | Qt::AlignVCenter;
drawDisplay(painter,myOption,myOption.rect,text);
drawFocus(painter,myOption,myOption.rect);
}
else
{
QItemDelegate::paint(painter,option,index);
}
}
void ComboboxDelegate::commitAndCloseEditor()
{
QComboBox *editor = qobject_cast(sender());
emit commitData(editor);
emit closeEditor(editor);
}
mainwindow.h文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include "controldelegate.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void tableViewInit();
private slots:
void contextMenuEvent(QContextMenuEvent *event);
//插入行操作
void sltInsertAction();
//删除指定行操作
void sltDeleteAction();
private:
Ui::MainWindow *ui;
QMenu *OperationMenu; //操作菜单
QAction *DeleteAction; //删除动作
QAction *InsertAction; //插入动作
QStandardItemModel *tableModel;
};
#endif // MAINWINDOW_H
mainwindow.cpp文件
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tableViewInit();
OperationMenu = new QMenu();
DeleteAction = new QAction("删除");
InsertAction = new QAction("插入");
OperationMenu->addAction(DeleteAction);
OperationMenu->addAction(InsertAction);
connect(InsertAction, SIGNAL(triggered(bool)), this, SLOT(sltInsertAction()));
connect(DeleteAction, SIGNAL(triggered(bool)), this, SLOT(sltDeleteAction()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::contextMenuEvent(QContextMenuEvent *event) //重写上下文事件
{
//方法一
if(ui->tableView->hasFocus())
{
OperationMenu->move(cursor().pos());
OperationMenu->show();
}
//方法二
// {
// ui->tableView->addAction(InsertAction);
// ui->tableView->addAction(DeleteAction);
// ui->tableView->(Qt::ActionsContextMenu);
// }
}
void MainWindow::tableViewInit()
{
tableModel = new QStandardItemModel;
ui->tableView->setModel(tableModel);
tableModel->setHorizontalHeaderItem(0, new QStandardItem("学号"));
tableModel->setHorizontalHeaderItem(1, new QStandardItem("姓名"));
tableModel->setHorizontalHeaderItem(2, new QStandardItem("性别"));
tableModel->setHorizontalHeaderItem(3, new QStandardItem("语文"));
tableModel->setHorizontalHeaderItem(4, new QStandardItem("数学"));
tableModel->setHorizontalHeaderItem(5, new QStandardItem("测试通过"));
ui->tableView->setModel(tableModel);
//tableView委托设置每一列里的控件
ui->tableView->setItemDelegateForColumn(2, new ComboboxDelegate());
ui->tableView->setItemDelegateForColumn(3, new SpinboxDelegate(3));
ui->tableView->setItemDelegateForColumn(4, new SpinboxDelegate(4));
ui->tableView->setItemDelegateForColumn(5, new CheckBoxDelegate());
ui->tableView->setEditTriggers(QAbstractItemView::DoubleClicked);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
}
//插入行操作
void MainWindow::sltInsertAction()
{
QList item;
item.append(new QStandardItem());
item.append(new QStandardItem());
item.append(new QStandardItem());
item.append(new QStandardItem());
item.append(new QStandardItem());
item.append(new QStandardItem());
//设置列数的对齐方式
item.at(0)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
item.at(1)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
item.at(2)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
item.at(3)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
item.at(4)->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
tableModel->insertRow(tableModel->rowCount(), item);
}
//删除指定行操作
void MainWindow::sltDeleteAction()
{
int curreantRow = ui->tableView->currentIndex().row(); //获取当前行数
tableModel->removeRow(curreantRow);
}
源代码百度云下载地址:https://pan.baidu.com/s/1UzC-Z-CkWqttThS6B3mbpQ 提取码:rtkt