2013-03-17 80 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