Qt MVC结构之QItemSelectionModel模型介绍

QItemSelectionModel

Qt的MVC结构支持多个View共享同一个model,包括该model的选中状态等。我们可以通过设置QItemSelectionModel,来更改View的选中效果和显示效果。我们创建一个Qt Application项目,在MainWindow的头文件中添加一个QTbaleView*类型的成员 _table_view。然后在构造函数中为这个_table_view设置model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStandardItemModel * model = new QStandardItemModel(7,4,this);
for(int row=0; row < 7; row++){
for(int column = 0; column < 4; column++){
QStandardItem * item = new QStandardItem(QString("%1").arg(row*4+column));
model->setItem(row, column, item);
}
}

_table_view = new QTableView;
_table_view->setModel(model);
setCentralWidget(_table_view);
this->resize(800,800);
}

我们创建了一个QStandardItemModel对象,然后为其设置几个Item,最后将这个model设置到tableview中。
我们可以为TableView设置选择的项目,接下来继续在构造函数中补充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 //获取视图的项目选择模型
QItemSelectionModel * selection_model = _table_view->selectionModel();
//定义左上角和右下角的索引
QModelIndex topLeft;
QModelIndex bottomRight;
//根据上面两个索引选择项目
//第1行1列
topLeft = model->index(1,1,QModelIndex());
//第5行2列
bottomRight = model->index(5,2,QModelIndex());
//设置选择区域
QItemSelection selection(topLeft, bottomRight);
//将选择的区域设置给选择模型, 设置 为选中状态
selection_model->select(selection, QItemSelectionModel::Select);

我们从tableview中获取选择模型,然后从根节点下选择第1行1列作为左上索引,选择第5行2列作为右下索引。然后创建选择区域QItemSelection,最后将选择区域这只给选择模型。接下来为了我们为工具栏添加两个动作,为动作绑定两个槽函数,在MainWindow声明文件中添加两个函数的声明

1
2
3
public slots:
void getCurrentItemData();
void toggleSelection();

在构造函数中将动作和槽函数绑定起来

1
2
ui->mainToolBar->addAction(tr("当前项目"), this, &MainWindow::getCurrentItemData);
ui->mainToolBar->addAction(tr("切换选择"), this, &MainWindow::toggleSelection);

实现这两个槽函数, getCurrentItemData获取当前条目的数据信息,toggleSelection实现切换选择的条目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void MainWindow::getCurrentItemData(){
auto currentData = _table_view->selectionModel()->currentIndex().data().toString();
qDebug() <<tr("当前项目的内容") << currentData;
}

void MainWindow::toggleSelection(){
//找到根节点下第0行0列的item的索引
QModelIndex topLeft = _table_view->model()->index(0,0,QModelIndex());
//获取根节点下最大的行号
auto max_row = _table_view->model()->rowCount(QModelIndex());
//获取根节点下最大的列号
auto max_column = _table_view->model()->columnCount(QModelIndex());
//根据列号和行号获取最右下角的item的索引
QModelIndex bottomRight = _table_view->model()->index(max_row-1, max_column-1, QModelIndex());
//设置选择区域
QItemSelection curSelection(topLeft, bottomRight);
_table_view->selectionModel()->select(curSelection, QItemSelectionModel::Toggle);
}

通过点击切换选择,可以实现选择区域的切换,因为我们设置选择的类型为Toggle,系统会将选中的变为取消选中,将取消选中的变为选中。
切换前
https://cdn.llfc.club/1671529103099.jpg
切换后
https://cdn.llfc.club/1671529287147.jpg
因为默认当前的条目是第1行1列,所以getCurrentItemData会打印他的信息。每一个model都有当前条目和选择条目两个属性。

捕获选择条目的变化

当我们点击鼠标选择一个条目时,当前条目就变为该条目,选择的条目也变为该条目。我们可以通过选择模型发出的selectionChanged信号,获取选择了那些条目的索引,以及取消选择了哪些条目的索引。我们可以通过currentChanged获取当前的条目索引以及变化之前的条目索引。现在MainWindow中添加两个槽函数的声明

1
2
3
public slots:
void updateSelection(const QItemSelection& selected, const QItemSelection& deselected);
void changeCurrent(const QModelIndex& current, const QModelIndex& previous);

两个槽函数的参数和信号的参数匹配。我们实现changeCurrent,当选择模型的当前索引变化时,打印变化前后的索引行号,列号。

1
2
3
4
void MainWindow::changeCurrent(const QModelIndex& current, const QModelIndex& previous){
qDebug() << tr("move(%1, %2) to (%3, %4)").arg(previous.row())
.arg(previous.column()).arg(current.row()).arg(current.column());
}

然后我们实现选择模型的选择条目变化时更新条目的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void MainWindow::updateSelection(const QItemSelection& selected, const QItemSelection& deselected){
QModelIndex index;
QModelIndexList list = selected.indexes();
//为现在的选择项目设置值
for(int i =0; i < list.size(); i++){
QString text = QString("(%1, %2)").arg(list[i].row()).arg(list[i].column());
_table_view->model()->setData(list[i], text);
}

list = deselected.indexes();
foreach(index, list){
_table_view->model()->setData(index,"");
}
}

在MainWindow的构造函数中添加信号和槽函数的链接

1
2
3
4
//选择模型的选择条目更改后触发updateSelection函数
connect(selection_model, &QItemSelectionModel::selectionChanged, this, &MainWindow::updateSelection);
//选择模型的当前项目更改后,关联changeCurrent函数
connect(selection_model, &QItemSelectionModel::currentChanged, this, &MainWindow::changeCurrent);

点击某个条目,其他条目的数据都变为空,这个条目被选中,内容修改为行列号
https://cdn.llfc.club/1671530820828.jpg

多个View共享模型

MVC结构最大的好处就是可以通过多个View共享同一个model,这个model的选中状态改变时,多个View的显示效果一致。
在构造函数中添加另一个QTableView

1
2
3
4
5
6
7
QTableView * tableView2;
tableView2 = new QTableView();
tableView2->setWindowTitle("tableView2");
tableView2->resize(400,300);
tableView2->setModel(model);
tableView2->setSelectionModel(selection_model);
tableView2->show();

可以看到两个View显示的选中状态是一致的
https://cdn.llfc.club/1671531054879.jpg

源码链接

源码链接
https://gitee.com/secondtonone1/qt-learning-notes