At the center of my python/Qt application is a tabular view using QTreeView. In one column, I have implemented sparklines by subclassing QStyledItemDelegate
, and setting the data items in the appropriate column to be numpy arrays, and plotting these in the delegate's paint method.
My line plots go slightly outside the bounding boxes, but I like this effect (and I would like to keep it):
However, when I brush downwards, some repainting and somehow, some background repainting occurs, resulting in a temporary image where the neutral background breaks up the overpainted lines:
When I leave the window, or touch the header, some repainting happens again, back to the first image.
How and where is this background repainting happening, and what can I do to affect it? I am surprised because my user code overrides the delegates paint method and only draws lines.
def paint(self, painter, option, index):
data = index.data(UserRole+1)
rectF = option.rect.toRectF()
ndims = self.ndims
yscale = self.yscale
midHeight = rectF.top() + rectF.height()/2
ctrLine = QtCore.QLineF( rectF.left(), midHeight,
rectF.right(), midHeight )
painter.setPen( self.midPen )
painter.drawLine( ctrLine )
painter.setPen( self.linePen )
segWidth = rectF.width() / (ndims-1)
for s in range(ndims-1):
seg = data[s:s+2]
segProj = -seg / yscale * rectF.height()
segLine = QtCore.QLineF( rectF.left() + s*segWidth,
midHeight + segProj[0],
rectF.left() + (s+1)*segWidth,
midHeight + segProj[1] )
painter.drawLine( segLine )
I tried setting item.setBackground( brush )
with either an opaque or a transparent QColor. Neither of these did anything because my paint code is never calling any background painting.
Update: based on the critique of @musicamante, I developed this approach based on QTreeWidget.itemEntered
.
First, I changed my code to be able to use QTreeWidget
. I connected the itemEntered
signal to an application-level function that calls emitDataChanged
(from QTreeWidgetItem
) on all items.
This requests repaint on mouse hover, seeming to cover all the cases except for when the mouse exits the bottom item. This depicts this state:
We want to detect the event where the mouse leaves the bottom item. In this approach, we develop a signal that detects leaving any item.
In a subclass of QTreeWidget
, we have a function that maintains a variable for the last entered item, and detects changes in this to emit a new itemExited
Signal.
def updateItemEntered(self, item):
if item != self.lastItemEntered:
self.itemExited.emit( self.lastItemEntered )
self.lastItemEntered = item
This function is called in response to the tree's itemEntered
signal, as well as from within the override of mouseMoveEvent
.
def mouseMoveEvent(self,event):
super().mouseMoveEvent(event)
item = self.itemAt( event.position().toPoint() )
self.updateItemEntered(item)
As above, when itemExited
is detected, update all items via emitDataChanged
.
In this approach, repaint requests are triggered only by the mouse crossing boundaries, avoiding any infinite recursion.