Russian Qt Forum
Ноябрь 24, 2024, 02:24 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: [РЕШЕНО] QTableView - видимые ячейки  (Прочитано 20137 раз)
DmP
Гость
« Ответ #15 : Август 02, 2010, 12:22 »

Это нормально, у тролей при определении последней строки в таблице если получается -1, то берется максимальный номер строки, типа model()->rowCount() - 1. Только у них от высоты не отнимается 1, просто rowAt(viewport()->height())

Спасибо!
Т. е. такой способ определения последней строки является правильным?
Да, даже бы сказал официальным Улыбающийся. Пожалуйста.
Записан
Sky
Гость
« Ответ #16 : Август 02, 2010, 13:12 »

Отлично! Большое спасибо!
Записан
daimon
Гость
« Ответ #17 : Август 06, 2010, 22:32 »

Можете кинуть пример с базой (посмотреть). Я пытаюсь делать простую таблицу (данные в файле-считывание из файла)
Записан
Sky
Гость
« Ответ #18 : Август 09, 2010, 09:09 »

Вот классы, работы с БД и класс модели. С отображением уж сами, у меня весьма запутанно все выглядит, там под свои задачи переколбашено много.

db_data.py
Код:
# -*- coding: utf-8 -*-

from PyQt4.QtCore import *
from PyQt4.QtSql import *
import threading as trd

class DbThread(QThread):
    """
    DbThread(QSqlDatabase db)
    Экземпляр класса в отдельном потоке загружает данные из БД.   
    """
    def __init__(self, db):
        QThread.__init__(self)
        self.db = db
        self.data = {}
        self.begin = 0
        self.end = 0  # Эта переменная указывает на последний индекс + 1
        self.cacheSize = 0
        self.queryInfo = {} # В словаре хранятся списки таблиц, полей и сортировки
        self.queryPrepared = {} # В словаре хранятся таблицы, поля и сортировки, перечисленные через запятую

    def setBounds(self, begin, end):
        """
        setBound(begin, end)
        Установка первой и "последней + 1" строки необходимого блока данных.
        """
        if begin > end or begin < 0 or end < 0:
            return       
        self.begin = begin
        self.end = end

    def run(self):
        """
        Не использовать, автоматически запускается функцией start().
        Здесь находится основной код получения данных от БД.
        """
        blockBegin = -1
        qryPrepare = self.queryInfo
        qryText = 'SELECT %(fields)s FROM %(tables)s ORDER BY %(orders)s' % self.queryPrepared
        for i in xrange(self.begin, self.end):
            if blockBegin == -1 and (not self.data.has_key(i)):
                blockBegin = i
            if blockBegin != -1 and (self.data.has_key(i) or i == self.end - 1):
                if i == self.end - 1:
                    blockEnd = self.end
                else:
                    blockEnd = i
                query = QSqlQuery(self.db)
                #print '%s OFFSET %d LIMIT %d' % (qryText, blockBegin, blockEnd - blockBegin)
                query.exec_('%s OFFSET %d LIMIT %d' % (qryText, blockBegin, blockEnd - blockBegin))
                #print query.executedQuery()
                currentRow = blockBegin
                while query.next():
                    fld = []
                    for i in xrange(query.record().count()):
                        fld.append(query.record().value(i).toString())
                    self.data[currentRow] = fld
                    currentRow += 1
                blockBegin = -1
       
        for i in self.data.copy():        # сборка мусора
            if i < self.begin - self.cacheSize or i >= self.end + self.cacheSize:
                del(self.data[i])

class DbData(QObject):
    """
    DbData(QSqlDatabase db)
    С классом можно обращаться как с обычным списком,
    любой индекс будет корректен. Если строка не загружена,
    то возвращается None. Элементы списка - словари {field:data}"""


    def __init__(self, db):
        QObject.__init__(self)
        self.thread = DbThread(db)
        self.connect(self.thread, SIGNAL('finished()'), self.threadFinished)
        self.lastBegin = -1
        self.lastEnd = -1
        self.fin = True

    def __getitem__(self, index):
        """
        Получение строки данных по индексу.
        dbData.__getitem__(i) <==> dbData[i]
        """
        if self.thread.data.has_key(index):
            return dict(zip(self.thread.queryInfo['fields'], self.thread.data[index]))
        else:
            return None

    def __setitem__(self, index, item):
        """
        Присваивание строки данных по индексу.
        dbData.__setitem__(i, data) <==> dbData[i] = data
        """
        pass  # Не реализовано и не надо

    def start(self, newBegin, newEnd):
        """
        start(begin, end)
        Запуск процесса получения данных.
        begin = первая строка
        end = последняя строка + 1
        """
        if not self.fin:                # Здесь мы ожидаем окончания потока, хотя лучше бы его убивать,
            self.lastBegin = newBegin   # но это почему-то глючит. :( А сейчас мы немного теряем в производительности,
            self.lastEnd = newEnd       # но есть мнение, что выигрываем в нагрузке на сервер.
        else:
            self.thread.setBounds(newBegin, newEnd) # Устанавливаем границы, которые были запрошены последними
            self.fin = False                        # и запускаем поток
            self.thread.start()
            self.lastBegin = -1

    def threadFinished(self):
        """
        Слот окончания работы потока. Если других запросов
        во время работы не было, генерирует сигнал finished()
        """
        if self.lastBegin > -1:
            self.thread.setBounds(self.lastBegin, self.lastEnd)
            self.fin = False           
            self.thread.start()
            self.lastBegin = -1
        else:
            self.emit(SIGNAL('finished()'))
            self.fin = True
           
    def getCacheSize(self):
        return self.thread.cacheSize
    def setCacheSize(self, cacheSize):
        self.thread.cacheSize = cacheSize
    cacheSize = property(getCacheSize, setCacheSize)

db_model.py
Код:
# -*- coding: utf-8 -*-

from PyQt4.QtCore import *
from PyQt4.QtSql import *
from db_data import DbData

class DbAbstractModel(QAbstractTableModel):
   
    def __init__(self, database, parent=None):
        self.rCnt = None
        self.database = database
        self.dbData = DbData(database)
        self.connect(self.dbData, SIGNAL('finished()'), self.dbFinished)
        self.queryInfo = {}
        self.queryPrepared = {}
        self.colList = []
        QAbstractTableModel.__init__(self, parent)

    def getRowCount(self):
        qry = QSqlQuery(self.database)
        qry.exec_('SELECT COUNT(*) FROM %(tables)s' % (self.queryPrepared))
        qry.first()
        self.rCnt = qry.record().value('count').toInt()[0]

    def viewportChanged(self, begin, end):
        self.dbData.start(begin, end)

    def dbFinished(self):
        self.emit(SIGNAL('layoutChanged()'))

    def rowCount(self, parent=QModelIndex()):
        if self.rCnt == None:
            self.getRowCount()
        return self.rCnt

    def columnCount(self, parent=QModelIndex()):
        return len(self.colList)

    def data(self, index, role = Qt.DisplayRole):
        if role == Qt.DisplayRole:
            if self.dbData[index.row()]:
                return self.dbData[index.row()][self.colList[index.column()]]
        return QVariant()
   
    def setQueryInfo(self, queryInfo):
        """
        setQueryInfo(dict('tables':[], 'fields':[], 'orders':[]))
        Параметр передает в словаре списки таблиц, полей и сортировки
        """
        self.queryInfo = queryInfo
        for key in queryInfo:
            self.queryPrepared[key] = ','.join(queryInfo[key])

        if len(queryInfo['pkey']):
            self.queryPrepared['orders'] += ',' + self.queryPrepared['pkey']

        self.dbData.thread.queryInfo = queryInfo
        self.dbData.thread.queryPrepared = self.queryPrepared
        self.dataReset()

    def setCacheSize(self, cacheSize):
        self.dbData.cacheSize = cacheSize
       
    def headerData(self, section, orientation, role = Qt.DisplayRole):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.colList[section]
        return QAbstractTableModel.headerData(self, section, orientation, role)
           
    def dataReset(self):
        self.dbData.thread.terminate()
        self.dbData.thread.data.clear()
        self.getRowCount()

