2013-03-17 149 views
4

我正在编写一个应用程序,它使用自定义QWidget代替PyQt中的常规列表项或代表。我遵循Render QWidget in paint() method of QWidgetDelegate for a QListView中的回答 - 其中包括 - 使用自定义小部件实现QTableModel。结果示例代码位于此问题的底部。执行中存在一些问题,我不知道如何解决:在QListView中平滑延迟加载和卸载自定义IndexWidget

  1. 卸载项目时,他们不显示。我打算为我的应用程序建立一个有数千个条目的列表,并且我无法在内存中保存那么多小部件。
  2. 加载尚未进入或至少异步加载的项目。小部件需要一些时间来渲染,下面的示例代码在滚动列表时有一些明显的滞后。
  3. 当在下面的实现中滚动列表时,加载时每个新加载的按钮出现在QListView的左上角一秒钟之后跳回到位置。这怎么可以避免?

-

import sys 
from PyQt4 import QtGui, QtCore 
from PyQt4.QtCore import Qt 


class TestListModel(QtCore.QAbstractListModel): 
    def __init__(self, parent=None): 
     QtCore.QAbstractListModel.__init__(self, parent) 
     self.list = parent 

    def rowCount(self, index): 
     return 1000 

    def data(self, index, role): 
     if role == Qt.DisplayRole: 
      if not self.list.indexWidget(index): 
       button = QtGui.QPushButton("This is item #%s" % index.row()) 
       self.list.setIndexWidget(index, button) 
      return QtCore.QVariant() 

     if role == Qt.SizeHintRole: 
      return QtCore.QSize(100, 50) 

    def columnCount(self, index): 
     pass 


def main(): 
    app = QtGui.QApplication(sys.argv) 

    window = QtGui.QWidget() 

    list = QtGui.QListView() 
    model = TestListModel(list) 

    list.setModel(model) 
    list.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel) 

    layout = QtGui.QVBoxLayout(window) 
    layout.addWidget(list) 

    window.setLayout(layout) 
    window.show() 

    sys.exit(app.exec_()) 


if __name__ == '__main__': 
    main() 
+0

为了解决问题3,你试图给按钮一个父母在创作时?即,QListView。 – Lorenz03Tx 2013-03-20 18:15:09

回答

2

您可以使用代理模式,以避免加载所有部件。代理模型可以根据视口和窗口小部件的高度计算行数。他可以使用滚动条值计算项目的索引。

这是一个不稳定的解决方案,但它应该工作。

如果修改您的数据()与方法:

button = QtGui.QPushButton("This is item #%s" % index.row()) 
self.list.setIndexWidget(index, button) 
button.setVisible(False) 

的项目将不显示,直到他们在他们的位置移动(我的作品)。

1

QTableView只向数据模型请求视图中的项目,所以数据的大小并不会真正影响速度。由于您已经子集QAbstractListModel,因此您可以将其重新实现为在初始化时仅返回一小部分行,并且如果尚未显示记录总量,请修改其canFetchMore方法以返回True。虽然,你的数据的大小,你可能要考虑创建一个数据库,并使用QSqlQueryModelQSqlTableModel相反,他们都做的256

组懒加载获取项目的平滑负荷,你可以连接到您QTableView.verticalScrollBar()valueChanged信号,并根据该差值之间是valuemaximum有类似:

while xCondition: 
    if self.model.canFetchMore(): 
     self.model.fetchMore() 

使用setIndexWidget大大减慢您的应用程序。你可以使用一个QItemDelegate和定制它的paint法的东西,如显示一个按钮:

class MyItemDelegate(QtGui.QItemDelegate): 
    def __init__(self, parent=None): 
     super(MyItemDelegate, self).__init__(parent) 

    def paint(self, painter, option, index): 
     text = index.model().data(index, QtCore.Qt.DisplayRole).toString() 

     pushButton = QtGui.QPushButton() 
     pushButton.setText(text) 
     pushButton.setGeometry(option.rect) 

     painter.save() 
     painter.translate(option.rect.x(), option.rect.y()) 

     pushButton.render(painter) 

     painter.restore() 

并与设置它:

myView.setItemDelegateForColumn(columnNumber, myItemDelegate) 
+0

延迟加载不会帮助我想要卸载不再可见的项目的问题。一个委托显然是无状态的,但我确实需要足够的状态来让内容响应输入。 – lyschoening 2013-03-22 18:41:57

+0

@lyschoening我认为子类['QSqlQueryModel'](http://doc-snapshot.qt-project.org/4.8/qsqlquerymodel.html)将是一个不错的选择。使用它的'setQuery'方法,您可以选择想要从数据库中显示的记录数。您可以将其与['QDataWidgetMapper'](http://doc-snapshot.qt-project.org/4.8/qdatawidgetmapper.html)结合使用,并将其映射到一组静态按钮,而不是动画他们更多的眼睛糖果,签出[这个问题]代码示例(http://stackoverflow.com/a/15582844/1006989) – 2013-03-23 03:57:58