PDA

View Full Version : Need help figuring out how to paint graphicsRectItems correctly



lightning2911
5th May 2010, 10:40
I am stuck with two versions of code that only differ in the way the rect is assigned. How are they different? and how does this effect the different behaviour?

(What I want is rectangles that are painted correctly with another style for selected ones and that can be moved around if in selection mode. I distinguish the mode in self.newItem. If True I am in adding-rectangles mode and if False I am in selection mode.)

This code below produces rectangles that are
- painted "correct" (snapped to grid)

- are selectable (but not drawn in red and yellow as in the paint method but with a black dashed line; although in debugging i see that the if-code for selected is visited)

- can be moved (snapped to grid)


class DesignerBlock(QGraphicsRectItem):
def __init__(self, rect=QRectF(0, 0, 0, 0), parent=None, scene=None):
super(DesignerBlock, self).__init__(parent, scene)
self.setFlag(self.ItemIsMovable, True)
self.setFlag(self.ItemIsSelectable, True)
self.setFlag(self.ItemSendsGeometryChanges, True)
self.setPen(QPen(Qt.black, 1, Qt.SolidLine))
self.setBrush(QBrush(Qt.white, Qt.SolidPattern))
self.moving = False
self.setRect(rect) # <-----
self.setSelected(True)
self.setFocus()
self.update()

def paint(self, painter, option, widget):
pen = self.pen()
brush = self.brush()
if self.isSelected():
pen = QPen(Qt.red, 1, Qt.SolidLine)
brush = QBrush(Qt.yellow, Qt.SolidPattern)
painter.setPen(pen)
painter.setBrush(brush)
painter.drawRect(self.rect()) # <-----
super(DesignerBlock, self).paint(painter, option, widget)

def deferPosition(self, value):
big = abs(value) / SCREEN_GRID
little = abs(value) % SCREEN_GRID

if little > (SCREEN_GRID / 2):
little = 1
else:
little = 0

if value > 0:
direction = 1
else:
direction = -1

return (big + little) * SCREEN_GRID * direction


def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionChange:
x = value.toPoint().x()
y = value.toPoint().y()
newPosition = value.toPoint()

newPosition.setX(self.deferPosition(x))

newPosition.setY(self.deferPosition(y))

return newPosition
else:
return value

Now this code below (the same except the two indicated changes) makes rectangles that
- are painted only in the rect of the mouse selection (but not adjusted to snap to grid)
with that i mean that if i rubberband a rect smaller than the grid point, only this area is painted although after i force a repaint (as in window minimize/maximize) the rectitem is drawn correct from gridPoint to gridPoint.

- selected rect is painted in red and yellow

- when selecting with rubberband the view is "erased" and click select does not work and they dont move



class DesignerBlock(QGraphicsRectItem):
def __init__(self, rect=QRectF(0, 0, 0, 0), parent=None, scene=None):
super(DesignerBlock, self).__init__(parent, scene)
self.setFlag(self.ItemIsMovable, True)
self.setFlag(self.ItemIsSelectable, True)
self.setFlag(self.ItemSendsGeometryChanges, True)
self.setPen(QPen(Qt.black, 1, Qt.SolidLine))
self.setBrush(QBrush(Qt.white, Qt.SolidPattern))
self.moving = False
self.rect = rect # <----------
#self.setRect(rect)
self.setSelected(True)
self.setFocus()
self.update()

def paint(self, painter, option, widget):
pen = self.pen()
brush = self.brush()
if self.isSelected():
pen = QPen(Qt.red, 1, Qt.SolidLine)
brush = QBrush(Qt.yellow, Qt.SolidPattern)
painter.setPen(pen)
painter.setBrush(brush)
painter.drawRect(self.rect) # <-----------
#painter.drawRect(self.rect())
super(DesignerBlock, self).paint(painter, option, widget)

def deferPosition(self, value):
big = abs(value) / SCREEN_GRID
little = abs(value) % SCREEN_GRID

if little > (SCREEN_GRID / 2):
little = 1
else:
little = 0

if value > 0:
direction = 1
else:
direction = -1

return (big + little) * SCREEN_GRID * direction


def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionChange:
x = value.toPoint().x()
y = value.toPoint().y()
newPosition = value.toPoint()

newPosition.setX(self.deferPosition(x))

newPosition.setY(self.deferPosition(y))

return newPosition
else:
return value

this is scene code for handling the mouse events:


def mousePressEvent(self, mouseEvent):
self.startPos = mouseEvent.scenePos()
self.emit(SIGNAL("startSet"), self.gridPos(self.startPos))
if self.newItem == False:
super(DesignerScene, self).mousePressEvent(mouseEvent)

def mouseMoveEvent(self, mouseEvent):
self.emit(SIGNAL("updateCoords"), self.gridPos(mouseEvent.scenePos()))
super(DesignerScene, self).mouseMoveEvent(mouseEvent)

def mouseReleaseEvent(self, mouseEvent):
self.endPos = mouseEvent.scenePos()
self.emit(SIGNAL("endSet"), self.gridPos(self.endPos))
if self.newItem:
self.emit(SIGNAL("createBox"), self.gridPos(self.startPos), self.gridPos(self.endPos))
else:
super(DesignerScene, self).mousePressEvent(mouseEvent)

def createBox(self, start, end):
xs = start.x()
ys = start.y()
xe = end.x()
ye = end.y()
if ys <> ye and xs <> xe:
# insert only if not a line
self.addItem(DesignerBlock(QRectF(xs, ys, xe-xs, ye-ys).normalized()))

lightning2911
6th May 2010, 07:39
solved: the super in the paint was positioned wrong. it should go in a else after the if isSelected statement