Здесь тоже много чего лишнего, но уж разбирайтесь. Подмигивающий

В представлении надо реализовать вызов viewportChanged(begin, end) модели по событиям изменения размера вьюпорта и скроллингу.
Записан
daimon
Гость
« Ответ #19 : Август 09, 2010, 15:47 »

Вот классы, работы с БД и класс модели. С отображением уж сами, у меня весьма запутанно все выглядит, там под свои задачи переколбашено много.

db_data.py
Код:
# -*- coding: utf-8 -*-

from PyQt4.QtCore import *
from PyQt4.QtSql import *
import threading as trd

class DbThread(QThread):
    """
    DbThread(QSqlDatabase db)
    Экземпляр класса в отдельном потоке загружает данные из БД.   
    """
    def __init__(self, db):
        QThread.__init__(self)
        self.db = db
        self.data = {}
        self.begin = 0
        self.end = 0  # Эта переменная указывает на последний индекс + 1
        self.cacheSize = 0
        self.queryInfo = {} # В словаре хранятся списки таблиц, полей и сортировки
        self.queryPrepared = {} # В словаре хранятся таблицы, поля и сортировки, перечисленные через запятую

    def setBounds(self, begin, end):
        """
        setBound(begin, end)
        Установка первой и "последней + 1" строки необходимого блока данных.
        """
        if begin > end or begin < 0 or end < 0:
            return       
        self.begin = begin
        self.end = end

    def run(self):
        """
        Не использовать, автоматически запускается функцией start().
        Здесь находится основной код получения данных от БД.
        """
        blockBegin = -1
        qryPrepare = self.queryInfo
        qryText = 'SELECT %(fields)s FROM %(tables)s ORDER BY %(orders)s' % self.queryPrepared
        for i in xrange(self.begin, self.end):
            if blockBegin == -1 and (not self.data.has_key(i)):
                blockBegin = i
            if blockBegin != -1 and (self.data.has_key(i) or i == self.end - 1):
                if i == self.end - 1:
                    blockEnd = self.end
                else:
                    blockEnd = i
                query = QSqlQuery(self.db)
                #print '%s OFFSET %d LIMIT %d' % (qryText, blockBegin, blockEnd - blockBegin)
                query.exec_('%s OFFSET %d LIMIT %d' % (qryText, blockBegin, blockEnd - blockBegin))
                #print query.executedQuery()
                currentRow = blockBegin
                while query.next():
                    fld = []
                    for i in xrange(query.record().count()):
                        fld.append(query.record().value(i).toString())
                    self.data[currentRow] = fld
                    currentRow += 1
                blockBegin = -1
       
        for i in self.data.copy():        # сборка мусора
            if i < self.begin - self.cacheSize or i >= self.end + self.cacheSize:
                del(self.data[i])

