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...
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
Related
I have KeyEvent(self, event) function and transfer event.key() to function in module MoveKeyboard but only catch KeyReleaseEvent. I need to handle the release and continuous holding of the button and execute appropriate action . I tested KeyEvent(self, event) and in console output is only: 1: Release.
Joy, rviz, ..., move_keyboard have PyQt5.QtWidgets.QWidget class.
Main window code:
class MainWindow(PyQt5.QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__(None)
self.title = 'Robot teleoperation'
self.left = 10
self.top = 10
self.width = 1920
self.height = 1080
rospy.init_node("gui_node")
#self.joy = Joystick(maxDistance=50,MinimumSize=100,EclipseX=-20,EclipseY=40)
#self.rviz = Rviz()
#self.arm_position = BaseArmPosition()
#self.laser_position = LaserPosition()
#self.move_slider = MoveSlider()
#self.arm_slider = ArmSlider()
self.move_keyboard = MoveKeyboard()
self.initUI()
def initUI(self):
self.central_widget = PyQt5.QtWidgets.QWidget()
self.setCentralWidget(self.central_widget)
grid = PyQt5.QtWidgets.QGridLayout(self.centralWidget())
#grid.addWidget(self.rviz, 0, 0)
#grid.addWidget(self.joy, 0, 1)
#grid.addWidget(self.arm_slider,0,2)
#grid.addWidget(self.arm_position, 1, 0)
#grid.addWidget(self.move_slider, 1,1)
grid.addWidget(self.move_keyboard,0,0)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.show()
def keyPressEvent(self, event):
print("1: Press")
self.move_keyboard.PressEvent(event)
if event.key() == PyQt5.QtCore.Qt.Key_Control:
print("2: Press")
self.move_keyboard.PressEvent(event)
return super(MainWindow, self).keyPressEvent(event)
def keyReleaseEvent(self, event):
print("1: Release")
self.move_keyboard.ReleaseEvent(event)
if event.key() == PyQt5.QtCore.Qt.Key_Control:
print("2: Release")
self.move_keyboard.ReleaseEvent(event)
return super(MainWindow, self).keyReleaseEvent(event)
Class MoveKeyoard:
import PyQt5
import rospy
from geometry_msgs.msg import Twist
class MoveKeyboard(PyQt5.QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super(MoveKeyboard, self).__init__(*args, **kwargs)
self.Up = PyQt5.QtWidgets.QLabel("Up(W)")
self.Left = PyQt5.QtWidgets.QLabel("Left(A)")
self.Right = PyQt5.QtWidgets.QLabel("Right(D)")
self.Down = PyQt5.QtWidgets.QLabel("Down(S)")
self.LinearValue = PyQt5.QtWidgets.QDoubleSpinBox(self)
self.AngularValue = PyQt5.QtWidgets.QDoubleSpinBox(self)
self.label_linear = PyQt5.QtWidgets.QLabel("Linear speed")
self.label_angular = PyQt5.QtWidgets.QLabel("Angular speed")
self.initUI()
def initUI(self):
self.LinearValue.setMaximum(1.00)
self.LinearValue.setMinimum(0.00)
self.LinearValue.setSingleStep(0.01)
self.AngularValue.setMaximum(1.00)
self.AngularValue.setMinimum(0.00)
self.AngularValue.setSingleStep(0.01)
layout = PyQt5.QtWidgets.QGridLayout(self)
layout.addWidget(self.label_linear,0,0)
layout.addWidget(self.LinearValue,0,1)
layout.addWidget(self.label_angular,1,0)
layout.addWidget(self.AngularValue,1,1)
layout.addWidget(self.Up,2,1)
layout.addWidget(self.Left,3,0)
layout.addWidget(self.Down,3,1)
layout.addWidget(self.Right,3,2)
self.pub = rospy.Publisher('cmd_vel', Twist, queue_size = 1)
def PressEvent(self, e):
if e.key() == PyQt5.QtCore.Qt.Key_W:
self.Up.setStyleSheet('color: red')
self.do("W")
if e.key() == PyQt5.QtCore.Qt.Key_S:
self.Down.setStyleSheet('color: red')
self.do("S")
if e.key() == PyQt5.QtCore.Qt.Key_A:
self.Left.setStyleSheet('color: red')
self.do("A")
if e.key() == PyQt5.QtCore.Qt.Key_D:
self.Right.setStyleSheet('color: red')
self.do("D")
def ReleaseEvent(self, e):
if e.key() == PyQt5.QtCore.Qt.Key_W:
self.Up.setStyleSheet('color: black')
self.do("---W")
if e.key() == PyQt5.QtCore.Qt.Key_S:
self.Down.setStyleSheet('color: black')
self.do("---S")
if e.key() == PyQt5.QtCore.Qt.Key_A:
self.Left.setStyleSheet('color: black')
self.do("---A")
if e.key() == PyQt5.QtCore.Qt.Key_D:
self.Right.setStyleSheet('color: black')
self.do("---D")
def do(self,str_):
print(str_)
If a widget consumes the QKeyEvent event (event.accept()) then that event will not be propagated, in this case QDoubleSpinBox consumes the events they use as a Qt.ControlModifier modifier so that other widgets will not receive the press, only the release.
So the solution in this case is to prevent the QDoubleSpinBox from consuming the combination Ctrl+W, Ctrl+S, Ctrl+A and Ctrl+D.
On the other hand I do not need the window to handle these events, I think it is better for the widget itself to handle them.
from PyQt5 import QtCore, QtWidgets
class DoubleSpinBox(QtWidgets.QDoubleSpinBox):
def keyPressEvent(self, event):
if event.modifiers() == QtCore.Qt.ControlModifier and event.key() in (
QtCore.Qt.Key_W,
QtCore.Qt.Key_S,
QtCore.Qt.Key_A,
QtCore.Qt.Key_D,
):
event.ignore()
else:
super(DoubleSpinBox, self).keyPressEvent(event)
class MoveKeyboard(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MoveKeyboard, self).__init__(parent)
self.Up = QtWidgets.QLabel("Up(W)")
self.Left = QtWidgets.QLabel("Left(A)")
self.Right = QtWidgets.QLabel("Right(D)")
self.Down = QtWidgets.QLabel("Down(S)")
self.LinearValue = DoubleSpinBox()
self.AngularValue = DoubleSpinBox()
self.label_linear = QtWidgets.QLabel("Linear speed")
self.label_angular = QtWidgets.QLabel("Angular speed")
self.initUI()
def initUI(self):
self.LinearValue.setMaximum(1.00)
self.LinearValue.setMinimum(0.00)
self.LinearValue.setSingleStep(0.01)
self.AngularValue.setMaximum(1.00)
self.AngularValue.setMinimum(0.00)
self.AngularValue.setSingleStep(0.01)
layout = QtWidgets.QGridLayout(self)
layout.addWidget(self.label_linear, 0, 0)
layout.addWidget(self.LinearValue, 0, 1)
layout.addWidget(self.label_angular, 1, 0)
layout.addWidget(self.AngularValue, 1, 1)
layout.addWidget(self.Up, 2, 1)
layout.addWidget(self.Left, 3, 0)
layout.addWidget(self.Down, 3, 1)
layout.addWidget(self.Right, 3, 2)
def get_widget_by_key(self, key):
d = {
QtCore.Qt.Key_W: ("W", self.Up),
QtCore.Qt.Key_S: ("S", self.Down),
QtCore.Qt.Key_A: ("A", self.Left),
QtCore.Qt.Key_D: ("D", self.Right),
}
return d.get(key, ("", None))
def keyPressEvent(self, event):
if event.modifiers() == QtCore.Qt.ControlModifier and not event.isAutoRepeat():
letter, widget = self.get_widget_by_key(event.key())
if widget is not None:
widget.setStyleSheet("color: red")
print(letter)
super(MoveKeyboard, self).keyPressEvent(event)
def keyReleaseEvent(self, event):
if event.modifiers() == QtCore.Qt.ControlModifier and not event.isAutoRepeat():
letter, widget = self.get_widget_by_key(event.key())
if widget is not None:
widget.setStyleSheet("color: black")
print("--{}".format(letter))
super(MoveKeyboard, self).keyReleaseEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__(None)
self.title = "Robot teleoperation"
self.move_keyboard = MoveKeyboard()
self.initUI()
def initUI(self):
self.central_widget = QtWidgets.QWidget()
self.setCentralWidget(self.central_widget)
grid = QtWidgets.QGridLayout(self.centralWidget())
grid.addWidget(self.move_keyboard, 0, 0)
self.setWindowTitle(self.title)
self.setGeometry(10, 10, 1920, 1080)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I want to make cropping image tool by using python and pyqt5
Below code, I can't use the mouseMoveEvent and mouseReleaseEvent on
the graphic view.
But, I only can use the mousePressEvent on the graphicview. I checked the interactive about QGraphicView properties.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PIL import Image
from PyQt5 import uic
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
IS_RESULT = False
CROP_UI = uic.loadUiType("Image_crop_screen.ui")[0]
BRING_IN_IMG_ROUTE = "C:/Users/yoon/Desktop/test/test.jpg"
class MainScreen(QMainWindow, CROP_UI):
def __init__(self):
super().__init__()
self.setupUi(self)
# Graphic Screen set
self.img = QGraphicsPixmapItem(QPixmap(BRING_IN_IMG_ROUTE))
self.scene = QGraphicsScene()
self.scene.addItem(self.img)
self.graphicsView.setScene(self.scene)
self.graphicsView.pencolor = QColor(240, 240, 240)
self.graphicsView.brushcolor = QColor(255, 255, 255, 0)
QGV = QGraphicsView()
self.items = []
# Full Screen set size
_WIDTH_ADD = 25
_HEIGHT_ADD = 25
self.setGeometry(0, 0, 640 + _WIDTH_ADD, 500 + _HEIGHT_ADD)
def moveEvent(self, e):
rect = QRectF(self.rect())
rect.adjust(0, 0, 0, 0) # 창 스크롤 바 없애기 위해서 일부 크기 작게 설정
self.scene.setSceneRect(rect)
# Draw rectangular while moving mouse
def mouseMoveEvent(self, e):
# e.buttons()는 정수형 값을 리턴, e.button()은 move시 Qt.Nobutton 리턴
print(Qt.LeftButton)
print(e.buttons())
print(e)
if e.buttons() & Qt.LeftButton:
self.end = e.pos()
pen = QPen(self.parent().pencolor)
brush = QBrush(self.parent().brushcolor)
pen.setWidth(3)
# 장면에 그려진 이전 선을 제거
if len(self.items) > 0:
self.scene.removeItem(self.items[-1])
del (self.items[-1])
rect = QRectF(self.start, self.end)
self.items.append(self.scene.addRect(rect, pen, brush))
def mousePressEvent(self, e):
if e.button() == Qt.LeftButton:
# 시작점 저장
self.start = e.pos()
self.end = e.pos()
print(Qt.LeftButton)
print(e.buttons())
print(e)
def mouseReleaseEvent(self, e):
print("aaa2")
if e.button() == Qt.LeftButton:
global IS_RESULT
print("ttt2")
pen = QPen(self.parent().pencolor)
brush = QBrush(self.parent().brushcolor)
self.items.clear()
rect = QRectF(self.start, self.end)
self.scene.addRect(rect, pen, brush)
print("(" + str(self.start.x()) + ", " + str(self.start.y()) + "), (" + str(self.end.x()) + ", " + str(
self.end.y()) + ")")
area = (self.start.x(), self.start.y(), self.end.x(), self.end.y())
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainScreen()
w.show()
sys.exit(app.exec_())
If you want to listen to the events of the QGraphicsView you should not override the events of another widget since some events will not be transmitted. In this case it is better to use an event filter that tracks the mouse, in this case the events of the viewport() of the QGraphicsView should be monitored.
In the following example I show how to create rectangles with the mouse.
class MainScreen(QMainWindow, CROP_UI):
def __init__(self):
super().__init__()
self.setupUi(self)
# Graphic Screen set
self.img = QGraphicsPixmapItem(QPixmap(BRING_IN_IMG_ROUTE))
self.scene = QGraphicsScene()
self.scene.addItem(self.img)
self.graphicsView.setScene(self.scene)
# Full Screen set size
_WIDTH_ADD = 25
_HEIGHT_ADD = 25
self.setGeometry(0, 0, 640 + _WIDTH_ADD, 500 + _HEIGHT_ADD)
self.graphicsView.viewport().installEventFilter(self)
self.current_item = None
self.start_pos = QPointF()
self.end_pos = QPointF()
def eventFilter(self, o, e):
if self.graphicsView.viewport() is o:
if e.type() == QEvent.MouseButtonPress:
if e.buttons() & Qt.LeftButton:
print("press")
self.start_pos = self.end_pos = self.graphicsView.mapToScene(
e.pos()
)
pen = QPen(QColor(240, 240, 240))
pen.setWidth(3)
brush = QBrush(QColor(100, 255, 100, 100))
self.current_item = self.scene.addRect(QRectF(), pen, brush)
self._update_item()
elif e.type() == QEvent.MouseMove:
if e.buttons() & Qt.LeftButton and self.current_item is not None:
print("move")
self.end_pos = self.graphicsView.mapToScene(e.pos())
self._update_item()
elif e.type() == QEvent.MouseButtonRelease:
print("release")
self.end_pos = self.graphicsView.mapToScene(e.pos())
self._update_item()
self.current_item = None
return super().eventFilter(o, e)
def _update_item(self):
if self.current_item is not None:
self.current_item.setRect(QRectF(self.start_pos, self.end_pos).normalized())
You have to create a class with type QGraphicView in which you will use the mouse events
class MyGraphicView(QGraphicsView):
def __init__():
super.__init__(self)
self.myScene = QGraphicsScene()
self.setScene(self.myScene)
# the rest code
def mousePressEvent(self, event):
...
def mouseMoveEvent(self, event):
...
def mouseReleaseEvent(self, event):
...
I have some x and y coordinates that are being associated with some QGraphicItems, and then put into a QGraphicView. I recently noticed that while selecting the items with the rubberBand function that my dots were not orientated correctly.
I have 4 dots that overlap, and they are overlapping in the wrong spots, I did some debugging and found out my origin is starting in the upper left corner and Y+ is going down and my X+ is going toward the right.
I would like my system so that the Y+ will be getting larger as it goes up. I have taken a screenshot to show what the results of the code is currently ( I will paste below) and I put numbers next to the dots. Those numbers are representing how many dots are in that location. Also, I have put the X and Y directions.
Then Moved the numbers that are next to the dot around to represent what I am trying to achieve. Along with the X and Y orientation that I am Looking for.
I also noticed that it seems to be normalizing the coordinates. If I can retain the actually X and Y positions that would be for the best.
Here is the photo of what I currently Have
Here is what I want
Here is my current code
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
from math import sqrt
class LogObject(QObject):
hovered = pyqtSignal()
notHovered = pyqtSignal()
class Point(QGraphicsRectItem):
def __init__(self, x, y, name):
super(Point, self).__init__(QRectF(0, 0, 30, 30))
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.name = name
self.x = x
self.y = y
self.setBrush(QBrush(Qt.black))
self.setAcceptHoverEvents(True)
self.log = LogObject()
self.setPos(x, y)
def itemChange(self, change, value):
if change == self.ItemSelectedChange:
self.setBrush(QBrush(Qt.green) if value else QBrush(Qt.black))
return QGraphicsItem.itemChange(self, change, value)
def hoverEnterEvent(self, event):
self.setBrush(QColor("red"))
self.log.hovered.emit()
QGraphicsItem.hoverMoveEvent(self, event)
def hoverLeaveEvent(self, event):
self.setBrush(QColor("black"))
self.log.notHovered.emit()
QGraphicsItem.hoverMoveEvent(self, event)
def mousePressEvent(self, event):
print(self.name)
QGraphicsItem.mousePressEvent(self, event)
class Viewer(QGraphicsView):
photoClicked = pyqtSignal(QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(Viewer, self).__init__(parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
self._zoom = 0
self._empty = True
self._scene = QGraphicsScene(self)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.area = float()
self.setPoints()
QTimer.singleShot(0, self.fitInView) # This is done so that it can fit into view on load
self.viewport().setCursor(Qt.ArrowCursor)
def setItems(self):
self.data = {'x': [-2414943.8686, -2417160.6592, -2417160.6592, -2417856.1783, -2417054.7618, -2416009.9966, -2416012.5232, -2418160.8952, -2418160.8952, -2416012.5232, -2417094.7694, -2417094.7694], 'y': [10454269.7008,
10454147.2672, 10454147.2672, 10453285.2456, 10452556.8132, 10453240.2808, 10455255.8752, 10455183.1912, 10455183.1912, 10455255.8752, 10456212.5959, 10456212.5959]}
maxX = max(self.data['x'])
minX = min(self.data['x'])
maxY = max(self.data['y'])
minY = min(self.data['y'])
distance = sqrt((maxX-minX)**2+(maxY-minY)**2)
self.area = QRectF(minX, minY, distance, distance)
self._scene.setSceneRect(QRectF(minX, -minY, distance, distance)) # Tried this but didn't seem to do anything
for i, (x, y) in enumerate(zip(self.data["x"], self.data["y"])):
p = Point(x, y, "Point__" + str(i))
p.log.hovered.connect(self.hoverChange)
p.log.notHovered.connect(self.notHoverChange)
self._scene.addItem(p)
self.setScene(self._scene)
def fitInView(self, scale=True):
rect = QRectF(self.area)
if not rect.isNull():
self.setSceneRect(rect)
unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def setPoints(self):
self._zoom = 0
self.setItems()
self.setDragMode(self.ScrollHandDrag)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.fitInView()
else:
self._zoom = 0
def hoverChange(self):
self.viewport().setCursor(Qt.PointingHandCursor)
def notHoverChange(self):
self.viewport().setCursor(Qt.ArrowCursor)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
return
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ClosedHandCursor)
self.original_event = event
handmade_event = QMouseEvent(QEvent.MouseButtonPress,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mousePressEvent(self,handmade_event)
super(Viewer, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
point= event.pos()
print(point)
if event.button() == Qt.LeftButton:
self.changeRubberBand = False
if self.rubberBand.isVisible():
self.rubberBand.hide()
rect = self.rubberBand.geometry()
rect_scene = self.mapToScene(rect).boundingRect()
selected = self.scene().items(rect_scene)
if selected:
print(
"".join("Item: %s\n" % child.name for child in selected)
)
else:
print(" Nothing\n")
QGraphicsView.mouseReleaseEvent(self, event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ArrowCursor)
handmade_event = QMouseEvent(QEvent.MouseButtonRelease,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mouseReleaseEvent(self,handmade_event)
super(Viewer, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self,event)
super(Viewer, self).mouseMoveEvent(event)
def hoverMoveEvent(self,event):
point=event.pos().toPoint()
print(point)
QGraphicsView.hoverMoveEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = Viewer(self)
self.btnLoad = QToolButton(self)
self.btnLoad.setText('Fit Into View')
self.btnLoad.clicked.connect(self.fitPoints)
VBlayout = QVBoxLayout(self)
VBlayout.addWidget(self.viewer)
HBlayout = QHBoxLayout()
HBlayout.setAlignment(Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
VBlayout.addLayout(HBlayout)
self.viewer.fitInView()
def fitPoints(self):
self.viewer.fitInView()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
The idea is to scale the scene with (1, -1) that will make the Y axis invert. On the other hand QGraphicsView already has a fitInView method so I will use it since your current method can generate problems
class LogObject(QObject):
hovered = pyqtSignal()
notHovered = pyqtSignal()
class Point(QGraphicsRectItem):
def __init__(self, x, y, name):
super(Point, self).__init__(QRectF(0, 0, 30, 30))
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.name = name
self.setBrush(QBrush(Qt.black))
self.setAcceptHoverEvents(True)
self.log = LogObject()
self.setPos(x, y)
def itemChange(self, change, value):
if change == self.ItemSelectedChange:
self.setBrush(QBrush(Qt.green) if value else QBrush(Qt.black))
return QGraphicsItem.itemChange(self, change, value)
def hoverEnterEvent(self, event):
self.setBrush(QColor("red"))
self.log.hovered.emit()
QGraphicsItem.hoverMoveEvent(self, event)
def hoverLeaveEvent(self, event):
self.setBrush(QColor("black"))
self.log.notHovered.emit()
QGraphicsItem.hoverMoveEvent(self, event)
def mousePressEvent(self, event):
print(self.name)
QGraphicsItem.mousePressEvent(self, event)
class Viewer(QGraphicsView):
photoClicked = pyqtSignal(QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(Viewer, self).__init__(parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
self._zoom = 0
self._empty = True
self.setScene(QGraphicsScene(self))
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.area = float()
self.setPoints()
self.viewport().setCursor(Qt.ArrowCursor)
QTimer.singleShot(0, self.reset_fit)
def setItems(self):
self.data = {
"x": [
-2414943.8686,
-2417160.6592,
-2417160.6592,
-2417856.1783,
-2417054.7618,
-2416009.9966,
-2416012.5232,
-2418160.8952,
-2418160.8952,
-2416012.5232,
-2417094.7694,
-2417094.7694,
],
"y": [
10454269.7008,
10454147.2672,
10454147.2672,
10453285.2456,
10452556.8132,
10453240.2808,
10455255.8752,
10455183.1912,
10455183.1912,
10455255.8752,
10456212.5959,
10456212.5959,
],
}
maxX = max(self.data["x"])
minX = min(self.data["x"])
maxY = max(self.data["y"])
minY = min(self.data["y"])
distance = sqrt((maxX - minX) ** 2 + (maxY - minY) ** 2)
self.area = QRectF(minX, minY, distance, distance)
self.scene().setSceneRect(
QRectF(minX, -minY, distance, distance)
) # Tried this but didn't seem to do anything
for i, (x, y) in enumerate(zip(self.data["x"], self.data["y"])):
p = Point(x, y, "Point__" + str(i))
p.log.hovered.connect(self.hoverChange)
p.log.notHovered.connect(self.notHoverChange)
self.scene().addItem(p)
def setPoints(self):
self.setItems()
self.setDragMode(self.ScrollHandDrag)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.reset_fit()
else:
self._zoom = 0
def hoverChange(self):
self.viewport().setCursor(Qt.PointingHandCursor)
def notHoverChange(self):
self.viewport().setCursor(Qt.ArrowCursor)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
return
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ClosedHandCursor)
self.original_event = event
handmade_event = QMouseEvent(
QEvent.MouseButtonPress,
QPointF(event.pos()),
Qt.LeftButton,
event.buttons(),
Qt.KeyboardModifiers(),
)
QGraphicsView.mousePressEvent(self, handmade_event)
super(Viewer, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
point = event.pos()
print(self.mapToScene(point))
if event.button() == Qt.LeftButton:
self.changeRubberBand = False
if self.rubberBand.isVisible():
self.rubberBand.hide()
rect = self.rubberBand.geometry()
rect_scene = self.mapToScene(rect).boundingRect()
selected = self.scene().items(rect_scene)
if selected:
print(
"".join("Item: %s\n" % child.name for child in selected)
)
else:
print(" Nothing\n")
QGraphicsView.mouseReleaseEvent(self, event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ArrowCursor)
handmade_event = QMouseEvent(
QEvent.MouseButtonRelease,
QPointF(event.pos()),
Qt.LeftButton,
event.buttons(),
Qt.KeyboardModifiers(),
)
QGraphicsView.mouseReleaseEvent(self, handmade_event)
super(Viewer, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(
QRect(self.origin, event.pos()).normalized()
)
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self, event)
super(Viewer, self).mouseMoveEvent(event)
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
print(point)
QGraphicsView.hoverMoveEvent(event)
def reset_fit(self):
r = self.scene().itemsBoundingRect()
self.resetTransform()
self.setSceneRect(r)
self.fitInView(r, Qt.KeepAspectRatio)
self._zoom = 0
self.scale(1, -1)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = Viewer(self)
self.btnLoad = QToolButton(self)
self.btnLoad.setText("Fit Into View")
self.btnLoad.clicked.connect(self.fitPoints)
VBlayout = QVBoxLayout(self)
VBlayout.addWidget(self.viewer)
HBlayout = QHBoxLayout()
HBlayout.setAlignment(Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
VBlayout.addLayout(HBlayout)
def fitPoints(self):
self.viewer.reset_fit()
I have two issues here.
When i paint the ellipse it appears the edges of the ellipse are not being painted white during the hover event. How can i fix this both when the dot is it's regular size and when it's being hovered over?
When the user hovers over the dot I want the dot's radius to increase by 2, however when i do that, it currently does not scale from the center of the dot. How can i adjust so it increases it's size based on the center point of the dot?
import sys
from PySide.QtGui import *
from PySide.QtCore import *
import random
class MyGraphicsView(QGraphicsView):
def __init__(self):
super(MyGraphicsView, self).__init__()
self.setDragMode(QGraphicsView.RubberBandDrag)
self._isPanning = False
self._mousePressed = False
# self.setBackgroundBrush(QImage("C:/Users/jmartini/Desktop/Temp/images/flag_0140.jpg"))
self.setCacheMode(QGraphicsView.CacheBackground)
self.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff )
self.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff )
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__()
self.setBackgroundBrush(QBrush(QColor(50,50,50)))
class EllipseItem(QGraphicsEllipseItem):
def __init__(self):
super(EllipseItem, self).__init__()
self.setAcceptHoverEvents(True)
self.hover = False
def paint(self, painter, option, widget):
painter.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing, True )
painter.setBrush(QBrush(QColor(170,170,170,255)))
if self.isSelected():
painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
else:
painter.setPen(QPen(QColor(30,30,30), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
self.setRect(-16, -16, 16, 16)
if self.hover:
painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
self.setRect(-18, -18, 18, 18)
painter.drawEllipse(self.rect())
def hoverEnterEvent(self, event):
self.hover = True
self.update()
super(self.__class__, self).hoverEnterEvent(event)
def hoverLeaveEvent(self, event):
self.hover = False
self.update()
super(self.__class__, self).hoverEnterEvent(event)
class MyMainWindow(QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
self.setWindowTitle("Test")
self.resize(800,600)
self.gv = MyGraphicsView()
self.gv.setScene(MyGraphicsScene(self))
lay_main = QVBoxLayout()
lay_main.addWidget(self.gv)
widget_main = QWidget()
widget_main.setLayout(lay_main)
self.setCentralWidget(widget_main)
self.populate()
def populate(self):
scene = self.gv.scene()
item = EllipseItem()
item.setFlag( QGraphicsItem.ItemIsSelectable )
scene.addItem(item)
def main():
app = QApplication(sys.argv)
ex = MyMainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I'm not quite sure of what you exactly want (maybe it's my english). From running your code I see that on hover the edges get cut from the boxes and that the two circles are not centered on the same point.
Well, the centering problem is due to the use of the setRect method on the paint overload of your EllipseItem class. For the hovering case (I'm disregarding the selected item logic of your code), you are setting rectangles that actually have different centers. For solving this issue you could use QPainter.drawEllipse(center, rx, ry), docs.
The edges issue could be fixed noting that painted edges are not considered on the rectangle setted by setRect as posted here. To be honest I'm not quite sure why the smaller ellipse fits the rectangle and the larger one doesnt.
Anyway, you can try doing something like this:
def paint(self, painter, option, widget):
painter.setRenderHints( QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing, True )
painter.setBrush(QBrush(QColor(170,170,170,255)))
# if self.isSelected():
# painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
# else:
# painter.setPen(QPen(QColor(30,30,30), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
#self.setRect(-16, -16, 16, 16)
center = QPointF(0,0)
if self.hover:
painter.setPen(QPen(QColor(255,255,255), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
# self.setRect(-10,-10, 20, 20) # this one wont fit the ellipse
self.setRect(-11, -11, 22, 22)
# plus 2
painter.drawEllipse(center, 10, 10)
else:
painter.setPen(QPen(QColor(30,30,30), 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
self.setRect(-8, -8, 16, 16) # but this one does
painter.drawEllipse(center, 8, 8)
Clearly you can center your ellipses in multiple ways, the code above is just one way of doing it.
Hope it helps.
I need help with the implementation of the brush on PyQt5
I already have some event code for the mouse:
def mousePressEvent(self, event):
if event.button() and event.button() == Qt.LeftButton:
self.lastPoint = event.pos()
self.scribbling = True
def mouseMoveEvent(self, event):
if (event.buttons() & Qt.LeftButton) and self.scribbling:
self.drawLineTo(event.pos())
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton and self.scribbling:
self.drawLineTo(event.pos())
self.scribbling = False
Inside of which the brush drawing function is declared:
def drawLineTo(self, endPoint):
painter = QPainter(self.image)
painter.setPen(QPen(self.myPenColor, self.myPenWidth, Qt.SolidLine,
Qt.RoundCap, Qt.RoundJoin))
painter.drawLine(self.lastPoint, endPoint)
self.modified = True
rad = self.myPenWidth / 2 + 2
self.update(QRect(self.lastPoint, endPoint).normalized().adjusted(-rad, -rad, +rad, +rad))
self.lastPoint = QPoint(endPoint)
But the main problem is that this function is declared in the events themselves. Therefore, drawing goes immediately, and I can not add other tools. Because together with them the "pencil" will constantly be drawn. But I need to somehow pull out the function from there and assign it to the corresponding button. To include only by clicking on this button.
Let's say I have some toolbar:
toolbar = self.addToolBar('Инструменты')
toolbar.addAction(self.pen)
For which there is an action:
self.pen = QAction(QIcon('Image/pen.png'), 'Pencil', self)
self.pen.triggered.connect(self. )
How would I do so in the "triggered.connect" assign the drawing function, and that it works only when the button is clicked.
Maybe there are some bonds for this, like in tkinter, in the similarity:
def draw_pen(self):
self.parent.config(cursor="arrow")
self.parent.unbind("<Button-1>")
self.parent.unbind("<Motion>")
self.parent.bind("<ButtonPress-1>", self.button_press)
self.parent.bind('<B1-Motion>', self.draw_pencil_move)
self.parent.bind('<ButtonRelease-1>', self.draw_pencil_release)
And, in the end, I just assigned this function to the button, and everything worked fine
I will be very grateful for answers and especially for examples of solving problems or examples of brushes that are not declared in the events
P.S. I apologize for my English, if something is wrong с:
Try it:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class MyScribbling(QMainWindow):
def __init__(self):
super().__init__()
self.penOn = QAction(QIcon('Image/ok.png'), 'Включить рисование', self)
self.penOn.triggered.connect(self.drawingOn)
self.penOff = QAction(QIcon('Image/exit.png'), 'ВЫКЛЮЧИТЬ рисование', self)
self.penOff.triggered.connect(self.drawingOff)
toolbar = self.addToolBar('Инструменты')
toolbar.addAction(self.penOn)
toolbar.addAction(self.penOff)
self.scribbling = False
self.myPenColor = Qt.red # +
self.myPenWidth = 3 # +
self.lastPoint = QPoint()
self.image = QPixmap("Image/picture.png")
self.setFixedSize(600, 600)
self.resize(self.image.width(), self.image.height())
self.show()
# +++
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPixmap(self.rect(), self.image)
def mousePressEvent(self, event):
# if event.button() and event.button() == Qt.LeftButton: # -
if (event.button() == Qt.LeftButton) and self.scribbling: # +
self.lastPoint = event.pos()
# self.scribbling = True # -
def mouseMoveEvent(self, event):
if (event.buttons() & Qt.LeftButton) and self.scribbling:
# self.drawLineTo(event.pos()) # -
# +++
painter = QPainter(self.image)
painter.setPen(QPen(self.myPenColor, self.myPenWidth,
Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
painter.drawLine(self.lastPoint, event.pos())
# self.modified = True # ?
self.lastPoint = event.pos()
self.update()
# ?
#rad = self.myPenWidth / 2 + 2
#self.update(QRect(self.lastPoint, event.pos()).normalized().adjusted(-rad, -rad, +rad, +rad))
#self.lastPoint = QPoint(event.pos())
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton and self.scribbling:
#self.drawLineTo(event.pos())
#self.scribbling = False
pass
# Перенес в mouseMoveEvent
# def drawLineTo(self, endPoint):
# painter = QPainter(self.image)
# painter.setPen(QPen(self.myPenColor, self.myPenWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
# painter.drawLine(self.lastPoint, endPoint)
# self.modified = True
# rad = self.myPenWidth / 2 + 2
# self.update(QRect(self.lastPoint, endPoint).normalized().adjusted(-rad, -rad, +rad, +rad))
# self.lastPoint = QPoint(endPoint)
# +++
def drawingOn(self):
self.scribbling = True
# +++
def drawingOff(self):
self.scribbling = False
if __name__ == '__main__':
app = QApplication(sys.argv)
mainMenu = MyScribbling()
sys.exit(app.exec_())