Уведомления

Группа в Telegram: @pythonsu

#1 Май 3, 2010 09:48:26

Bujhm666
От:
Зарегистрирован: 2010-03-23
Сообщения: 36
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

В документации по QT есть пример с замороженным столбцом в QTableView, а в доке по PyQt4 он отсутствует (или может я не нашел). Если кто пробывал реализовать это на PyQt поделитесь пожалуйста примером. Пробовал переписать сам, но опыта не хватает, а реализация интересная.



Офлайн

#2 Май 3, 2010 10:09:59

Bujhm666
От:
Зарегистрирован: 2010-03-23
Сообщения: 36
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

Офлайн

#3 Май 3, 2010 14:49:40

Bujhm666
От:
Зарегистрирован: 2010-03-23
Сообщения: 36
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

Все, вроде разобрался. Не понял только для чего переопределяется moveCursor, все и без него прекрасно работет. Я его пока закомментировал. И еще может кто объяснит своими словами вот эту строку - self.viewport().stackUnder(self.frozenTableView), из документации не очень понял.

Вот собственно Frozen Column Example (немного переделанный). Критика приветствуется.

# -*- coding: utf-8 -*-

import sys
from PyQt4 import QtCore, QtGui, QtSql


class MyWindow(QtGui.QWidget):
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)

# create table
table = FreezeTableWidget(self)

# layout
layout = QtGui.QVBoxLayout()
layout.addWidget(table)
self.setLayout(layout)


class FreezeTableWidget(QtGui.QTableView):
def __init__(self, parent = None, *args):
QtGui.QTableView.__init__(self, parent, *args)

# Минимальный размер окна
self.setMinimumSize(800, 600)

# set the table model
tm = MyTableModel(self)

# set the proxy model
pm = QtGui.QSortFilterProxyModel(self)
pm.setSourceModel(tm)

# назначаем модель данных для TableView
self.setModel(pm)

# ***ВИДЖЕТ ЗАФИКСИРОВАННЫХ СТОЛБЦОВ***
# (будет расположен поверх основного)
self.frozenTableView = QtGui.QTableView(self)
# устанавливаем модель для виджета зафиксированных столбцов
self.frozenTableView.setModel(pm)
# скрываем заголовки строк
self.frozenTableView.verticalHeader().hide()
# виджет не принимает фокус
self.frozenTableView.setFocusPolicy(QtCore.Qt.NoFocus)
# пользователь не может изменять размер столбцов
self.frozenTableView.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed)
# отключаем показ границ виджета
self.frozenTableView.setStyleSheet('''border: none; background-color: #8EDE21;
selection-background-color: #999''')
# режим выделения как у основного виджета
self.frozenTableView.setSelectionModel(QtGui.QAbstractItemView.selectionModel(self))
# убираем полосы прокрутки
self.frozenTableView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.frozenTableView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

# помещает дополнительный виджет на передний план
self.viewport().stackUnder(self.frozenTableView)

# Вход в режим редактирования - еще одним щелчком мыши
self.setEditTriggers(QtGui.QAbstractItemView.SelectedClicked)

# hide gridnt()
# self.setShowGrid(False)

# Установка шрифта
self.setStyleSheet('font: 10pt "Courier New"')

# Установка свойств заголовков столбцов
hh = self.horizontalHeader()
# выравнивание текста по центру
hh.setDefaultAlignment(QtCore.Qt.AlignCenter)
# включаем растягивание последнего столбца
hh.setStretchLastSection(True)

# Установка ширины столбцов по содержимому
# self.resizeColumnsToContents()

# Установка ширины столбцов
ncol = tm.columnCount(self)
for col in xrange(ncol):
if col == 0:
# устанавливаем размер
self.horizontalHeader().resizeSection(col, 60)
# фиксируем ширину
self.horizontalHeader().setResizeMode(col, QtGui.QHeaderView.Fixed)
# ширина фиксированных столбцов - как у основного виджета
self.frozenTableView.setColumnWidth(col, self.columnWidth(col))
elif col == 1:
self.horizontalHeader().resizeSection(col, 150)
self.horizontalHeader().setResizeMode(col, QtGui.QHeaderView.Fixed)
self.frozenTableView.setColumnWidth(col, self.columnWidth(col))
else:
self.horizontalHeader().resizeSection(col, 100)
# скрываем не нужные столбцы у виджета зафиксированных столбцов
self.frozenTableView.setColumnHidden(col, True)

# Сортировка по щелчку на заголовке столбца
self.frozenTableView.setSortingEnabled(True)
self.frozenTableView.sortByColumn(0, QtCore.Qt.AscendingOrder)

# Включаем чередующуюся подсветку строк
self.setAlternatingRowColors(True)

# Установка свойств заголовков строк
vh = self.verticalHeader()
vh.setDefaultSectionSize(25) # высота строк
vh.setDefaultAlignment(QtCore.Qt.AlignCenter) # выравнивание текста по центру
vh.setVisible(True)
# высота строк - как у основного виджета
self.frozenTableView.verticalHeader().setDefaultSectionSize(vh.defaultSectionSize())