class DbData(QObject):
    """
    DbData(QSqlDatabase db)
    С классом можно обращаться как с обычным списком,
    любой индекс будет корректен. Если строка не загружена,
    то возвращается None. Элементы списка - словари {field:data}"""


    def __init__(self, db):
        QObject.__init__(self)
        self.thread = DbThread(db)
        self.connect(self.thread, SIGNAL('finished()'), self.threadFinished)
        self.lastBegin = -1
        self.lastEnd = -1
        self.fin = True

    def __getitem__(self, index):
        """
        Получение строки данных по индексу.
        dbData.__getitem__(i) <==> dbData[i]
        """
        if self.thread.data.has_key(index):
            return dict(zip(self.thread.queryInfo['fields'], self.thread.data[index]))
        else:
            return None

    def __setitem__(self, index, item):
        """
        Присваивание строки данных по индексу.
        dbData.__setitem__(i, data) <==> dbData[i] = data
        """
        pass  # Не реализовано и не надо

    def start(self, newBegin, newEnd):
        """
        start(begin, end)
        Запуск процесса получения данных.
        begin = первая строка
        end = последняя строка + 1
        """
        if not self.fin:                # Здесь мы ожидаем окончания потока, хотя лучше бы его убивать,
            self.lastBegin = newBegin   # но это почему-то глючит. :( А сейчас мы немного теряем в производительности,
            self.lastEnd = newEnd       # но есть мнение, что выигрываем в нагрузке на сервер.
        else:
            self.thread.setBounds(newBegin, newEnd) # Устанавливаем границы, которые были запрошены последними
            self.fin = False                        # и запускаем поток
            self.thread.start()
            self.lastBegin = -1

    def threadFinished(self):
        """
        Слот окончания работы потока. Если других запросов
        во время работы не было, генерирует сигнал finished()
        """
        if self.lastBegin > -1:
            self.thread.setBounds(self.lastBegin, self.lastEnd)
            self.fin = False           
            self.thread.start()
            self.lastBegin = -1
        else:
            self.emit(SIGNAL('finished()'))
            self.fin = True
           
    def getCacheSize(self):
        return self.thread.cacheSize
    def setCacheSize(self, cacheSize):
        self.thread.cacheSize = cacheSize
    cacheSize = property(getCacheSize, setCacheSize)

db_model.py
Код:
# -*- coding: utf-8 -*-

from PyQt4.QtCore import *
from PyQt4.QtSql import *
from db_data import DbData

class DbAbstractModel(QAbstractTableModel):
   
    def __init__(self, database, parent=None):
        self.rCnt = None
        self.database = database
        self.dbData = DbData(database)
        self.connect(self.dbData, SIGNAL('finished()'), self.dbFinished)
        self.queryInfo = {}
        self.queryPrepared = {}
        self.colList = []
        QAbstractTableModel.__init__(self, parent)

    def getRowCount(self):
        qry = QSqlQuery(self.database)
        qry.exec_('SELECT COUNT(*) FROM %(tables)s' % (self.queryPrepared))
        qry.first()
        self.rCnt = qry.record().value('count').toInt()[0]

    def viewportChanged(self, begin, end):
        self.dbData.start(begin, end)

    def dbFinished(self):
        self.emit(SIGNAL('layoutChanged()'))

    def rowCount(self, parent=QModelIndex()):
        if self.rCnt == None:
            self.getRowCount()
        return self.rCnt

    def columnCount(self, parent=QModelIndex()):
        return len(self.colList)

    def data(self, index, role = Qt.DisplayRole):
        if role == Qt.DisplayRole:
            if self.dbData[index.row()]:
                return self.dbData[index.row()][self.colList[index.column()]]
        return QVariant()
   
    def setQueryInfo(self, queryInfo):
        """
        setQueryInfo(dict('tables':[], 'fields':[], 'orders':[]))
        Параметр передает в словаре списки таблиц, полей и сортировки
        """
        self.queryInfo = queryInfo
        for key in queryInfo:
            self.queryPrepared[key] = ','.join(queryInfo[key])

        if len(queryInfo['pkey']):
            self.queryPrepared['orders'] += ',' + self.queryPrepared['pkey']

        self.dbData.thread.queryInfo = queryInfo
        self.dbData.thread.queryPrepared = self.queryPrepared
        self.dataReset()

    def setCacheSize(self, cacheSize):
        self.dbData.cacheSize = cacheSize
       
    def headerData(self, section, orientation, role = Qt.DisplayRole):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.colList[section]
        return QAbstractTableModel.headerData(self, section, orientation, role)
           
    def dataReset(self):
        self.dbData.thread.terminate()
        self.dbData.thread.data.clear()
        self.getRowCount()

Здесь тоже много чего лишнего, но уж разбирайтесь. Подмигивающий

В представлении надо реализовать вызов viewportChanged(begin, end) модели по событиям изменения размера вьюпорта и скроллингу.

жаль что на питоне, я С/С++ шарю - буду дуплить
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.068 секунд. Запросов: 20.