2013-03-17 2 views
4

Я пишу приложение, которое использует пользовательский QWidget вместо обычных listitems или делегатов в PyQt. Я выполнил ответ в Render QWidget in paint() method of QWidgetDelegate for a QListView - среди прочего - для реализации QTableModel с пользовательскими виджетами. Полученный образец кода находится в нижней части этого вопроса. Есть некоторые проблемы с реализацией, которые я не знаю, как решить:Плавная ленивая загрузка и выгрузка пользовательского IndexWidget в QListView

  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

ответ

2

Вы можете использовать модель прокси, чтобы избежать загрузки всех виджетов. Прокси-модель может вычислять количество строк с высотами видового экрана и виджета. Он может вычислять индекс элементов со значением полосы прокрутки.

Это шаткое решение, но оно должно работать.

При изменении данных() метод с:

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

Элементы не будут отображаться, пока они не будут перемещены в свои позиции (это работает для меня).

1

QTableView только запрашивает данные для модели для элементов в своем окне просмотра, поэтому размер ваших данных не влияет на скорость. Поскольку вы уже подклассифицировали QAbstractListModel, вы можете переопределить его, чтобы вернуть только небольшой набор строк при его инициализации и изменить его метод canFetchMore для возврата True, если общий объем записей не был отображен. Хотя, с размером ваших данных, вы можете захотеть создать базу данных и вместо этого использовать QSqlQueryModel или QSqlTableModel, обе они выполняют ленивую загрузку в группах по 256.

Чтобы получить более плавную нагрузку предметов, которые вы могли бы подключить к valueChanged сигнал вашего QTableView.verticalScrollBar() и в зависимости от разницы между его value и maximum есть что-то вроде:

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

Lazy loading не помогает моей проблеме выгрузки элементов, которые больше не отображаются.Делегат явно не имеет гражданства, но мне нужно достаточно, чтобы контент отвечал на ввод. – lyschoening

+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

 Смежные вопросы

  • Нет связанных вопросов^_^