QTableView:选中的细胞混乱了

时间:2014-02-03 13:43:25

标签: pyqt pyqt4 selection paint qtableview

我想自定义QTableView的外观。因此,我决定禁用网格线并自己进行绘画。我将QStyledItemDelegate子类化并重新实现其paint方法。一切正常,直到我在表格中选择一些单元格。选择不知何故弄乱了这幅画......

最后,我提供了一个小的演示应用程序。

如果您运行该应用程序,只需单击名为“Night”的单元格,您就会明白我的意思。我怎么能改变呢?

我想在用户选择一个单元格之后调用重新绘制,但这不起作用。

如果有人可以帮助我,我真的很感激。非常感谢!

main.py

from PyQt4 import QtCore
from PyQt4 import QtGui

import sys

from productiontable import productionTableModel
from productiontable import productionTableBorder

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    tableview = QtGui.QTableView()
    model = productionTableModel([["Prod. 1"], ["Prod. 2"], ["Prod. 3"], ["Prod. 4"], ["Prod. 5"]])

    tableview.setModel(model)

    tableview.resizeColumnsToContents()
    tableview.verticalHeader().setVisible(False)
    tableview.horizontalHeader().setVisible(False)
    tableview.setFrameStyle(QtGui.QFrame.NoFrame)
    tableview.setShowGrid(False)
    tableview.setFocusPolicy(QtCore.Qt.NoFocus) #remove dotted line, when cell has focus
    tableview.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

    d = productionTableBorder()
    tableview.setItemDelegate(d)

    tableview.resize(100, 300)
    tableview.show()

    sys.exit(app.exec_())

productiontable.py

from PyQt4 import QtCore
from PyQt4 import QtGui

class productionTableBorder(QtGui.QStyledItemDelegate):
    def __init__(self, parent = None):
        QtGui.QStyledItemDelegate.__init__(self, parent)

    def paint(self, painter, option, index):
        QtGui.QStyledItemDelegate.paint(self, painter, option, index)
        if index.row()%2 == 0:
            painter.save() 
            painter.setPen(QtGui.QPen(QtCore.Qt.white, 4))

            #draw a white line from start to end
            start = QtCore.QPoint(option.rect.x(), option.rect.y())
            end = QtCore.QPoint(option.rect.x() + option.rect.width(), option.rect.y())
            painter.drawLine(start, end)

            painter.restore()

class productionTableModel(QtCore.QAbstractTableModel):
    def __init__(self, lst = [[]], parent = None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.__lst = lst

    def rowCount(self, parent = None):
        return len(self.__lst) * 2

    def columnCount(self,  parent = None):
        return 2

    def data(self, index, role):
        col = index.column()
        row = index.row()
        if role == QtCore.Qt.DisplayRole:
            if col == 0:
                if row%2 == 0:
                    return self.__lst[row/2][col]
            if col == 1:
                if row%2 == 0:
                    return "Day"
                else:
                    return "Night"

        if role == QtCore.Qt.BackgroundRole:
            return QtGui.QColor(188, 250, 213)

    def flags(self, index):
        return (QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.NoItemFlags)    

1 个答案:

答案 0 :(得分:0)

好的,我明白了。

要绘制自己的网格线,需要子类QTableView ,子类化QStyledItemDelegate不起作用!如果您继承QStyledItemDelegate并覆盖其paint()方法,则还需要重新计算单元格的大小(因为网格线)。

更好地继承QTableView并在paintEvent中绘制网格线。

这是我的解决方案(受this主题启发):

<强> main.py

from PyQt4 import QtCore
from PyQt4 import QtGui

import sys

from productiontable import productionTableModel
from productiontable import customTable

if __name__ == "__main__":

    app = QtGui.QApplication(sys.argv)

    tableview = customTable()
    model = productionTableModel([["Prod. 1"], ["Prod. 2"], ["Prod. 3"], ["Prod. 4"], ["Prod. 5"]])

    tableview.setModel(model)

    tableview.resizeColumnsToContents()
    tableview.verticalHeader().setVisible(False)
    tableview.horizontalHeader().setVisible(False)
    tableview.setFrameStyle(QtGui.QFrame.NoFrame)
    tableview.setShowGrid(False)
    tableview.setFocusPolicy(QtCore.Qt.NoFocus) #remove dotted line, when cell has focus
    tableview.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)

    tableview.resize(100, 300)
    tableview.show()

    sys.exit(app.exec_())

productiontable.py

from PyQt4 import QtCore
from PyQt4 import QtGui

class customTable(QtGui.QTableView):
    def __init__(self, parent = None):
        QtGui.QTableView.__init__(self, parent)


    def paintEvent(self, event):
        super(customTable, self).paintEvent(event)

        #set the pen
        pen = QtGui.QPen(QtCore.Qt.white, 4)

        # 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 xrange(firstVisualRow, lastVisualRow + 1, 2):
            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
                top = rowY
                bottom = rowY
                left = colX
                right = colX + colw

                # Save the painter and set the pen
                painter.save()
                painter.setPen(pen)

                # Draw Horizontal Lines
                painter.drawLine(left, bottom, right, bottom)

                # Restore painter
                painter.restore()


class productionTableModel(QtCore.QAbstractTableModel):
    def __init__(self, lst = [[]], parent = None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.__lst = lst

    def rowCount(self, parent = None):
        return len(self.__lst) * 2

    def columnCount(self,  parent = None):
        return 2

    def data(self, index, role):
        col = index.column()
        row = index.row()
        if role == QtCore.Qt.DisplayRole:
            if col == 0:
                if row%2 == 0:
                    return self.__lst[row/2][col]
            if col == 1:
                if row%2 == 0:
                    return "Day"
                else:
                    return "Night"

        if role == QtCore.Qt.BackgroundRole:
            return QtGui.QColor(188, 250, 213)

    def flags(self, index):
        return (QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable)