Qt Model/View(模型/视图)结构
博主是基于QTableView实现的表格,并将QTableView的数据模型设置为QStandardItemModel标准数据模型。将数据展示在表格中
Widget.h头文件
// Widget.h
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
QStandardItemModel *pstModel; // 标准数据模型类
QItemSelectionModel *pstSelectModel; // 单元格选择状态类 可以选择单行/多行 可获取单元格的模型索引
~Widget();
};
Widget.cpp构造函数
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
// 表格每次显示的行数目 初始化
iRowIndex = 0;
// 浏览器控件显示
initWidget();
// 设置显示 tableView和浏览器控件 的底部窗口widget的相对位置 (效果没有调整好)
ui->tabWidget->setGeometry(QRect(0, 0, 700, 800));
// 设置tableView的相对位置
ui->tableView->setGeometry(QRect(20, 40, 600, 680));
// 设置初始当前页和所有页
iCurrentPage = D_NSP_TDYTH_USMRS_CURRENT_PAGE;
iAllPage = 9; // 目前设定所有页面数目为20
// 初始化标准数据模型类对象
pstModel = new QStandardItemModel();
// 初始化选择状态类对象
pstSelectModel = new QItemSelectionModel(pstModel);
// 为tableView设置数据模型和选择模型
ui->tableView->setModel(pstModel);
ui->tableView->setSelectionModel(pstSelectModel);
//
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
// 设置表头
pstModel->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("设备编号")));
pstModel->setHorizontalHeaderItem(1, new QStandardItem(QObject::tr("设备名称")));
pstModel->setHorizontalHeaderItem(2, new QStandardItem(QObject::tr("设备类型")));
pstModel->setHorizontalHeaderItem(3, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(4, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(5, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(6, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(7, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(8, new QStandardItem(QObject::tr("帐号")));
pstModel->setHorizontalHeaderItem(9, new QStandardItem(QObject::tr("密码")));
pstModel->setHorizontalHeaderItem(10, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(11, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(12, new QStandardItem(QObject::tr("*****")));
pstModel->setHorizontalHeaderItem(13, new QStandardItem(QObject::tr("联系方式")));
// 设置每一列的固定宽度 默认设置每一列的宽度为100
// ui->tableView->setColumnWidth(0,250);
// 表格总体宽度自适应窗口宽度
// ui->tableView->horizontalHeader()->setStretchLastSection(true);
// ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// 行头显示和隐藏
ui->tableView->verticalHeader()->hide();
// 设置选中为整行选中
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
// 设置单元格为只读 不能编辑
// ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
// 启动 右键菜单
ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
// 动态添加行
// pstModel->setItem(0, 0, new QStandardItem("张三"));
// pstModel->setItem(0, 1, new QStandardItem("2013014221"));
// 显示数据样式
// 更新界面显示状态
updateStatus();
}
核心的语句
这里需要设置选择的行为:为选中一行,后面删除的时候选中的单元也是整行。
// 初始化标准数据模型类对象
pstModel = new QStandardItemModel();
// 初始化选择状态类对象
pstSelectModel = new QItemSelectionModel(pstModel);
// 为tableView设置数据模型和选择模型
ui->tableView->setModel(pstModel);
ui->tableView->setSelectionModel(pstSelectModel);
//
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
// 设置选中为整行选中
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
WIdget.cpp 实现删除按钮相应函数
// 对表格内的行进行删除
void Widget::on_pushButton_Delete_clicked()
{
/*
* selectedIndexes(); // 以单元格作为List连接单元
* selectedColumns(); // 以列作为List连接单元
* selectedRows(); // 以行作为List连接单元
*/
unsigned int uiRowsSort[NUM_PERPAGE] = {'\0'};
QModelIndexList curIndexList = pstSelectModel->selectedRows();
QModelIndex index;
int k1 = 0;
// 界面上显示删除单行的操作 实际上数据库中没有删除
//QModelIndex curIndex = pstSelectModel->currentIndex();
//pstModel->removeRow(curIndex.row());
foreach(index, curIndexList){
// 这里直接执行remove 删除一行之后 后面的行号发生变化 导致删除出现问题
uiRowsSort[k1++] = index.row();
printf("Index.Row = %d\tIndex.column = %d\n", index.row(), index.column());
}
// 逆序排序后从后往前删除 解决前面删除行导致后面行号出现的删除异常问题
array_Sort(uiRowsSort, k1);
for(int i = 0; i < k1; i++){
// printf("%d\n", uiRowsSort[i]);
pstModel->removeRow(uiRowsSort[i]);
}
/*
for(int k1 = 0; k1 < curIndexList.count(); k1++){
QModelIndex aIndex = curIndexList.at(k1);
printf("Index.Row = %d\tIndex.column = %d\n", aIndex.row(), aIndex.column());
// pstModel->removeRow(aIndex.row());
}*/
//pstModel->removeRows(curIndex.row(), 3);
return ;
}
这里主要记录删除单行的操作和删除多行的操作遇到的问题及解决方法。
- 单行的实现方法:
QModelIndex curIndex = pstSelectModel->currentIndex();
pstModel->removeRow(curIndex.row());
选择当前行作为需要删除的行,执行数据模型对象的removeRow()操作,removeRow()参数是待删除的行号,current.row()即为获取到待删除的行号。
- 多行的实现方法:
/*
* selectedIndexes(); // 以单元格作为List连接单元
* selectedColumns(); // 以列作为List连接单元
* selectedRows(); // 以行作为List连接单元
*/
QModelIndexList curIndexList = pstSelectModel->selectedRows();
QModelIndex index;
这里需要清除QModelIndexList类型,是一个QList类型,它所调用的API中selectedIndexes、selectedRows、selectedColumns分别表示的功能是以单元格/一行/一列作为List的一个元素进行链接,因此对整行进行操作使用selectedRows这个API。
遇到的问题:
删除多行时,删除了当前行,整个pstModel会进行调整,也即是已经选择的行号,在删除一行之后在调整后的pstModel中会变化,导致删除出现异常。
比如先选择了5,6行,又选择了2,3行,最后选择了8,9行,则获取的行号输出的顺序就是5,6,2,3,8,9,这样就存在一个问题,在执行删除的时候就有问题,执行的删除工作是单独一行执行的,如果按照获取行号的顺序进行删除,删除完一行以后,整个列表的行号就会发生改变,再按前面获取的行号进行删除,删除的结果就会乱套。
解决方法:
获取所有需要删除的行,将行号倒序排列,从后往前删除行,删除后面的行不会影响到前面待删除的行号。具体实现如下:
foreach(index, curIndexList){
// 这里直接执行remove 删除一行之后 后面的行号发生变化 导致删除出现问题
uiRowsSort[k1++] = index.row();
printf("Index.Row = %d\tIndex.column = %d\n", index.row(), index.column());
}
// 逆序排序后从后往前删除 解决前面删除行导致后面行号出现的删除异常问题
array_Sort(uiRowsSort, k1);
for(int i = 0; i < k1; i++){
// printf("%d\n", uiRowsSort[i]);
pstModel->removeRow(uiRowsSort[i]);
}
代替foreach的for循环也可以如下实现
for(int k1 = 0; k1 < curIndexList.count(); k1++){
QModelIndex aIndex = curIndexList.at(k1);
printf("Index.Row = %d\tIndex.column = %d\n", aIndex.row(), aIndex.column());
// pstModel->removeRow(aIndex.row());
}
结束语
遇到类似问题,可以留言私信交流,如博文存在问题请批评指正!