# Альтернативная устновка высоты строк
# nrows = tm.rowCount(self)
# for row in xrange(nrows):
# self.setRowHeight(row, 25)

# показываем наш дополнительный виджет
self.frozenTableView.show()
# устанавливаем ему размеры как у основного
self.updateFrozenTableGeometry()

self.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.frozenTableView.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)

# Создаем соединения
tm.dataChanged.connect(self.test)
# connect the headers and scrollbars of both tableviews together
self.horizontalHeader().sectionResized.connect(self.updateSectionWidth)
self.verticalHeader().sectionResized.connect(self.updateSectionHeight)
self.frozenTableView.verticalScrollBar().valueChanged.connect(self.verticalScrollBar().setValue)
self.verticalScrollBar().valueChanged.connect(self.frozenTableView.verticalScrollBar().setValue)

def test(self, index):
print index.row(), index.column()

def updateSectionWidth(self, logicalIndex, oldSize, newSize):
if logicalIndex==0 or logicalIndex==1:
self.frozenTableView.setColumnWidth(logicalIndex, newSize)
self.updateFrozenTableGeometry()

def updateSectionHeight(self, logicalIndex, oldSize, newSize):
self.frozenTableView.setRowHeight(logicalIndex, newSize)

def resizeEvent(self, event):
QtGui.QTableView.resizeEvent(self, event)
self.updateFrozenTableGeometry()

def scrollTo(self, index, hint):
if index.column() > 1:
QtGui.QTableView.scrollTo(self, index, hint)

def updateFrozenTableGeometry(self):
if self.verticalHeader().isVisible():
self.frozenTableView.setGeometry(self.verticalHeader().width() + self.frameWidth(),
self.frameWidth(), self.columnWidth(0) + self.columnWidth(1),
self.viewport().height() + self.horizontalHeader().height())
else:
self.frozenTableView.setGeometry(self.frameWidth(),
self.frameWidth(), self.columnWidth(0) + self.columnWidth(1),
self.viewport().height() + self.horizontalHeader().height())

# переопределяем функцию moveCursor, для корректного скрола влево с клавиатуры
def moveCursor(self, cursorAction, modifiers):
current = QtGui.QTableView.moveCursor(self, cursorAction, modifiers)
if cursorAction == self.MoveLeft and current.column() > 1 and self.visualRect(current).topLeft().x() < (self.frozenTableView.columnWidth(0) + self.frozenTableView.columnWidth(1)):
newValue = self.horizontalScrollBar().value() + self.visualRect(current).topLeft().x() - (self.frozenTableView.columnWidth(0) + self.frozenTableView.columnWidth(1))
self.horizontalScrollBar().setValue(newValue)
return current


class MyTableModel(QtCore.QAbstractTableModel):
def __init__(self, parent = None, *args):
QtCore.QAbstractTableModel.__init__(self, parent, *args)
self.colLabels = ['Col1', 'Col2', 'Col3', 'Col4', 'Col5', 'Col6',
'Col7', 'Col8', 'Col9', 'Col10'] # Заголовки столбцов
self.dataCached = [
[111,'cell12','cell13','cell14','cell15','cell12','cell13','cell14','cell15','cell16'],
[112,'cell22','cell23','cell24','cell25','cell26','cell27','cell28','cell29','cell30'],
[113,'cell32','cell33','cell34','cell35','cell36','cell37','cell38','cell39','cell40'],
[114,'cell42','cell43','cell44','cell45','cell46','cell47','cell48','cell49','cell50'],
[115,'cell52','cell53','cell54','cell55','cell56','cell57','cell58','cell59','cell60'],
[116,'cell62','cell63','cell64','cell65','cell66','cell67','cell68','cell69','cell70'],
[117,'cell72','cell73','cell74','cell75','cell76','cell77','cell78','cell79','cell80'],
[118,'cell82','cell83','cell84','cell85','cell86','cell87','cell88','cell89','cell90'],
[119,'cell12','cell13','cell14','cell15','cell12','cell13','cell14','cell15','cell16'],
[120,'cell22','cell23','cell24','cell25','cell26','cell27','cell28','cell29','cell30'],
[121,'cell32','cell33','cell34','cell35','cell36','cell37','cell38','cell39','cell40'],
[122,'cell42','cell43','cell44','cell45','cell46','cell47','cell48','cell49','cell50'],
[123,'cell52','cell53','cell54','cell55','cell56','cell57','cell58','cell59','cell60'],
[124,'cell62','cell63','cell64','cell65','cell66','cell67','cell68','cell69','cell70'],
[125,'cell72','cell73','cell74','cell75','cell76','cell77','cell78','cell79','cell80'],
[126,'cell82','cell83','cell84','cell85','cell86','cell87','cell88','cell89','cell90'],
[127,'cell12','cell13','cell14','cell15','cell12','cell13','cell14','cell15','cell16'],
[128,'cell22','cell23','cell24','cell25','cell26','cell27','cell28','cell29','cell30'],
[129,'cell32','cell33','cell34','cell35','cell36','cell37','cell38','cell39','cell40'],
[130,'cell42','cell43','cell44','cell45','cell46','cell47','cell48','cell49','cell50'],
[131,'cell52','cell53','cell54','cell55','cell56','cell57','cell58','cell59','cell60'],
[132,'cell62','cell63','cell64','cell65','cell66','cell67','cell68','cell69','cell70'],
[133,'cell72','cell73','cell74','cell75','cell76','cell77','cell78','cell79','cell80'],
[134,'cell82','cell83','cell84','cell85','cell86','cell87','cell88','cell89','cell90'],
[135,'cell82','cell83','cell84','cell85','cell86','cell87','cell88','cell89','cell90'],
[136,'cell82','cell83','cell84','cell85','cell86','cell87','cell88','cell89','cell90']
] # Область данных

