QTableView本身只承担表格的显示、选择处理和编辑操作,真正的数据由绑定的模型提供,这是使用Qt的Model/View架构时,一个经常会被碰到的问题。表格一片空白,或者修改了数据之后画面不刷新,通常并不是视图这个控件本身坏掉了,而是模型的接口、对象的生命周期,或者更新的通知,这几个环节没有被处理好。去排查的时候,要先确认模型是不是正确地给出了数据,然后再去看数据起了变化以后,有没有去通知视图,让它重新读取一遍。
一、Qt QTableView数据模型怎么绑定
QTableView可以去绑定QStandardItemModel、QSqlTableModel,也可以绑定那种从QAbstractTableModel继承下来的自定义模型。数据结构比较简单的时候,可以直接用标准模型;要是数据是从业务对象、接口返回的结果,或者自定义的容器里面来的,那自定义模型通常会更好去控制。
1、根据数据来源选择模型
QStandardItemModel适合用在数据量不大,单元格需要直接去增、删、改的场景,可以一行一行地去创建QStandardItem,再把内容给设好。QSqlTableModel适合直接把数据库的表给显示出来。自定义的QAbstractTableModel呢,则适合QVector、QList,或者是业务上的结构体数据,但至少得把rowCount、columnCount和data这三个给正确地实现了,要不然QTableView是没法知道要去显示多少行、多少列,以及每一个单元格里面的内容的。
2、把模型绑定到QTableView
通过【QTableView】的【setModel】方法,去把需要显示的数据模型给设上去。
比方说,模型的指针名字叫model,那就可以用tableView->setModel(model);把绑定的动作给完成掉。调用了以后,QTableView就会照着模型返回来行和列的数量,还有数据的内容,去把表格给生成出来。通常是不需要为了去更新数据,来来回回地调用setModel的,模型只要绑定上一次,后面只要是正确地发出了数据变化的信号,视图就会自己跟着去更新。
3、保证模型对象没有提前销毁
模型是不能被创建成函数里面那种临时的局部对象的。函数一结束,模型就给销毁掉了,QTableView内部存着的那个模型指针,也就跟着失效了,表格就可能会显示成空白,或者是出些别的毛病。可以把模型定义成窗口类的一个成员,也可以在创建模型的时候,把窗口的那个对象拿来当作父对象。这么做的话,模型在窗口还活着的这段时间里面,就会一直有效,不会因为初始化的那个函数跑完了,它也就跟着没掉了。
二、Qt QTableView数据刷新后不显示怎么办
把底层的数据给改了以后,QTableView它是不会自己跑过去检查,容器里面的东西是不是已经变了的。Qt是靠着模型发出来的信号,去通知视图做刷新的,所以要是只修改了QVector、QList,或者是结构体里面的值,却没有把信号给发出去,那表格就还是会显示修改以前的内容。
1、修改单元格后发送dataChanged
已经有的那些行和列的数量,并没有起变化,只是某些单元格里头的内容被修改过了,这个时候,应该在模型更新完成了以后,去把dataChanged信号给发出去。信号里面,是需要把发生变化的那块区域,它左上角和右下角的QModelIndex给提供出来的。要是只改了一个单元格,那两个索引是可以弄成一样的;要是成批地改了一片区域,那就该把真实的变化范围给覆盖进去。信号发出去了以后,QTableView就会再去调用data,把这一部分内容给重新读出来。
2、新增或删除行时使用行变更通知
在新增数据以前,去调用【beginInsertRows】,把底层的容器给改完了之后,再去调用【endInsertRows】。
删数据的时候,用的就是【beginRemoveRows】和【endRemoveRows】。这一类的操作,是不能只去发一个dataChanged就完事的,因为新增或者删除以后,模型的rowCount已经变掉了。要是少了行的变更通知,底层的容器里面虽然已经有了新的数据,可是QTableView说不定还会继续守着原来的那个行数,看起来就像是刷新没有起作用一样。
3、整批替换数据时重置模型
碰上查询的条件变了、重新去读了文件,或者是整批地去替换数据的时候,可以用beginResetModel和endResetModel。在重置的这个过程里面,先把内部的数据给换掉,等结束了以后,视图就会去重新读取行数、列数,还有所有单元格里面的内容。模型重置这个东西,是会影响当前的选择、排序的状态,还有一部分索引的,所以只是少量的修改,就不太建议频繁地去用它,只有在数据的结构整体上都起了变化的时候,再去拿过来用。
三、Qt QTableView数据仍然不显示怎么排查
模型已经给绑定上了,更新的信号也发出去了,表格还是什么东西都没有显示出来,这个时候,就还要接着去检查data的返回值、代理模型,还有线程。好多时候,问题并不是视图没有去刷新,而是刷新之后取回来的结果,它本身还是空的。
1、检查data函数返回条件
QTableView在显示普通文本的时候,data函数是需要在Qt::DisplayRole这个角色下面,去把对应到的内容给返回来的。如果只是处理了Qt::EditRole,那单元格在编辑的那一下子,是有可能看得见值的,可在正常的状态下面,就还是会显示成空的。还要去检查一下index.row和index.column,看它们是不是跑到了容器的范围外头去了,rowCount返回的那个数量,也一定得跟实际的数据对得上才行。
2、检查代理模型是否过滤数据
用到了QSortFilterProxyModel的时候,QTableView绑定的,通常就是那个代理模型,而实际的数据,是存在源模型里面的。业务代码,应当是去更新源模型,然后再让代理模型去接住这个变化。数据更新完了还是不显示,就得去查一查,筛选的条件是不是把新的数据给滤掉了,也要去确认一下,修改的是不是当前这个代理模型所对应到的sourceModel,而不是另外一个,早就已经没有绑定关系的模型对象了。
3、避免在线程中直接修改模型
后台的线程,是可以去查数据库、读文件,或者是算数据的,但是不应该直接去改界面线程里面的那个QAbstractItemModel。比较稳当的办法,是让工作的那个线程把结果给返回来,再通过信号,把数据给传到主线程里面,由主线程去更新模型。跨着线程,直接去操作模型,是有可能会出现偶尔不刷新、数据错位,或者程序崩掉的情况的,而且这种问题,往往是很难稳定地把它复现出来的。
总结
Qt QTableView数据模型怎么绑定Qt QTableView数据刷新后不显示怎么办,要紧的地方,是得把模型的接口、对象的生命周期,还有变化的通知,这几个给处理好。在绑定的时候,要挑一个合适的模型,通过setModel去把关系给建起来,还得保证模型是一直都在的;更新数据的那会儿,则要看修改的类型,去发送dataChanged、行插入删除的那些通知,或者是去执行模型的重置。如果还是没有东西显示出来,就再去查一查DisplayRole、行和列的数量、代理模型的过滤,还有线程的调用。光是去调用QTableView的update或者repaint,那也只是把现有的内容重新画上一遍,是不能代替模型的通知机制的。