文章目录
- 0 背景
- 1 MVC知识
- 1. 1 视图
- 1. 2 代理
- 1.3 模型
- 2 QTableVie数据呈现
- 2.1 使用数据模型
- 2.1.1 使用QStandardItemModel模型
- 2.1.2 使用QSqlQueryModel模型
- 2.2 QTableView的样式设计
- 2.3 QTableView事件
- 2.3.1 选择模型触发的事件
- 2.3.2 点击模型触发的事件
- 2.3.3 代理触发的事件
- 2.3.3.1 使用setIndexWidget
- 2.3.3.1 使用QStyledItemDelegate
0 背景
因为最近在做数据库、表格方面的应用程序,因此用到了很多这方面的知识,比如QTableView、QStandardItemModel、QItemSelectionModel、QSqlQUeryModel等等。查阅了很多资料,问了很多大佬,这篇文章就是为了方便日后再次使用这面知识时,能够快速查到对应的资料。
1 MVC知识
MV编程就是model(模型)、view(视图)、control(Delegate(代理))编程,就是把模型和视图分开来。
1. 1 视图
视图:例如QTableView、QListView、QTreeView,就是总体数据的呈现方式。
例如效果如下图。
1. 2 代理
代理:把视图里改变的值反馈到模型里;把模型里的数据库呈现到视图里。
例如:如下图里的商品名称和单位就是两个不同的代理,一个是QLineEdit(缺省时的默认代理),另一个是QComboBox。
1.3 模型
模型:分为数据模型和选择模型。
数据模型(组织数据的方式):
因为我主要跟数据库打交道,因此常用到的数据库为QStandardItemModel、QSqlQueryModel、QSqlTableModel、QSqlRelationTableModel。(注意带Abstarct为抽象类,要使用继承纯虚函数的子类才可以)
区别(下面的模型,越往下越高级):
- 1,QStandardItemModel:每项数据可以存任何内容。【最灵活,但是需要手写代码把每个数据导入到模型中】
- 2,QSqlQueryModel:用于sql查询的模型。(把sql语句查询后的全部结果自动导入模型中)
- 3,QSqlTableModel:封装了QSqlQueryModel,一次只能读写一个数据表的模型。(处理表格时只需编写很少的代码来修改表格)
- 4,QSqlRelationTableModel:封装了QSqlTableModel,提供对外键的支持。
选择模型(选择/点击模型后的事件):
QAbstractItemModel:用于获得当前选择的model索引
例如:类似于下面的效果
图片取自(https://wwwblogs/lvdongjie/p/4809484.html)
2 QTableVie数据呈现
2.1 使用数据模型
2.1.1 使用QStandardItemModel模型
- 1, 定义模型
QStandardItemModel *theModel;//数据模型
QItemSelectionModel *theSelection;//选择模型
- 2,初始化模型
theModel = new QStandardItemModel(this);//数据模型
theSelection = new QItemSelectionModel(theModel);//选择模型
- 3,设置模型
ui->TableView->setModel(theModel);//数据模型
ui->TableView->setSelectionModel(theSelection);//选择模型
- 4,填充数据
创建数据库连接并打开数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connection1");
db.setDatabaseName("/Users/mac/Qt/test.db");
db.open();
填充
QSqlDatabase db = QSqlDatabase::database("connection1");//关联数据库
QSqlQuery query(db);//指定数据库
query("SELECT id,name,score FROM stundet");//查询数据库
int queryRow = 0;//统计查询的行数
while(query.next()){
queryRow++;
}
query.seek(-1);//重置查询的位置到第一个数据的前一位
if(queryRow > 0){//查询到结果时进行填充
//设置数据库的行数和列数
theModel->setRowCount(queryRow);
theModel->setColumnCount(8);
//设置表头
thetModel->setHeaderData(0, Qt::Horizontal, QStringLiteral("id")); //设置表头,如不设置则使用数据库中的默认表头
theModel->setHeaderData(1, Qt::Horizontal, QStringLiteral("姓名"));
theModel->setHeaderData(2, Qt::Horizontal, QStringLiteral("商成绩"));
queryRow = 0;//重置,用于表示填充的行数
while(query.next()){
//获得模型的索引
QModelIndex index = theModel->index(queryRow, 0);
theModel->setData(index, query.value(0).toInt(), Qt::DisplayRole);
index = theModel->index(row, 1);
theModel->setData(index, query.value(1).toString(), Qt::DisplayRole);
index = theModel->index(row, 1);
theModel->setData(index, query.value(1).toDouble(), Qt::DisplayRole);
queryRow++;//行数+1
}
}
2.1.2 使用QSqlQueryModel模型
- 1,定义模型
QSqlQueryModel *sqlQueryModel;//数据模型
QItemSelectionModel *theSelection;//选择模型
- 2,初始化模型
创建数据库连接并打开数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connection1");
db.setDatabaseName("/Users/mac/Qt/test.db");
db.open();
初始化
QSqlDatabase db = QSqlDatabase::database("connection1");
sqlQueryModel = new QSqlQueryModel(this);
theSelection = new QItemSelectionModel(sqlQueryModel);//初始化选择模型
sqlQueryModel->setQuery("SELECT id,name,score FROM stundet");//初始化数据模型
//设置表头
sqlQueryModel->setHeaderData(0, Qt::Horizontal, tr("id"));
sqlQueryModel->setHeaderData(1, Qt::Horizontal, tr("姓名"));
sqlQueryModel->setHeaderData(2, Qt::Horizontal, tr("成绩"));
//设置模型
ui->TableView->setModel(sqlQueryModel);
ui->TableView->setSelectionModel(theSelection);
2.2 QTableView的样式设计
隐藏最左边的列排序:
ui->TableView->verticalHeader()->hide();
![在这里插入图片描述](https://img-blog.csdnimg/20210121084719992.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMzMzc1NTk4,size_16,color_FFFFFF,t_70)
设置不可编辑:
ui->TableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
隔行变色:
ui->TableView->setAlternatingRowColors(true);
单选模式:
ui->TableView->setSelectionMode ( QAbstractItemView::SingleSelection);
根据控件长度调整表格的列宽:
ui->TableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
根据内容自适应调整列宽
ui->theTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
ui->theTableView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
ui->theTableView->horizontalHeader()->setMinimumSectionSize(102);/最小宽度
设置选中后高亮
ui->TableView->horizontalHeader()->setHighlightSections(true);
设置代理为一个控件,如为QComboBox控件:
QComboBox *tempComboBox = new QComboBox(this);
tempComboBox->addItem("good");
tempComboBox->addItem("bad");
ui->TableView->setIndexWidget(theModel->index(row, 3), tempComboBox);
如果需要获得QComBox中的值,可以使用:
static_cast<QComboBox *>(ui->TableView->indexWidget(theModel->index(i, 3)))->currentText()
2.3 QTableView事件
2.3.1 选择模型触发的事件
//选择的项
connect(theSelection, &QItemSelectionModel::currentChanged,
this, &MainWindow::onCurrentChanged);
//选择的索引
connect(theSelection, &QItemSelectionModel::selectionChanged,
this, &MainWindow::updateSelection);
void MainWindow::onCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous){
//....
}
```cpp
void MainWindow::updateSelection(const QItemSelection &selected, const QItemSelection &deselected){
//...
}
2.3.2 点击模型触发的事件
双击
connect(ui->TableView, &QTableView::doubleClicked,
this, &QueryDialog::chooseQuery, Qt::UniqueConnection);// &QueryDialog::chooseQuery为自定义的槽函数
单击:
connect(ui->newOrderTableView, &QTableView::clicked,
[=](){
//槽函数
});
2.3.3 代理触发的事件
2.3.3.1 使用setIndexWidget
单位为法一的效果,删除为法二的效果:
法一:用于多个控件重复相同功能,传递参数
QComboBox *tempComboBox = new QComboBox(this);
tempComboBox->addItem("good");//个性化穿参数
tempComboBox->addItem("bad");
//关联事件
connect(tempComboBox, &QComboBox::currentTextChanged,
this, &MainWindow::changeQComboBoxData);
ui->TableView->setIndexWidget(theModel->index(row, 3), tempComboBox);
法二:用于多个控件重复相同功能,不传递参数
继承重写button
class DeleteToolButton : public QToolButton{
Q_OBJECT
public:
DeleteToolButton(QObject *parent = nullptr);
};
DeleteToolButton::DeleteToolButton(QObject *parent)
{
this->setIcon(QIcon(":/Image/sc.png"));
this->setStyleSheet("background: transparent");
}
添加并关联事件
ui->TableView->setIndexWidget(goodsListModel->index(row, 7), new DeleteToolButton(this));
//
QList<QToolButton*> deleteToolButtonList =
this->ui->goodsListTableView->findChildren<QToolButton*>();
for(auto it = deleteToolButtonList.begin();it != deleteToolButtonList.end();it++){
connect((*it), &QAbstractButton::clicked, this, &MainWindow::deleteRowData, Qt::UniqueConnection);
}
2.3.3.1 使用QStyledItemDelegate
价格为效果
使用
QDoubleSpinDelegate SpinDelegate;
ui->TableView->setItemDelegateForColumn(5, &SpinDelegate);
创建
class QDoubleSpinDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
QDoubleSpinDelegate(QObject *parent=0);
//自定义代理组件必须继承以下4个函数
//创建编辑组件
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const Q_DECL_OVERRIDE;
//从数据模型获取数据,显示到代理组件中
void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
//将代理组件的数据,保存到数据模型中
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const Q_DECL_OVERRIDE;
//更新代理编辑组件的大小
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
const QModelIndex &index) const Q_DECL_OVERRIDE;
};
QWidget *QDoubleSpinDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{ //创建代理编辑组件
Q_UNUSED(option);
Q_UNUSED(index);
QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setDecimals(2);
editor->setMaximum(10000);
return editor; //返回此编辑器
}
void QDoubleSpinDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{//从数据模型获取数据,显示到代理组件中
//获取数据模型的模型索引指向的单元的数据
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor); //强制类型转换
spinBox->setValue(value); //设置编辑器的数值
}
void QDoubleSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{ //将代理组件的数据,保存到数据模型中
QSpinBox *spinBox = static_cast<QSpinBox*>(editor); //强制类型转换
spinBox->interpretText(); //解释数据,如果数据被修改后,就触发信号
int value = spinBox->value(); //获取spinBox的值
model->setData(index, value, Qt::EditRole); //更新到数据模型
}
void QDoubleSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{ //设置组件大小
Q_UNUSED(index);
editor->setGeometry(option.rect);
}
只读代理:
class ReadOnlyDelegate: public QItemDelegate
{
public:
ReadOnlyDelegate(QWidget *parent = NULL):QItemDelegate(parent)
{}
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override //final
{
Q_UNUSED(parent)
Q_UNUSED(option)
Q_UNUSED(index)
return NULL;
}
};
更多推荐
一篇文章带你看懂Qt MVC(模型、视图、代理)编程————附带详细图文和代码
发布评论