diff --git a/pyqtgraph/graphicsItems/GraphicsLayout.py b/pyqtgraph/graphicsItems/GraphicsLayout.py index 6ec38fb5..c0db5890 100644 --- a/pyqtgraph/graphicsItems/GraphicsLayout.py +++ b/pyqtgraph/graphicsItems/GraphicsLayout.py @@ -23,6 +23,7 @@ class GraphicsLayout(GraphicsWidget): self.setLayout(self.layout) self.items = {} ## item: [(row, col), (row, col), ...] lists all cells occupied by the item self.rows = {} ## row: {col1: item1, col2: item2, ...} maps cell location to item + self.itemBorders = {} ## {item1: QtGui.QGraphicsRectItem, ...} border rects self.currentRow = 0 self.currentCol = 0 self.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)) @@ -39,8 +40,10 @@ class GraphicsLayout(GraphicsWidget): See :func:`mkPen ` for arguments. """ self.border = fn.mkPen(*args, **kwds) - self.update() - + + for borderRect in self.itemBorders.values(): + borderRect.setPen(self.border) + def nextRow(self): """Advance to next row for automatic item placement""" self.currentRow += 1 @@ -119,7 +122,17 @@ class GraphicsLayout(GraphicsWidget): self.rows[row2] = {} self.rows[row2][col2] = item self.items[item].append((row2, col2)) - + + borderRect = QtGui.QGraphicsRectItem() + + borderRect.setParentItem(self) + borderRect.setZValue(1e3) + borderRect.setPen(fn.mkPen(self.border)) + + self.itemBorders[item] = borderRect + + item.geometryChanged.connect(self._updateItemBorder) + self.layout.addItem(item, row, col, rowspan, colspan) self.nextColumn() @@ -129,15 +142,7 @@ class GraphicsLayout(GraphicsWidget): def boundingRect(self): return self.rect() - - def paint(self, p, *args): - if self.border is None: - return - p.setPen(fn.mkPen(self.border)) - for i in self.items: - r = i.mapRectToParent(i.boundingRect()) - p.drawRect(r) - + def itemIndex(self, item): for i in range(self.layout.count()): if self.layout.itemAt(i).graphicsItem() is item: @@ -150,13 +155,16 @@ class GraphicsLayout(GraphicsWidget): self.layout.removeAt(ind) self.scene().removeItem(item) - for r,c in self.items[item]: + for r, c in self.items[item]: del self.rows[r][c] del self.items[item] + + item.geometryChanged.disconnect(self._updateItemBorder) + del self.itemBorders[item] + self.update() def clear(self): - items = [] for i in list(self.items.keys()): self.removeItem(i) @@ -168,4 +176,14 @@ class GraphicsLayout(GraphicsWidget): def setSpacing(self, *args): self.layout.setSpacing(*args) - \ No newline at end of file + + def _updateItemBorder(self): + if self.border is None: + return + + item = self.sender() + if item is None: + return + + r = item.mapRectToParent(item.boundingRect()) + self.itemBorders[item].setRect(r) diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index 27fb8268..a542e916 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -14,6 +14,7 @@ from ...Qt import isQObjectAlive __all__ = ['ViewBox'] + class WeakList(object): def __init__(self): @@ -34,10 +35,12 @@ class WeakList(object): yield d i -= 1 + class ChildGroup(ItemGroup): def __init__(self, parent): ItemGroup.__init__(self, parent) + self.setFlag(self.ItemClipsChildrenToShape) # Used as callback to inform ViewBox when items are added/removed from # the group. @@ -64,6 +67,12 @@ class ChildGroup(ItemGroup): listener.itemsChanged() return ret + def shape(self): + return self.mapFromParent(self.parentItem().shape()) + + def boundingRect(self): + return self.mapRectFromParent(self.parentItem().boundingRect()) + class ViewBox(GraphicsWidget): """ @@ -185,6 +194,13 @@ class ViewBox(GraphicsWidget): self.background.setPen(fn.mkPen(None)) self.updateBackground() + self.border = fn.mkPen(border) + + self.borderRect = QtGui.QGraphicsRectItem(self.rect()) + self.borderRect.setParentItem(self) + self.borderRect.setZValue(1e3) + self.borderRect.setPen(self.border) + ## Make scale box that is shown when dragging on the view self.rbScaleBox = QtGui.QGraphicsRectItem(0, 0, 1, 1) self.rbScaleBox.setPen(fn.mkPen((255,255,100), width=1)) @@ -207,7 +223,6 @@ class ViewBox(GraphicsWidget): self.setAspectLocked(lockAspect) - self.border = fn.mkPen(border) if enableMenu: self.menu = ViewBoxMenu(self) else: @@ -428,8 +443,10 @@ class ViewBox(GraphicsWidget): self.updateViewRange() self._matrixNeedsUpdate = True self.background.setRect(self.rect()) + self.borderRect.setRect(self.rect()) self.sigStateChanged.emit(self) self.sigResized.emit(self) + self.childGroup.prepareGeometryChange() def viewRange(self): """Return a the view's visible range as a list: [[xmin, xmax], [ymin, ymax]]""" @@ -571,7 +588,7 @@ class ViewBox(GraphicsWidget): self._autoRangeNeedsUpdate = True elif changed[1] and self.state['autoVisibleOnly'][0] and (self.state['autoRange'][1] is not False): self._autoRangeNeedsUpdate = True - + self.sigStateChanged.emit(self) def setYRange(self, min, max, padding=None, update=True): @@ -1054,6 +1071,19 @@ class ViewBox(GraphicsWidget): def xInverted(self): return self.state['xInverted'] + def setBorder(self, *args, **kwds): + """ + Set the pen used to draw border around the view + + If border is None, then no border will be drawn. + + Added in version 0.9.10 + + See :func:`mkPen ` for arguments. + """ + self.border = fn.mkPen(*args, **kwds) + self.borderRect.setPen(self.border) + def setAspectLocked(self, lock=True, ratio=1): """ If the aspect ratio is locked, view scaling must always preserve the aspect ratio. @@ -1499,7 +1529,7 @@ class ViewBox(GraphicsWidget): if any(changed): self._matrixNeedsUpdate = True self.update() - + # Inform linked views that the range has changed for ax in [0, 1]: if not changed[ax]: