import random
from PyQt4 import QtCore, QtGui
""" Test Setup Data Model
In this model the first row of the table is always empty.
"""
def __init__(self, dataset, parent=None):
super(TestModel, self).__init__(parent)
self.ds = dataset
def columnCount(self, index=model_idx()):
return len(self.ds.keys())
def rowCount(self, index=model_idx()):
return max(map(len, self.ds.values()))
def data(self, index, role=QtCore.Qt.DisplayRole):
row = index.row()
col = index.column()
try:
field = self.ds.keys()[col]
except IndexError:
if (role == QtCore.Qt.DisplayRole) or (role == QtCore.Qt.EditRole):
values = self.ds[field]
if row == 0:
k = None
elif len(values) > (row - 1):
k = values[row - 1]
else:
k = None
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal:
if role == QtCore.Qt.DisplayRole:
name = self.ds.keys()[section]
def flags(self, index):
if index.isValid():
return QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsEnabled |
QtCore.Qt.ItemIsSelectable)
""" Table View With Sparse Grid Lines
This is an example of how you can overide the paintEvent in the QTableView
to draw your own grid lines. In this particular view grid lines won't be
drawn for empty cells with the exception of the first row which if use with
the TestModel is always empty. Note this view cannot deal with cells that
span multiple rows or columns.
"""
def __init__(self, parent=None):
super(SparseTableView, self).__init__(parent)
self.setAlternatingRowColors(True)
self.setShowGrid(False)
def paintEvent(self, event):
# Call the super here first. It will draw a bunch of stuff including
# alternating background color and the text. It will also call the item
# delegate if one is set. We do this first otherwise our gridlines
# might get painted over.
super(SparseTableView, self).paintEvent(event)
# Get all the specifics about the grid color and size and setup the
# grid pen
sh
= QtGui.
QStyle.
SH_Table_GridLineColor gridHint = self.style().styleHint(sh, self.viewOptions())
# Do this to convert from signed int to unsigned int
gridHint &= 0xffffffff
gridColor
= QtGui.
QColor.
fromRgb(gridHint
) gridSize = 1
gridPen
= QtGui.
QPen(gridColor, gridSize, self.
gridStyle())
# Create the painter
painter
= QtGui.
QPainter(self.
viewport())
# Shortcuts to vertical and horizontal headers
vh = self.verticalHeader()
hh = self.horizontalHeader()
# Get the first and last rows that are visible in the view and if the
# last visiable row returns -1 set it to the row count
firstVisualRow = max([vh.visualIndexAt(0), 0])
lastVisualRow = vh.visualIndexAt(vh.viewport().height())
if lastVisualRow == -1:
lastVisualRow = self.model().rowCount(self.rootIndex()) - 1
# Get the first and last columns that are visible in the view and if
# if the last visible column is -1 set it to the column count.
firstVisualColumn = max([hh.visualIndexAt(0), 0])
lastVisualColumn = hh.visualIndexAt(hh.viewport().width())
if lastVisualColumn == -1:
lastVisualColumn = hh.count() - 1
# Iterate through each row and column drawing only the
# bottom and left side lines for each cell. Skipping rows and columns
# that are hidden
for vrow in range(firstVisualRow, lastVisualRow + 1):
row = vh.logicalIndex(vrow)
FirstRow = (vrow == 0)
if vh.isSectionHidden(row):
continue
# Get top left Y coordinate and row height
rowY = self.rowViewportPosition(row)
rowh = self.rowHeight(row)
for vcol in range(firstVisualColumn, lastVisualColumn + 1):
col = hh.logicalIndex(vcol)
FirstColumn = (vcol == 0)
if hh.isSectionHidden(col):
continue
# Get top left X coordinate and column width
colX = self.columnViewportPosition(col)
colw = self.columnWidth(col)
# Get the model index
index = self.model().createIndex(row, col)
# Specify top, bottom, left and right of the cell accounting
# for the with of the grid pen.
top = rowY
bottom = rowY + rowh - gridSize
left = colX
right = colX + colw - gridSize
# Boolean holder values for if this cell has data or if the
# adjacent cell has data. If the adjacent cell has data. We
# Still need to draw some lines.
cell_has_data = index.data().toBool()
adj_idx = index.model().createIndex(row, col + 1)
adjacent_cell_filled = adj_idx.data().toBool()
# Save the painter and set the pen
painter.save()
painter.setPen(gridPen)
# If the cell is empty erase the back ground that way the
# alternating background colors won't show up
if not cell_has_data:
painter.eraseRect(colX, rowY, colw, rowh)
# Draw Horizontal Lines
# Only do this if the cell has data or is in the first row
# We draw only the bottom line
if cell_has_data or FirstRow:
painter.drawLine(left, bottom, right, bottom)
# Draw Vertical Lines
# Only do this if this cell or the right side adjacent cell has
# data or we are in the first row.
# We draw only the right side line
if cell_has_data or adjacent_cell_filled or FirstRow:
painter.drawLine(right, top, right, bottom)
# Restore painter
painter.restore()
def SetupData():
random.seed(94546)
space = xrange(5000)
data = {}
for k in range(5):
key = 'Data Field {}'.format(k)
ds = random.sample(space, 10)
num_toss = random.randint(0,10)
for it in range(num_toss):
idx = random.randint(0,len(ds) - 1)
ds.pop(idx)
data[key] = ds
return data
if __name__ == "__main__":
import sys
if not app:
data = SetupData()
form = SparseTableView()
model = TestModel(data, form)
form.setModel(model)
form.show()
sys.exit(app.exec_())
Bookmarks