# Возвращает количество строк
def rowCount(self, parent):
return len(self.dataCached)

# Возвращает количество столбцов
def columnCount(self, parent):
return len(self.colLabels)

# Возвращает значение ячейки
def get_value(self, index):
i = index.row()
j = index.column()
return self.dataCached[i][j]

# Значение и свойства ячейки данных в зависимости от роли
def data(self, index, role):
if not index.isValid():
return QtCore.QVariant()
value = self.get_value(index)
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
return QtCore.QVariant(value)
elif role == QtCore.Qt.TextAlignmentRole:
return QtCore.QVariant(QtCore.Qt.AlignCenter)
return QtCore.QVariant()

# Изменение значения ячейки
def setData(self, index, value, role):
if index.isValid() and role == QtCore.Qt.EditRole:
self.dataCached[index.row()][index.column()] = QtCore.QVariant(value)
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex, QModelIndex)"), index, index)
return True
else:
return False

# Заголовки столбцов и строк
def headerData(self, section, orientation, role):
#заголовки столбцов
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
header = QtCore.QVariant(self.colLabels[section])
return header
#заголовки строк
if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant("%s" % str(section + 1))

return QtCore.QVariant()

# Переопределяем метод flags (включаем выделение и редактирование в ячейках)
def flags(self, index):
if not index.isValid():
return QtCore.Qt.ItemIsEnabled
elif index.column() > 1:
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable

return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable


if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())



Отредактировано (Май 7, 2010 11:09:41)

Офлайн

#4 Май 3, 2010 21:23:16

villager
От:
Зарегистрирован: 2008-11-04
Сообщения: 111
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

проверить невозможно - отсутствует модуль connection

я раньше вот здесь пробовал эту проблему решить:
http://www.python.su/forum/viewtopic.php?id=5328



Офлайн

#5 Май 4, 2010 08:33:18

Bujhm666
От:
Зарегистрирован: 2010-03-23
Сообщения: 36
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

Этот модуль не нужен, просто я делал изначально под postgresql, потом просто поменял модель под локальные данные для примера, а про этот модуль забыл. Код поправил. Должно все работать.

Ваш пример я видел, от него и начал копать, просто у троллей все уже с рюшечками - красиво.



Офлайн

#6 Май 4, 2010 23:00:19

villager
От:
Зарегистрирован: 2008-11-04
Сообщения: 111
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

Спасибо

когда я пробовал, версия Qt была пониже :), не было таких примеров



Офлайн

#7 Май 5, 2010 10:30:01

Bujhm666
От:
Зарегистрирован: 2010-03-23
Сообщения: 36
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

moveCursor переопределять надо, иначе будет некорректный скрол влево с клавиатуры. Код поправил.



Офлайн

#8 Дек. 1, 2010 16:33:20

dark123us
От:
Зарегистрирован: 2010-12-01
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

Смотрю на пример, читаю документацию, прозрение пока не пришло, как все это работает.
В классе class FreezeTableWidget в объявлении
Изменил строку tm = MyTableModel(self) на self.tm = MyTableModel(self), дабы можно было добраться до self.dataCached
Затем в class MyWindow
добавил
table.tm.dataCached=[,
]
что позволило изменить данные в таблице, но не изменило количество строк и столбцов.
Подскажите, как программно изменить данные (т.е. правильно ли я изменяю данные), а также как изменить количество строк столбцов в данном примере?



Офлайн

#9 Дек. 3, 2010 07:12:04

hellslade
От:
Зарегистрирован: 2008-01-28
Сообщения: 240
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

table.tm.colLabels =



Офлайн

#10 Дек. 3, 2010 08:26:41

dark123us
От:
Зарегистрирован: 2010-12-01
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Frozen Column Example => PyQt4

Делал и так, но приходится переинициализировать tm = MyTableModel(self), изменив __init__ в классе FreezeTableWidget, т.е. любое изменение dataCached и colLabels изменяют данные в ячейках и хедере, но не изменяют количество строк, столбцов. Вылезла еще проблема, как узнать в какой ячейке был произведен клик, к примеру для вызова контекстного меню. Видно просто еще не понимаю, как работает QAbstractTableModel.



Отредактировано (Дек. 3, 2010 08:28:56)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version