Reputation: 353
I have been trying to learn a bit more about the QGraphicsView widget by taking a look at this example here:
Toggle QPen for selected items after QGraphicsScene selection change
I found this fairly helpful, however i noticed that upon selection there is marquee thing that pops up when an item is selected. I was looking at ways to get rid of this, and it seems like there is a consistent answer to this in C++ which I see as an example here:
https://www.qtcentre.org/threads/39659-About-QGraphicsItem-question
But i am very confused as to how to translate this into pyqt, so I was wondering if anyone can provide any insight to how to do this within the example project from the first link....
I've been searching around for possible equivalents by looking at codes such as this:
https://www.riverbankcomputing.com/pipermail/pyqt/2012-November/032110.html
Although to be honest I don't even know what the application of these example codes are...
Upvotes: 1
Views: 490
Reputation: 244351
If you want to remove the rectangle from the selection of the item in python you must use the following:
class GraphicsEllipseItem(QGraphicsEllipseItem):
def paint(self, painter, option, widget):
option.state &= ~QStyle.State_Selected
super(GraphicsEllipseItem, self).paint(painter, option, widget)
Complete script
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import random
class GraphicsEllipseItem(QGraphicsEllipseItem):
def paint(self, painter, option, widget):
option.state &= ~QStyle.State_Selected
super(GraphicsEllipseItem, self).paint(painter, option, widget)
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.setDragMode(QGraphicsView.RubberBandDrag)
self._isPanning = False
self._mousePressed = False
self.setCacheMode(QGraphicsView.CacheBackground)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setScene(MyGraphicsScene(self))
self.scene().selectionChanged.connect(self.selection_changed)
self._current_selection = []
def select_items(self, items, on):
pen = QPen(
QColor(255, 255, 255) if on else QColor(255, 128, 0),
0.5,
Qt.SolidLine,
Qt.RoundCap,
Qt.RoundJoin,
)
for item in items:
item.setPen(pen)
def selection_changed(self):
try:
self.select_items(self._current_selection, False)
self._current_selection = self.scene().selectedItems()
self.select_items(self._current_selection, True)
except RuntimeError:
pass
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self._mousePressed = True
if self._isPanning:
self.setCursor(Qt.ClosedHandCursor)
self._dragPos = event.pos()
event.accept()
else:
super(MyGraphicsView, self).mousePressEvent(event)
elif event.button() == Qt.MiddleButton:
self._mousePressed = True
self._isPanning = True
self.setCursor(Qt.ClosedHandCursor)
self._dragPos = event.pos()
event.accept()
def mouseMoveEvent(self, event):
if self._mousePressed and self._isPanning:
newPos = event.pos()
diff = newPos - self._dragPos
self._dragPos = newPos
self.horizontalScrollBar().setValue(
self.horizontalScrollBar().value() - diff.x()
)
self.verticalScrollBar().setValue(
self.verticalScrollBar().value() - diff.y()
)
event.accept()
else:
super(MyGraphicsView, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
if self._isPanning:
self.setCursor(Qt.OpenHandCursor)
else:
self._isPanning = False
self.setCursor(Qt.ArrowCursor)
self._mousePressed = False
elif event.button() == Qt.MiddleButton:
self._isPanning = False
self.setCursor(Qt.ArrowCursor)
self._mousePressed = False
super(MyGraphicsView, self).mouseReleaseEvent(event)
def mouseDoubleClickEvent(self, event):
self.fitInView(self.sceneRect(), Qt.KeepAspectRatio)
pass
def keyPressEvent(self, event):
if event.key() == Qt.Key_Space and not self._mousePressed:
self._isPanning = True
self.setCursor(Qt.OpenHandCursor)
else:
super(MyGraphicsView, self).keyPressEvent(event)
def keyReleaseEvent(self, event):
if event.key() == Qt.Key_Space:
if not self._mousePressed:
self._isPanning = False
self.setCursor(Qt.ArrowCursor)
else:
super(MyGraphicsView, self).keyPressEvent(event)
def wheelEvent(self, event):
# zoom factor
factor = 1.25
# Set Anchors
self.setTransformationAnchor(QGraphicsView.NoAnchor)
self.setResizeAnchor(QGraphicsView.NoAnchor)
# Save the scene pos
oldPos = self.mapToScene(event.pos())
# Zoom
if event.delta() < 0:
factor = 1.0 / factor
self.scale(factor, factor)
# Get the new position
newPos = self.mapToScene(event.pos())
# Move scene to old position
delta = newPos - oldPos
self.translate(delta.x(), delta.y())
class MyGraphicsScene(QGraphicsScene):
def __init__(self, parent):
super(MyGraphicsScene, self).__init__(parent)
self.setBackgroundBrush(QBrush(QColor(50, 50, 50)))
# self.setSceneRect(50,50,0,0)
class MyMainWindow(QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
self.setWindowTitle("Test")
self.resize(800, 600)
self.gv = MyGraphicsView()
self.setCentralWidget(self.gv)
self.populate()
def populate(self):
scene = self.gv.scene()
for i in range(500):
x = random.randint(0, 1000)
y = random.randint(0, 1000)
r = random.randint(2, 8)
rect = GraphicsEllipseItem(x, y, r, r)
rect.setPen(
QPen(QColor(255, 128, 0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
)
rect.setBrush(QBrush(QColor(255, 128, 20, 128)))
scene.addItem(rect)
rect.setFlag(QGraphicsItem.ItemIsSelectable)
rect.setFlag(QGraphicsItem.ItemIsMovable)
rect = GraphicsEllipseItem(300, 500, 20, 20)
rect.setPen(
QPen(QColor(255, 128, 0), 0.5, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
)
rect.setBrush(QBrush(QColor(255, 0, 0, 128)))
scene.addItem(rect)
rect.setFlag(QGraphicsItem.ItemIsSelectable)
rect.setFlag(QGraphicsItem.ItemIsMovable)
def main():
app = QApplication(sys.argv)
ex = MyMainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Explanation of option.state &= ~QStyle.State_Selected
:
state is an attribute of QStyleOptionGraphicsItem that stores the information of the state of the painting that may contain a combination of the following flags:
In this case the flags can be combined with using the "|" operator, and deactivate using the "&~".
To understand it better, let's use the following example: we set the state in State_Active and State_Editing as initial state:
state = State_Active | State_Editing
= 0x00010000 | 0x00400000
= 0x00410000
And to deactivate the State_Active flag:
state & ~State_Active
0x00410000 & ~(0x00010000)
0x00410000 & 0xFFFEFFFF
0x00400000
As you can see, flag State_Active is removed without removing other flags only with binary operations.
So how do you want to deactivate the State_Selected flag and replace it to the state then it must be done:
option.state = option.state & ~QStyle.State_Selected
option.state &= ~QStyle.State_Selected
Upvotes: 3