QPaint with mouse Event panning











up vote
1
down vote

favorite












I have created a paint widget, that I want to implement a pan event with hand icon tool, which usually sees in many softwares. it is when user press on mouse button and hold it then move over within Qpainter canvas, the drawing follows the mouse movement. I can't find out how to do it in PyQt5.



VISUAL EXAMPLE



The current screen:



enter image description here



The desired screen event:



enter image description here



The Code:



import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Foo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setGeometry(QtCore.QRect(200, 100, 1200, 600))
self.paint = Paint()
self.sizeHint()
self.lay = QtWidgets.QVBoxLayout()
self.lay.addWidget(self.paint)
self.setLayout(self.lay)

class Paint(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Paint, self).__init__(parent)
self.setBackgroundRole(QtGui.QPalette.Base)
self.setAutoFillBackground(True)

self._width = 350
self._height = 250

def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
painter.setPen(QtCore.Qt.darkCyan)

r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
r.moveCenter(self.rect().center())
painter.drawRect(r)


if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Foo()
w.show()
sys.exit(app.exec_())


I appreciate any help and thanks in advance.



Update of code:



Visualization:



Well,that's what happens when I implement the updated code in my central code.
it is when user clicks and picks section from circular then plots within the widget, right after click and select another section from rectangular. The widget should update and erase previous drawing. But it does't do that. In my previous code the section drawing appears directly in the center of widget, now it sticks to upperleft edge of canvas.



enter image description here



A part of code:



from PyQt5 import QtCore, QtGui, QtWidgets

class Foo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setGeometry(QtCore.QRect(200, 100, 800, 800))

self.button = Button()
self.paint = Createpaintwidget()
self.button.valuesChanged.connect(self.paint.set_size_squares)
self.button.valueChanged.connect(self.paint.set_size_round)

self.lay = QtWidgets.QVBoxLayout(self)
self.lay.addWidget(self.paint)
self.lay.addWidget(self.button)

class Createpaintwidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.sizeHint()
self.setBackgroundRole(QtGui.QPalette.Base)
self.setAutoFillBackground(True)

self._size = QtCore.QSizeF()
self._path = QtGui.QPainterPath()
self._rect = QtCore.QRectF()
self._type = QtGui.QRegion.Rectangle
self._factor = 1.0

self._pos = QtCore.QPointF()
self._initial_flag = False
fnt = self.font()
fnt.setPointSize(20)
self.setFont(fnt)

def showEvent(self, event):
if not self._initial_flag:
self._pos = self.rect().center()
self._initial_flag = True

@QtCore.pyqtSlot(int,int)
def set_size_squares(self, w, h):
self._size = QtCore.QSizeF(w, h)
self._type = QtGui.QRegion.Rectangle
self.updatePath()

@QtCore.pyqtSlot(int)
def set_size_round(self, v):
self._size = QtCore.QSizeF(v, v)
self._type = QtGui.QRegion.Ellipse
self.updatePath()

def paintEvent(self, event):
pen = QtGui.QPen()
brush = QtGui.QBrush(QtCore.Qt.black)
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setPen(pen)
painter.setBrush(brush)

painter.translate(self.rect().center())
painter.scale(self._factor, self._factor)
painter.translate(-self.rect().center())

painter.translate(self._pos)
painter.drawPath(self._path)
if self._type == QtGui.QRegion.Rectangle:
painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
painter.drawRect(self._rect)
elif self._type == QtGui.QRegion.Ellipse:
painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
painter.drawEllipse(self._rect)

def mousePressEvent(self, event):
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
self._initial_pos = event.pos()
super().mousePressEvent(event)

def mouseMoveEvent(self, event):
delta = event.pos() - self._initial_pos
self._path.translate(delta)
self._rect.translate(delta)
self.update()
self._initial_pos = event.pos()
super().mouseMoveEvent(event)

def mouseReleaseEvent(self, event):
QtWidgets.QApplication.restoreOverrideCursor()
super().mouseReleaseEvent(event)

def updatePath(self):
fm = QtGui.QFontMetrics(self.font())
r = QtCore.QRectF(QtCore.QPointF(), self._size)
r.moveCenter(QtCore.QPointF())
self._rect = QtCore.QRectF(r)
self._path.moveTo(QtCore.QPointF())
p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
self._path.lineTo(p)
self._path.lineTo(p + QtCore.QPoint(-16, -16))
self._path.lineTo(p)
self._path.moveTo(p)
self._path.lineTo(p + QtCore.QPoint(-16, 16))
self._path.lineTo(p)
self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

self._path.moveTo(QtCore.QPointF())
p = QtCore.QPointF(0, -self._size.height()/2 - 75)
self._path.lineTo(p)
self._path.lineTo(p + QtCore.QPoint(16, 16))
self._path.lineTo(p)
self._path.moveTo(p)
self._path.lineTo(p + QtCore.QPoint(-16, 16))
self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

if self._type == QtGui.QRegion.Rectangle:
pl = r.bottomLeft() + QtCore.QPointF(0, 75)
pr = r.bottomRight() + QtCore.QPointF(0, 75)
self._path.moveTo(pl)
self._path.lineTo(pr)
for p in (pl, pr):
self._path.moveTo(p+ QtCore.QPoint(0, -40))
self._path.lineTo(p+ QtCore.QPoint(0, 20))
self._path.moveTo(p+ QtCore.QPoint(10, -10))
self._path.lineTo(p+ QtCore.QPoint(-10, 10))
word = "{}".format(self._size.width())
p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
self._path.addText(p , self.font(), word)

pt = r.topLeft() + QtCore.QPointF(-75, 0)
pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
self._path.moveTo(pt)
self._path.lineTo(pb)
for p in (pt, pb):
self._path.moveTo(p+ QtCore.QPoint(40, 0))
self._path.lineTo(p+ QtCore.QPoint(-20, 0))
self._path.moveTo(p+ QtCore.QPoint(10, -10))
self._path.lineTo(p+ QtCore.QPoint(-10, 10))
word = "{}".format(self._size.height())
p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
self._path.addText(p , self.font(), word)
if self._type == QtGui.QRegion.Ellipse:
pl = r.bottomLeft() + QtCore.QPointF(0, 75)
pr = r.bottomRight() + QtCore.QPointF(0, 75)
self._path.moveTo(pl)
self._path.lineTo(pr)
for p in (pl, pr):
self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
self._path.lineTo(p+ QtCore.QPoint(0, 10))
self._path.moveTo(p+ QtCore.QPoint(10, -10))
self._path.lineTo(p+ QtCore.QPoint(-10, 10))
word = "{}".format(self._size.width())
p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
self._path.addText(p , self.font(), word)
self.update()

def wheelEvent(self, event):
self._factor *= 1.01**(event.angleDelta().y()/15.0)
self.update()
super().wheelEvent(event)

class Button(QtWidgets.QWidget):
valueChanged = QtCore.pyqtSignal(int)
valuesChanged = QtCore.pyqtSignal(int,int)
def __init__(self, parent=None):
super(Button, self).__init__(parent)
roundbutton = QtWidgets.QPushButton('Round')
squarebutton = QtWidgets.QPushButton('Square')
Alay = QtWidgets.QVBoxLayout(self)
Alay.addWidget(roundbutton)
Alay.addWidget(squarebutton)
self.value = QtWidgets.QLabel()
roundbutton.clicked.connect(self.getbuttonfunc)
squarebutton.clicked.connect(self.sqaurebuttonfunc)

@QtCore.pyqtSlot()
def getbuttonfunc(self):
number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
self.tr("Input:"), 1, 1)
if ok:
self.valueChanged.emit(number)

@QtCore.pyqtSlot()
def sqaurebuttonfunc(self):
number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
self.tr("Input:"), 1, 1)
if ok:
self.valuesChanged.emit(number, number)


if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Foo()
w.show()
sys.exit(app.exec_())









share|improve this question




























    up vote
    1
    down vote

    favorite












    I have created a paint widget, that I want to implement a pan event with hand icon tool, which usually sees in many softwares. it is when user press on mouse button and hold it then move over within Qpainter canvas, the drawing follows the mouse movement. I can't find out how to do it in PyQt5.



    VISUAL EXAMPLE



    The current screen:



    enter image description here



    The desired screen event:



    enter image description here



    The Code:



    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets

    class Foo(QtWidgets.QWidget):
    def __init__(self, parent=None):
    super(Foo, self).__init__(parent)
    self.setGeometry(QtCore.QRect(200, 100, 1200, 600))
    self.paint = Paint()
    self.sizeHint()
    self.lay = QtWidgets.QVBoxLayout()
    self.lay.addWidget(self.paint)
    self.setLayout(self.lay)

    class Paint(QtWidgets.QWidget):
    def __init__(self, parent=None):
    super(Paint, self).__init__(parent)
    self.setBackgroundRole(QtGui.QPalette.Base)
    self.setAutoFillBackground(True)

    self._width = 350
    self._height = 250

    def paintEvent(self, event):
    painter = QtGui.QPainter(self)
    painter.setRenderHint(QtGui.QPainter.Antialiasing)
    painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
    painter.setPen(QtCore.Qt.darkCyan)

    r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
    r.moveCenter(self.rect().center())
    painter.drawRect(r)


    if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = Foo()
    w.show()
    sys.exit(app.exec_())


    I appreciate any help and thanks in advance.



    Update of code:



    Visualization:



    Well,that's what happens when I implement the updated code in my central code.
    it is when user clicks and picks section from circular then plots within the widget, right after click and select another section from rectangular. The widget should update and erase previous drawing. But it does't do that. In my previous code the section drawing appears directly in the center of widget, now it sticks to upperleft edge of canvas.



    enter image description here



    A part of code:



    from PyQt5 import QtCore, QtGui, QtWidgets

    class Foo(QtWidgets.QWidget):
    def __init__(self, parent=None):
    super(Foo, self).__init__(parent)
    self.setGeometry(QtCore.QRect(200, 100, 800, 800))

    self.button = Button()
    self.paint = Createpaintwidget()
    self.button.valuesChanged.connect(self.paint.set_size_squares)
    self.button.valueChanged.connect(self.paint.set_size_round)

    self.lay = QtWidgets.QVBoxLayout(self)
    self.lay.addWidget(self.paint)
    self.lay.addWidget(self.button)

    class Createpaintwidget(QtWidgets.QWidget):
    def __init__(self):
    super().__init__()
    self.sizeHint()
    self.setBackgroundRole(QtGui.QPalette.Base)
    self.setAutoFillBackground(True)

    self._size = QtCore.QSizeF()
    self._path = QtGui.QPainterPath()
    self._rect = QtCore.QRectF()
    self._type = QtGui.QRegion.Rectangle
    self._factor = 1.0

    self._pos = QtCore.QPointF()
    self._initial_flag = False
    fnt = self.font()
    fnt.setPointSize(20)
    self.setFont(fnt)

    def showEvent(self, event):
    if not self._initial_flag:
    self._pos = self.rect().center()
    self._initial_flag = True

    @QtCore.pyqtSlot(int,int)
    def set_size_squares(self, w, h):
    self._size = QtCore.QSizeF(w, h)
    self._type = QtGui.QRegion.Rectangle
    self.updatePath()

    @QtCore.pyqtSlot(int)
    def set_size_round(self, v):
    self._size = QtCore.QSizeF(v, v)
    self._type = QtGui.QRegion.Ellipse
    self.updatePath()

    def paintEvent(self, event):
    pen = QtGui.QPen()
    brush = QtGui.QBrush(QtCore.Qt.black)
    painter = QtGui.QPainter(self)
    painter.setRenderHint(QtGui.QPainter.Antialiasing)
    painter.setPen(pen)
    painter.setBrush(brush)

    painter.translate(self.rect().center())
    painter.scale(self._factor, self._factor)
    painter.translate(-self.rect().center())

    painter.translate(self._pos)
    painter.drawPath(self._path)
    if self._type == QtGui.QRegion.Rectangle:
    painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
    painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
    painter.drawRect(self._rect)
    elif self._type == QtGui.QRegion.Ellipse:
    painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
    painter.drawEllipse(self._rect)

    def mousePressEvent(self, event):
    QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
    self._initial_pos = event.pos()
    super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
    delta = event.pos() - self._initial_pos
    self._path.translate(delta)
    self._rect.translate(delta)
    self.update()
    self._initial_pos = event.pos()
    super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
    QtWidgets.QApplication.restoreOverrideCursor()
    super().mouseReleaseEvent(event)

    def updatePath(self):
    fm = QtGui.QFontMetrics(self.font())
    r = QtCore.QRectF(QtCore.QPointF(), self._size)
    r.moveCenter(QtCore.QPointF())
    self._rect = QtCore.QRectF(r)
    self._path.moveTo(QtCore.QPointF())
    p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
    self._path.lineTo(p)
    self._path.lineTo(p + QtCore.QPoint(-16, -16))
    self._path.lineTo(p)
    self._path.moveTo(p)
    self._path.lineTo(p + QtCore.QPoint(-16, 16))
    self._path.lineTo(p)
    self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

    self._path.moveTo(QtCore.QPointF())
    p = QtCore.QPointF(0, -self._size.height()/2 - 75)
    self._path.lineTo(p)
    self._path.lineTo(p + QtCore.QPoint(16, 16))
    self._path.lineTo(p)
    self._path.moveTo(p)
    self._path.lineTo(p + QtCore.QPoint(-16, 16))
    self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

    if self._type == QtGui.QRegion.Rectangle:
    pl = r.bottomLeft() + QtCore.QPointF(0, 75)
    pr = r.bottomRight() + QtCore.QPointF(0, 75)
    self._path.moveTo(pl)
    self._path.lineTo(pr)
    for p in (pl, pr):
    self._path.moveTo(p+ QtCore.QPoint(0, -40))
    self._path.lineTo(p+ QtCore.QPoint(0, 20))
    self._path.moveTo(p+ QtCore.QPoint(10, -10))
    self._path.lineTo(p+ QtCore.QPoint(-10, 10))
    word = "{}".format(self._size.width())
    p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
    self._path.addText(p , self.font(), word)

    pt = r.topLeft() + QtCore.QPointF(-75, 0)
    pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
    self._path.moveTo(pt)
    self._path.lineTo(pb)
    for p in (pt, pb):
    self._path.moveTo(p+ QtCore.QPoint(40, 0))
    self._path.lineTo(p+ QtCore.QPoint(-20, 0))
    self._path.moveTo(p+ QtCore.QPoint(10, -10))
    self._path.lineTo(p+ QtCore.QPoint(-10, 10))
    word = "{}".format(self._size.height())
    p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
    self._path.addText(p , self.font(), word)
    if self._type == QtGui.QRegion.Ellipse:
    pl = r.bottomLeft() + QtCore.QPointF(0, 75)
    pr = r.bottomRight() + QtCore.QPointF(0, 75)
    self._path.moveTo(pl)
    self._path.lineTo(pr)
    for p in (pl, pr):
    self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
    self._path.lineTo(p+ QtCore.QPoint(0, 10))
    self._path.moveTo(p+ QtCore.QPoint(10, -10))
    self._path.lineTo(p+ QtCore.QPoint(-10, 10))
    word = "{}".format(self._size.width())
    p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
    self._path.addText(p , self.font(), word)
    self.update()

    def wheelEvent(self, event):
    self._factor *= 1.01**(event.angleDelta().y()/15.0)
    self.update()
    super().wheelEvent(event)

    class Button(QtWidgets.QWidget):
    valueChanged = QtCore.pyqtSignal(int)
    valuesChanged = QtCore.pyqtSignal(int,int)
    def __init__(self, parent=None):
    super(Button, self).__init__(parent)
    roundbutton = QtWidgets.QPushButton('Round')
    squarebutton = QtWidgets.QPushButton('Square')
    Alay = QtWidgets.QVBoxLayout(self)
    Alay.addWidget(roundbutton)
    Alay.addWidget(squarebutton)
    self.value = QtWidgets.QLabel()
    roundbutton.clicked.connect(self.getbuttonfunc)
    squarebutton.clicked.connect(self.sqaurebuttonfunc)

    @QtCore.pyqtSlot()
    def getbuttonfunc(self):
    number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
    self.tr("Input:"), 1, 1)
    if ok:
    self.valueChanged.emit(number)

    @QtCore.pyqtSlot()
    def sqaurebuttonfunc(self):
    number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
    self.tr("Input:"), 1, 1)
    if ok:
    self.valuesChanged.emit(number, number)


    if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Foo()
    w.show()
    sys.exit(app.exec_())









    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I have created a paint widget, that I want to implement a pan event with hand icon tool, which usually sees in many softwares. it is when user press on mouse button and hold it then move over within Qpainter canvas, the drawing follows the mouse movement. I can't find out how to do it in PyQt5.



      VISUAL EXAMPLE



      The current screen:



      enter image description here



      The desired screen event:



      enter image description here



      The Code:



      import sys
      from PyQt5 import QtCore, QtGui, QtWidgets

      class Foo(QtWidgets.QWidget):
      def __init__(self, parent=None):
      super(Foo, self).__init__(parent)
      self.setGeometry(QtCore.QRect(200, 100, 1200, 600))
      self.paint = Paint()
      self.sizeHint()
      self.lay = QtWidgets.QVBoxLayout()
      self.lay.addWidget(self.paint)
      self.setLayout(self.lay)

      class Paint(QtWidgets.QWidget):
      def __init__(self, parent=None):
      super(Paint, self).__init__(parent)
      self.setBackgroundRole(QtGui.QPalette.Base)
      self.setAutoFillBackground(True)

      self._width = 350
      self._height = 250

      def paintEvent(self, event):
      painter = QtGui.QPainter(self)
      painter.setRenderHint(QtGui.QPainter.Antialiasing)
      painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
      painter.setPen(QtCore.Qt.darkCyan)

      r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
      r.moveCenter(self.rect().center())
      painter.drawRect(r)


      if __name__ == '__main__':
      app = QtWidgets.QApplication(sys.argv)
      w = Foo()
      w.show()
      sys.exit(app.exec_())


      I appreciate any help and thanks in advance.



      Update of code:



      Visualization:



      Well,that's what happens when I implement the updated code in my central code.
      it is when user clicks and picks section from circular then plots within the widget, right after click and select another section from rectangular. The widget should update and erase previous drawing. But it does't do that. In my previous code the section drawing appears directly in the center of widget, now it sticks to upperleft edge of canvas.



      enter image description here



      A part of code:



      from PyQt5 import QtCore, QtGui, QtWidgets

      class Foo(QtWidgets.QWidget):
      def __init__(self, parent=None):
      super(Foo, self).__init__(parent)
      self.setGeometry(QtCore.QRect(200, 100, 800, 800))

      self.button = Button()
      self.paint = Createpaintwidget()
      self.button.valuesChanged.connect(self.paint.set_size_squares)
      self.button.valueChanged.connect(self.paint.set_size_round)

      self.lay = QtWidgets.QVBoxLayout(self)
      self.lay.addWidget(self.paint)
      self.lay.addWidget(self.button)

      class Createpaintwidget(QtWidgets.QWidget):
      def __init__(self):
      super().__init__()
      self.sizeHint()
      self.setBackgroundRole(QtGui.QPalette.Base)
      self.setAutoFillBackground(True)

      self._size = QtCore.QSizeF()
      self._path = QtGui.QPainterPath()
      self._rect = QtCore.QRectF()
      self._type = QtGui.QRegion.Rectangle
      self._factor = 1.0

      self._pos = QtCore.QPointF()
      self._initial_flag = False
      fnt = self.font()
      fnt.setPointSize(20)
      self.setFont(fnt)

      def showEvent(self, event):
      if not self._initial_flag:
      self._pos = self.rect().center()
      self._initial_flag = True

      @QtCore.pyqtSlot(int,int)
      def set_size_squares(self, w, h):
      self._size = QtCore.QSizeF(w, h)
      self._type = QtGui.QRegion.Rectangle
      self.updatePath()

      @QtCore.pyqtSlot(int)
      def set_size_round(self, v):
      self._size = QtCore.QSizeF(v, v)
      self._type = QtGui.QRegion.Ellipse
      self.updatePath()

      def paintEvent(self, event):
      pen = QtGui.QPen()
      brush = QtGui.QBrush(QtCore.Qt.black)
      painter = QtGui.QPainter(self)
      painter.setRenderHint(QtGui.QPainter.Antialiasing)
      painter.setPen(pen)
      painter.setBrush(brush)

      painter.translate(self.rect().center())
      painter.scale(self._factor, self._factor)
      painter.translate(-self.rect().center())

      painter.translate(self._pos)
      painter.drawPath(self._path)
      if self._type == QtGui.QRegion.Rectangle:
      painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
      painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
      painter.drawRect(self._rect)
      elif self._type == QtGui.QRegion.Ellipse:
      painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
      painter.drawEllipse(self._rect)

      def mousePressEvent(self, event):
      QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
      self._initial_pos = event.pos()
      super().mousePressEvent(event)

      def mouseMoveEvent(self, event):
      delta = event.pos() - self._initial_pos
      self._path.translate(delta)
      self._rect.translate(delta)
      self.update()
      self._initial_pos = event.pos()
      super().mouseMoveEvent(event)

      def mouseReleaseEvent(self, event):
      QtWidgets.QApplication.restoreOverrideCursor()
      super().mouseReleaseEvent(event)

      def updatePath(self):
      fm = QtGui.QFontMetrics(self.font())
      r = QtCore.QRectF(QtCore.QPointF(), self._size)
      r.moveCenter(QtCore.QPointF())
      self._rect = QtCore.QRectF(r)
      self._path.moveTo(QtCore.QPointF())
      p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
      self._path.lineTo(p)
      self._path.lineTo(p + QtCore.QPoint(-16, -16))
      self._path.lineTo(p)
      self._path.moveTo(p)
      self._path.lineTo(p + QtCore.QPoint(-16, 16))
      self._path.lineTo(p)
      self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

      self._path.moveTo(QtCore.QPointF())
      p = QtCore.QPointF(0, -self._size.height()/2 - 75)
      self._path.lineTo(p)
      self._path.lineTo(p + QtCore.QPoint(16, 16))
      self._path.lineTo(p)
      self._path.moveTo(p)
      self._path.lineTo(p + QtCore.QPoint(-16, 16))
      self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

      if self._type == QtGui.QRegion.Rectangle:
      pl = r.bottomLeft() + QtCore.QPointF(0, 75)
      pr = r.bottomRight() + QtCore.QPointF(0, 75)
      self._path.moveTo(pl)
      self._path.lineTo(pr)
      for p in (pl, pr):
      self._path.moveTo(p+ QtCore.QPoint(0, -40))
      self._path.lineTo(p+ QtCore.QPoint(0, 20))
      self._path.moveTo(p+ QtCore.QPoint(10, -10))
      self._path.lineTo(p+ QtCore.QPoint(-10, 10))
      word = "{}".format(self._size.width())
      p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
      self._path.addText(p , self.font(), word)

      pt = r.topLeft() + QtCore.QPointF(-75, 0)
      pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
      self._path.moveTo(pt)
      self._path.lineTo(pb)
      for p in (pt, pb):
      self._path.moveTo(p+ QtCore.QPoint(40, 0))
      self._path.lineTo(p+ QtCore.QPoint(-20, 0))
      self._path.moveTo(p+ QtCore.QPoint(10, -10))
      self._path.lineTo(p+ QtCore.QPoint(-10, 10))
      word = "{}".format(self._size.height())
      p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
      self._path.addText(p , self.font(), word)
      if self._type == QtGui.QRegion.Ellipse:
      pl = r.bottomLeft() + QtCore.QPointF(0, 75)
      pr = r.bottomRight() + QtCore.QPointF(0, 75)
      self._path.moveTo(pl)
      self._path.lineTo(pr)
      for p in (pl, pr):
      self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
      self._path.lineTo(p+ QtCore.QPoint(0, 10))
      self._path.moveTo(p+ QtCore.QPoint(10, -10))
      self._path.lineTo(p+ QtCore.QPoint(-10, 10))
      word = "{}".format(self._size.width())
      p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
      self._path.addText(p , self.font(), word)
      self.update()

      def wheelEvent(self, event):
      self._factor *= 1.01**(event.angleDelta().y()/15.0)
      self.update()
      super().wheelEvent(event)

      class Button(QtWidgets.QWidget):
      valueChanged = QtCore.pyqtSignal(int)
      valuesChanged = QtCore.pyqtSignal(int,int)
      def __init__(self, parent=None):
      super(Button, self).__init__(parent)
      roundbutton = QtWidgets.QPushButton('Round')
      squarebutton = QtWidgets.QPushButton('Square')
      Alay = QtWidgets.QVBoxLayout(self)
      Alay.addWidget(roundbutton)
      Alay.addWidget(squarebutton)
      self.value = QtWidgets.QLabel()
      roundbutton.clicked.connect(self.getbuttonfunc)
      squarebutton.clicked.connect(self.sqaurebuttonfunc)

      @QtCore.pyqtSlot()
      def getbuttonfunc(self):
      number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
      self.tr("Input:"), 1, 1)
      if ok:
      self.valueChanged.emit(number)

      @QtCore.pyqtSlot()
      def sqaurebuttonfunc(self):
      number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
      self.tr("Input:"), 1, 1)
      if ok:
      self.valuesChanged.emit(number, number)


      if __name__ == '__main__':
      import sys
      app = QtWidgets.QApplication(sys.argv)
      w = Foo()
      w.show()
      sys.exit(app.exec_())









      share|improve this question















      I have created a paint widget, that I want to implement a pan event with hand icon tool, which usually sees in many softwares. it is when user press on mouse button and hold it then move over within Qpainter canvas, the drawing follows the mouse movement. I can't find out how to do it in PyQt5.



      VISUAL EXAMPLE



      The current screen:



      enter image description here



      The desired screen event:



      enter image description here



      The Code:



      import sys
      from PyQt5 import QtCore, QtGui, QtWidgets

      class Foo(QtWidgets.QWidget):
      def __init__(self, parent=None):
      super(Foo, self).__init__(parent)
      self.setGeometry(QtCore.QRect(200, 100, 1200, 600))
      self.paint = Paint()
      self.sizeHint()
      self.lay = QtWidgets.QVBoxLayout()
      self.lay.addWidget(self.paint)
      self.setLayout(self.lay)

      class Paint(QtWidgets.QWidget):
      def __init__(self, parent=None):
      super(Paint, self).__init__(parent)
      self.setBackgroundRole(QtGui.QPalette.Base)
      self.setAutoFillBackground(True)

      self._width = 350
      self._height = 250

      def paintEvent(self, event):
      painter = QtGui.QPainter(self)
      painter.setRenderHint(QtGui.QPainter.Antialiasing)
      painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
      painter.setPen(QtCore.Qt.darkCyan)

      r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
      r.moveCenter(self.rect().center())
      painter.drawRect(r)


      if __name__ == '__main__':
      app = QtWidgets.QApplication(sys.argv)
      w = Foo()
      w.show()
      sys.exit(app.exec_())


      I appreciate any help and thanks in advance.



      Update of code:



      Visualization:



      Well,that's what happens when I implement the updated code in my central code.
      it is when user clicks and picks section from circular then plots within the widget, right after click and select another section from rectangular. The widget should update and erase previous drawing. But it does't do that. In my previous code the section drawing appears directly in the center of widget, now it sticks to upperleft edge of canvas.



      enter image description here



      A part of code:



      from PyQt5 import QtCore, QtGui, QtWidgets

      class Foo(QtWidgets.QWidget):
      def __init__(self, parent=None):
      super(Foo, self).__init__(parent)
      self.setGeometry(QtCore.QRect(200, 100, 800, 800))

      self.button = Button()
      self.paint = Createpaintwidget()
      self.button.valuesChanged.connect(self.paint.set_size_squares)
      self.button.valueChanged.connect(self.paint.set_size_round)

      self.lay = QtWidgets.QVBoxLayout(self)
      self.lay.addWidget(self.paint)
      self.lay.addWidget(self.button)

      class Createpaintwidget(QtWidgets.QWidget):
      def __init__(self):
      super().__init__()
      self.sizeHint()
      self.setBackgroundRole(QtGui.QPalette.Base)
      self.setAutoFillBackground(True)

      self._size = QtCore.QSizeF()
      self._path = QtGui.QPainterPath()
      self._rect = QtCore.QRectF()
      self._type = QtGui.QRegion.Rectangle
      self._factor = 1.0

      self._pos = QtCore.QPointF()
      self._initial_flag = False
      fnt = self.font()
      fnt.setPointSize(20)
      self.setFont(fnt)

      def showEvent(self, event):
      if not self._initial_flag:
      self._pos = self.rect().center()
      self._initial_flag = True

      @QtCore.pyqtSlot(int,int)
      def set_size_squares(self, w, h):
      self._size = QtCore.QSizeF(w, h)
      self._type = QtGui.QRegion.Rectangle
      self.updatePath()

      @QtCore.pyqtSlot(int)
      def set_size_round(self, v):
      self._size = QtCore.QSizeF(v, v)
      self._type = QtGui.QRegion.Ellipse
      self.updatePath()

      def paintEvent(self, event):
      pen = QtGui.QPen()
      brush = QtGui.QBrush(QtCore.Qt.black)
      painter = QtGui.QPainter(self)
      painter.setRenderHint(QtGui.QPainter.Antialiasing)
      painter.setPen(pen)
      painter.setBrush(brush)

      painter.translate(self.rect().center())
      painter.scale(self._factor, self._factor)
      painter.translate(-self.rect().center())

      painter.translate(self._pos)
      painter.drawPath(self._path)
      if self._type == QtGui.QRegion.Rectangle:
      painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
      painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
      painter.drawRect(self._rect)
      elif self._type == QtGui.QRegion.Ellipse:
      painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
      painter.drawEllipse(self._rect)

      def mousePressEvent(self, event):
      QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
      self._initial_pos = event.pos()
      super().mousePressEvent(event)

      def mouseMoveEvent(self, event):
      delta = event.pos() - self._initial_pos
      self._path.translate(delta)
      self._rect.translate(delta)
      self.update()
      self._initial_pos = event.pos()
      super().mouseMoveEvent(event)

      def mouseReleaseEvent(self, event):
      QtWidgets.QApplication.restoreOverrideCursor()
      super().mouseReleaseEvent(event)

      def updatePath(self):
      fm = QtGui.QFontMetrics(self.font())
      r = QtCore.QRectF(QtCore.QPointF(), self._size)
      r.moveCenter(QtCore.QPointF())
      self._rect = QtCore.QRectF(r)
      self._path.moveTo(QtCore.QPointF())
      p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
      self._path.lineTo(p)
      self._path.lineTo(p + QtCore.QPoint(-16, -16))
      self._path.lineTo(p)
      self._path.moveTo(p)
      self._path.lineTo(p + QtCore.QPoint(-16, 16))
      self._path.lineTo(p)
      self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

      self._path.moveTo(QtCore.QPointF())
      p = QtCore.QPointF(0, -self._size.height()/2 - 75)
      self._path.lineTo(p)
      self._path.lineTo(p + QtCore.QPoint(16, 16))
      self._path.lineTo(p)
      self._path.moveTo(p)
      self._path.lineTo(p + QtCore.QPoint(-16, 16))
      self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

      if self._type == QtGui.QRegion.Rectangle:
      pl = r.bottomLeft() + QtCore.QPointF(0, 75)
      pr = r.bottomRight() + QtCore.QPointF(0, 75)
      self._path.moveTo(pl)
      self._path.lineTo(pr)
      for p in (pl, pr):
      self._path.moveTo(p+ QtCore.QPoint(0, -40))
      self._path.lineTo(p+ QtCore.QPoint(0, 20))
      self._path.moveTo(p+ QtCore.QPoint(10, -10))
      self._path.lineTo(p+ QtCore.QPoint(-10, 10))
      word = "{}".format(self._size.width())
      p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
      self._path.addText(p , self.font(), word)

      pt = r.topLeft() + QtCore.QPointF(-75, 0)
      pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
      self._path.moveTo(pt)
      self._path.lineTo(pb)
      for p in (pt, pb):
      self._path.moveTo(p+ QtCore.QPoint(40, 0))
      self._path.lineTo(p+ QtCore.QPoint(-20, 0))
      self._path.moveTo(p+ QtCore.QPoint(10, -10))
      self._path.lineTo(p+ QtCore.QPoint(-10, 10))
      word = "{}".format(self._size.height())
      p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
      self._path.addText(p , self.font(), word)
      if self._type == QtGui.QRegion.Ellipse:
      pl = r.bottomLeft() + QtCore.QPointF(0, 75)
      pr = r.bottomRight() + QtCore.QPointF(0, 75)
      self._path.moveTo(pl)
      self._path.lineTo(pr)
      for p in (pl, pr):
      self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
      self._path.lineTo(p+ QtCore.QPoint(0, 10))
      self._path.moveTo(p+ QtCore.QPoint(10, -10))
      self._path.lineTo(p+ QtCore.QPoint(-10, 10))
      word = "{}".format(self._size.width())
      p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
      self._path.addText(p , self.font(), word)
      self.update()

      def wheelEvent(self, event):
      self._factor *= 1.01**(event.angleDelta().y()/15.0)
      self.update()
      super().wheelEvent(event)

      class Button(QtWidgets.QWidget):
      valueChanged = QtCore.pyqtSignal(int)
      valuesChanged = QtCore.pyqtSignal(int,int)
      def __init__(self, parent=None):
      super(Button, self).__init__(parent)
      roundbutton = QtWidgets.QPushButton('Round')
      squarebutton = QtWidgets.QPushButton('Square')
      Alay = QtWidgets.QVBoxLayout(self)
      Alay.addWidget(roundbutton)
      Alay.addWidget(squarebutton)
      self.value = QtWidgets.QLabel()
      roundbutton.clicked.connect(self.getbuttonfunc)
      squarebutton.clicked.connect(self.sqaurebuttonfunc)

      @QtCore.pyqtSlot()
      def getbuttonfunc(self):
      number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
      self.tr("Input:"), 1, 1)
      if ok:
      self.valueChanged.emit(number)

      @QtCore.pyqtSlot()
      def sqaurebuttonfunc(self):
      number, ok = QtWidgets.QInputDialog.getInt(self, self.tr("Set Number"),
      self.tr("Input:"), 1, 1)
      if ok:
      self.valuesChanged.emit(number, number)


      if __name__ == '__main__':
      import sys
      app = QtWidgets.QApplication(sys.argv)
      w = Foo()
      w.show()
      sys.exit(app.exec_())






      python pyqt pyqt5 qpainter pan






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 2 days ago

























      asked Nov 21 at 18:56









      Zar Kha

      43111




      43111
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          1
          down vote



          accepted










          To make the pan you must follow the following steps:




          • Get the initial position in mousePressEvent


          • In mouseMoveEvent move the rectangle with the difference between the current position and the initial position, and update the initial position with the current position.



          The implementation is as follows:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._rect = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._rect.moveCenter(self.rect().center())
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          painter.drawRect(self._rect)

          def mousePressEvent(self, event):
          if self._rect.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          if self._rect.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          But instead of doing it Qt already offers classes that allow you to do the tasks that you point out in a simple way, in this case it is to use QGraphicsView with the QGraphicsItem:



          class GraphicsRectItem(QtWidgets.QGraphicsRectItem):
          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          super(GraphicsRectItem, self).mousePressEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(GraphicsRectItem, self).mouseReleaseEvent(event)

          class Paint(QtWidgets.QGraphicsView):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          scene = QtWidgets.QGraphicsScene(self)
          self.setScene(scene)
          rect_item = GraphicsRectItem(0, 0, 350, 250)
          rect_item.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          rect_item.setPen(QtCore.Qt.darkCyan)
          rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
          self.scene().addItem(rect_item)


          UPDATE:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()
          self._pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._pos = self.rect().center()
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          painter.drawRect(r)

          def mousePressEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._pos += delta
          self._initial_pos = event.pos()
          self.update()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          Update:



          One way to implement the task is to have an element or set connected element, in this case it is a QPainterPath plus a QRectF, the first will draw the arrows, lines, etc. and the second the rectangle or central circle. After that, it is enough to move those elements according to the case.



          class Createpaintwidget(QtWidgets.QWidget):
          def __init__(self):
          super().__init__()
          self.sizeHint()
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._size = QtCore.QSizeF()
          self._path = QtGui.QPainterPath()
          self._rect = QtCore.QRectF()
          self._type = QtGui.QRegion.Rectangle
          self._factor = 1.0

          self._pos = QtCore.QPointF()
          self._initial_flag = False
          fnt = self.font()
          fnt.setPointSize(20)
          self.setFont(fnt)

          def showEvent(self, event):
          if not self._initial_flag:
          self._pos = self.rect().center()
          self._initial_flag = True

          @QtCore.pyqtSlot(int, int)
          def set_size_squares(self, w, h):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(w, h)
          self._type = QtGui.QRegion.Rectangle
          self.updatePath()

          @QtCore.pyqtSlot(int)
          def set_size_round(self, v):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(v, v)
          self._type = QtGui.QRegion.Ellipse
          self.updatePath()

          def paintEvent(self, event):
          pen = QtGui.QPen()
          brush = QtGui.QBrush(QtCore.Qt.black)
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setPen(pen)
          painter.setBrush(brush)

          painter.translate(self.rect().center())
          painter.scale(self._factor, self._factor)
          painter.translate(-self.rect().center())

          painter.translate(self._pos)
          painter.drawPath(self._path)
          if self._type == QtGui.QRegion.Rectangle:
          painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
          painter.drawRect(self._rect)
          elif self._type == QtGui.QRegion.Ellipse:
          painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.drawEllipse(self._rect)

          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super().mousePressEvent(event)

          def mouseMoveEvent(self, event):
          delta = event.pos() - self._initial_pos
          self._path.translate(delta)
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super().mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super().mouseReleaseEvent(event)

          def updatePath(self):
          fm = QtGui.QFontMetrics(self.font())
          r = QtCore.QRectF(QtCore.QPointF(), self._size)
          r.moveCenter(QtCore.QPointF())
          self._rect = QtCore.QRectF(r)
          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, -16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.lineTo(p)
          self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(0, -self._size.height()/2 - 75)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(16, 16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

          if self._type == QtGui.QRegion.Rectangle:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -40))
          self._path.lineTo(p+ QtCore.QPoint(0, 20))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)

          pt = r.topLeft() + QtCore.QPointF(-75, 0)
          pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
          self._path.moveTo(pt)
          self._path.lineTo(pb)
          for p in (pt, pb):
          self._path.moveTo(p+ QtCore.QPoint(40, 0))
          self._path.lineTo(p+ QtCore.QPoint(-20, 0))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.height())
          p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
          self._path.addText(p , self.font(), word)
          if self._type == QtGui.QRegion.Ellipse:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
          self._path.lineTo(p+ QtCore.QPoint(0, 10))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)
          self.update()

          def wheelEvent(self, event):
          self._factor *= 1.01**(event.angleDelta().y()/15.0)
          self.update()
          super().wheelEvent(event)





          share|improve this answer























          • Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
            – Zar Kha
            Nov 21 at 20:13










          • @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
            – eyllanesc
            Nov 21 at 20:19










          • @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
            – eyllanesc
            Nov 21 at 20:20










          • My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
            – Zar Kha
            Nov 21 at 20:31












          • @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
            – eyllanesc
            Nov 21 at 20:38











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














           

          draft saved


          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418848%2fqpaint-with-mouse-event-panning%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          1
          down vote



          accepted










          To make the pan you must follow the following steps:




          • Get the initial position in mousePressEvent


          • In mouseMoveEvent move the rectangle with the difference between the current position and the initial position, and update the initial position with the current position.



          The implementation is as follows:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._rect = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._rect.moveCenter(self.rect().center())
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          painter.drawRect(self._rect)

          def mousePressEvent(self, event):
          if self._rect.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          if self._rect.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          But instead of doing it Qt already offers classes that allow you to do the tasks that you point out in a simple way, in this case it is to use QGraphicsView with the QGraphicsItem:



          class GraphicsRectItem(QtWidgets.QGraphicsRectItem):
          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          super(GraphicsRectItem, self).mousePressEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(GraphicsRectItem, self).mouseReleaseEvent(event)

          class Paint(QtWidgets.QGraphicsView):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          scene = QtWidgets.QGraphicsScene(self)
          self.setScene(scene)
          rect_item = GraphicsRectItem(0, 0, 350, 250)
          rect_item.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          rect_item.setPen(QtCore.Qt.darkCyan)
          rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
          self.scene().addItem(rect_item)


          UPDATE:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()
          self._pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._pos = self.rect().center()
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          painter.drawRect(r)

          def mousePressEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._pos += delta
          self._initial_pos = event.pos()
          self.update()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          Update:



          One way to implement the task is to have an element or set connected element, in this case it is a QPainterPath plus a QRectF, the first will draw the arrows, lines, etc. and the second the rectangle or central circle. After that, it is enough to move those elements according to the case.



          class Createpaintwidget(QtWidgets.QWidget):
          def __init__(self):
          super().__init__()
          self.sizeHint()
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._size = QtCore.QSizeF()
          self._path = QtGui.QPainterPath()
          self._rect = QtCore.QRectF()
          self._type = QtGui.QRegion.Rectangle
          self._factor = 1.0

          self._pos = QtCore.QPointF()
          self._initial_flag = False
          fnt = self.font()
          fnt.setPointSize(20)
          self.setFont(fnt)

          def showEvent(self, event):
          if not self._initial_flag:
          self._pos = self.rect().center()
          self._initial_flag = True

          @QtCore.pyqtSlot(int, int)
          def set_size_squares(self, w, h):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(w, h)
          self._type = QtGui.QRegion.Rectangle
          self.updatePath()

          @QtCore.pyqtSlot(int)
          def set_size_round(self, v):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(v, v)
          self._type = QtGui.QRegion.Ellipse
          self.updatePath()

          def paintEvent(self, event):
          pen = QtGui.QPen()
          brush = QtGui.QBrush(QtCore.Qt.black)
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setPen(pen)
          painter.setBrush(brush)

          painter.translate(self.rect().center())
          painter.scale(self._factor, self._factor)
          painter.translate(-self.rect().center())

          painter.translate(self._pos)
          painter.drawPath(self._path)
          if self._type == QtGui.QRegion.Rectangle:
          painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
          painter.drawRect(self._rect)
          elif self._type == QtGui.QRegion.Ellipse:
          painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.drawEllipse(self._rect)

          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super().mousePressEvent(event)

          def mouseMoveEvent(self, event):
          delta = event.pos() - self._initial_pos
          self._path.translate(delta)
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super().mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super().mouseReleaseEvent(event)

          def updatePath(self):
          fm = QtGui.QFontMetrics(self.font())
          r = QtCore.QRectF(QtCore.QPointF(), self._size)
          r.moveCenter(QtCore.QPointF())
          self._rect = QtCore.QRectF(r)
          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, -16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.lineTo(p)
          self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(0, -self._size.height()/2 - 75)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(16, 16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

          if self._type == QtGui.QRegion.Rectangle:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -40))
          self._path.lineTo(p+ QtCore.QPoint(0, 20))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)

          pt = r.topLeft() + QtCore.QPointF(-75, 0)
          pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
          self._path.moveTo(pt)
          self._path.lineTo(pb)
          for p in (pt, pb):
          self._path.moveTo(p+ QtCore.QPoint(40, 0))
          self._path.lineTo(p+ QtCore.QPoint(-20, 0))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.height())
          p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
          self._path.addText(p , self.font(), word)
          if self._type == QtGui.QRegion.Ellipse:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
          self._path.lineTo(p+ QtCore.QPoint(0, 10))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)
          self.update()

          def wheelEvent(self, event):
          self._factor *= 1.01**(event.angleDelta().y()/15.0)
          self.update()
          super().wheelEvent(event)





          share|improve this answer























          • Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
            – Zar Kha
            Nov 21 at 20:13










          • @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
            – eyllanesc
            Nov 21 at 20:19










          • @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
            – eyllanesc
            Nov 21 at 20:20










          • My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
            – Zar Kha
            Nov 21 at 20:31












          • @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
            – eyllanesc
            Nov 21 at 20:38















          up vote
          1
          down vote



          accepted










          To make the pan you must follow the following steps:




          • Get the initial position in mousePressEvent


          • In mouseMoveEvent move the rectangle with the difference between the current position and the initial position, and update the initial position with the current position.



          The implementation is as follows:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._rect = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._rect.moveCenter(self.rect().center())
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          painter.drawRect(self._rect)

          def mousePressEvent(self, event):
          if self._rect.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          if self._rect.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          But instead of doing it Qt already offers classes that allow you to do the tasks that you point out in a simple way, in this case it is to use QGraphicsView with the QGraphicsItem:



          class GraphicsRectItem(QtWidgets.QGraphicsRectItem):
          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          super(GraphicsRectItem, self).mousePressEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(GraphicsRectItem, self).mouseReleaseEvent(event)

          class Paint(QtWidgets.QGraphicsView):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          scene = QtWidgets.QGraphicsScene(self)
          self.setScene(scene)
          rect_item = GraphicsRectItem(0, 0, 350, 250)
          rect_item.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          rect_item.setPen(QtCore.Qt.darkCyan)
          rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
          self.scene().addItem(rect_item)


          UPDATE:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()
          self._pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._pos = self.rect().center()
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          painter.drawRect(r)

          def mousePressEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._pos += delta
          self._initial_pos = event.pos()
          self.update()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          Update:



          One way to implement the task is to have an element or set connected element, in this case it is a QPainterPath plus a QRectF, the first will draw the arrows, lines, etc. and the second the rectangle or central circle. After that, it is enough to move those elements according to the case.



          class Createpaintwidget(QtWidgets.QWidget):
          def __init__(self):
          super().__init__()
          self.sizeHint()
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._size = QtCore.QSizeF()
          self._path = QtGui.QPainterPath()
          self._rect = QtCore.QRectF()
          self._type = QtGui.QRegion.Rectangle
          self._factor = 1.0

          self._pos = QtCore.QPointF()
          self._initial_flag = False
          fnt = self.font()
          fnt.setPointSize(20)
          self.setFont(fnt)

          def showEvent(self, event):
          if not self._initial_flag:
          self._pos = self.rect().center()
          self._initial_flag = True

          @QtCore.pyqtSlot(int, int)
          def set_size_squares(self, w, h):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(w, h)
          self._type = QtGui.QRegion.Rectangle
          self.updatePath()

          @QtCore.pyqtSlot(int)
          def set_size_round(self, v):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(v, v)
          self._type = QtGui.QRegion.Ellipse
          self.updatePath()

          def paintEvent(self, event):
          pen = QtGui.QPen()
          brush = QtGui.QBrush(QtCore.Qt.black)
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setPen(pen)
          painter.setBrush(brush)

          painter.translate(self.rect().center())
          painter.scale(self._factor, self._factor)
          painter.translate(-self.rect().center())

          painter.translate(self._pos)
          painter.drawPath(self._path)
          if self._type == QtGui.QRegion.Rectangle:
          painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
          painter.drawRect(self._rect)
          elif self._type == QtGui.QRegion.Ellipse:
          painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.drawEllipse(self._rect)

          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super().mousePressEvent(event)

          def mouseMoveEvent(self, event):
          delta = event.pos() - self._initial_pos
          self._path.translate(delta)
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super().mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super().mouseReleaseEvent(event)

          def updatePath(self):
          fm = QtGui.QFontMetrics(self.font())
          r = QtCore.QRectF(QtCore.QPointF(), self._size)
          r.moveCenter(QtCore.QPointF())
          self._rect = QtCore.QRectF(r)
          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, -16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.lineTo(p)
          self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(0, -self._size.height()/2 - 75)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(16, 16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

          if self._type == QtGui.QRegion.Rectangle:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -40))
          self._path.lineTo(p+ QtCore.QPoint(0, 20))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)

          pt = r.topLeft() + QtCore.QPointF(-75, 0)
          pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
          self._path.moveTo(pt)
          self._path.lineTo(pb)
          for p in (pt, pb):
          self._path.moveTo(p+ QtCore.QPoint(40, 0))
          self._path.lineTo(p+ QtCore.QPoint(-20, 0))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.height())
          p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
          self._path.addText(p , self.font(), word)
          if self._type == QtGui.QRegion.Ellipse:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
          self._path.lineTo(p+ QtCore.QPoint(0, 10))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)
          self.update()

          def wheelEvent(self, event):
          self._factor *= 1.01**(event.angleDelta().y()/15.0)
          self.update()
          super().wheelEvent(event)





          share|improve this answer























          • Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
            – Zar Kha
            Nov 21 at 20:13










          • @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
            – eyllanesc
            Nov 21 at 20:19










          • @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
            – eyllanesc
            Nov 21 at 20:20










          • My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
            – Zar Kha
            Nov 21 at 20:31












          • @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
            – eyllanesc
            Nov 21 at 20:38













          up vote
          1
          down vote



          accepted







          up vote
          1
          down vote



          accepted






          To make the pan you must follow the following steps:




          • Get the initial position in mousePressEvent


          • In mouseMoveEvent move the rectangle with the difference between the current position and the initial position, and update the initial position with the current position.



          The implementation is as follows:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._rect = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._rect.moveCenter(self.rect().center())
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          painter.drawRect(self._rect)

          def mousePressEvent(self, event):
          if self._rect.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          if self._rect.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          But instead of doing it Qt already offers classes that allow you to do the tasks that you point out in a simple way, in this case it is to use QGraphicsView with the QGraphicsItem:



          class GraphicsRectItem(QtWidgets.QGraphicsRectItem):
          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          super(GraphicsRectItem, self).mousePressEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(GraphicsRectItem, self).mouseReleaseEvent(event)

          class Paint(QtWidgets.QGraphicsView):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          scene = QtWidgets.QGraphicsScene(self)
          self.setScene(scene)
          rect_item = GraphicsRectItem(0, 0, 350, 250)
          rect_item.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          rect_item.setPen(QtCore.Qt.darkCyan)
          rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
          self.scene().addItem(rect_item)


          UPDATE:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()
          self._pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._pos = self.rect().center()
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          painter.drawRect(r)

          def mousePressEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._pos += delta
          self._initial_pos = event.pos()
          self.update()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          Update:



          One way to implement the task is to have an element or set connected element, in this case it is a QPainterPath plus a QRectF, the first will draw the arrows, lines, etc. and the second the rectangle or central circle. After that, it is enough to move those elements according to the case.



          class Createpaintwidget(QtWidgets.QWidget):
          def __init__(self):
          super().__init__()
          self.sizeHint()
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._size = QtCore.QSizeF()
          self._path = QtGui.QPainterPath()
          self._rect = QtCore.QRectF()
          self._type = QtGui.QRegion.Rectangle
          self._factor = 1.0

          self._pos = QtCore.QPointF()
          self._initial_flag = False
          fnt = self.font()
          fnt.setPointSize(20)
          self.setFont(fnt)

          def showEvent(self, event):
          if not self._initial_flag:
          self._pos = self.rect().center()
          self._initial_flag = True

          @QtCore.pyqtSlot(int, int)
          def set_size_squares(self, w, h):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(w, h)
          self._type = QtGui.QRegion.Rectangle
          self.updatePath()

          @QtCore.pyqtSlot(int)
          def set_size_round(self, v):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(v, v)
          self._type = QtGui.QRegion.Ellipse
          self.updatePath()

          def paintEvent(self, event):
          pen = QtGui.QPen()
          brush = QtGui.QBrush(QtCore.Qt.black)
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setPen(pen)
          painter.setBrush(brush)

          painter.translate(self.rect().center())
          painter.scale(self._factor, self._factor)
          painter.translate(-self.rect().center())

          painter.translate(self._pos)
          painter.drawPath(self._path)
          if self._type == QtGui.QRegion.Rectangle:
          painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
          painter.drawRect(self._rect)
          elif self._type == QtGui.QRegion.Ellipse:
          painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.drawEllipse(self._rect)

          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super().mousePressEvent(event)

          def mouseMoveEvent(self, event):
          delta = event.pos() - self._initial_pos
          self._path.translate(delta)
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super().mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super().mouseReleaseEvent(event)

          def updatePath(self):
          fm = QtGui.QFontMetrics(self.font())
          r = QtCore.QRectF(QtCore.QPointF(), self._size)
          r.moveCenter(QtCore.QPointF())
          self._rect = QtCore.QRectF(r)
          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, -16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.lineTo(p)
          self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(0, -self._size.height()/2 - 75)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(16, 16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

          if self._type == QtGui.QRegion.Rectangle:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -40))
          self._path.lineTo(p+ QtCore.QPoint(0, 20))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)

          pt = r.topLeft() + QtCore.QPointF(-75, 0)
          pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
          self._path.moveTo(pt)
          self._path.lineTo(pb)
          for p in (pt, pb):
          self._path.moveTo(p+ QtCore.QPoint(40, 0))
          self._path.lineTo(p+ QtCore.QPoint(-20, 0))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.height())
          p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
          self._path.addText(p , self.font(), word)
          if self._type == QtGui.QRegion.Ellipse:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
          self._path.lineTo(p+ QtCore.QPoint(0, 10))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)
          self.update()

          def wheelEvent(self, event):
          self._factor *= 1.01**(event.angleDelta().y()/15.0)
          self.update()
          super().wheelEvent(event)





          share|improve this answer














          To make the pan you must follow the following steps:




          • Get the initial position in mousePressEvent


          • In mouseMoveEvent move the rectangle with the difference between the current position and the initial position, and update the initial position with the current position.



          The implementation is as follows:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._rect = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._rect.moveCenter(self.rect().center())
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          painter.drawRect(self._rect)

          def mousePressEvent(self, event):
          if self._rect.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          if self._rect.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          But instead of doing it Qt already offers classes that allow you to do the tasks that you point out in a simple way, in this case it is to use QGraphicsView with the QGraphicsItem:



          class GraphicsRectItem(QtWidgets.QGraphicsRectItem):
          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          super(GraphicsRectItem, self).mousePressEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(GraphicsRectItem, self).mouseReleaseEvent(event)

          class Paint(QtWidgets.QGraphicsView):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          scene = QtWidgets.QGraphicsScene(self)
          self.setScene(scene)
          rect_item = GraphicsRectItem(0, 0, 350, 250)
          rect_item.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          rect_item.setPen(QtCore.Qt.darkCyan)
          rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable)
          self.scene().addItem(rect_item)


          UPDATE:



          class Paint(QtWidgets.QWidget):
          def __init__(self, parent=None):
          super(Paint, self).__init__(parent)
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._width = 350
          self._height = 250
          self._initial_flag = False
          self._initial_pos = QtCore.QPoint()
          self._pos = QtCore.QPoint()

          def showEvent(self, event):
          if not self._initial_flag:
          # set initial pos
          self._pos = self.rect().center()
          self._initial_flag = True
          super(Paint, self).showEvent(event)

          def paintEvent(self, event):
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setBrush(QtGui.QBrush( QtCore.Qt.cyan))
          painter.setPen(QtCore.Qt.darkCyan)
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          painter.drawRect(r)

          def mousePressEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super(Paint, self).mousePressEvent(event)

          def mouseMoveEvent(self, event):
          r = QtCore.QRect(QtCore.QPoint(), QtCore.QSize(self._width, self._height))
          r.moveCenter(self._pos)
          if r.contains(event.pos()):
          delta = event.pos() - self._initial_pos
          self._pos += delta
          self._initial_pos = event.pos()
          self.update()
          super(Paint, self).mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super(Paint, self).mouseReleaseEvent(event)


          Update:



          One way to implement the task is to have an element or set connected element, in this case it is a QPainterPath plus a QRectF, the first will draw the arrows, lines, etc. and the second the rectangle or central circle. After that, it is enough to move those elements according to the case.



          class Createpaintwidget(QtWidgets.QWidget):
          def __init__(self):
          super().__init__()
          self.sizeHint()
          self.setBackgroundRole(QtGui.QPalette.Base)
          self.setAutoFillBackground(True)

          self._size = QtCore.QSizeF()
          self._path = QtGui.QPainterPath()
          self._rect = QtCore.QRectF()
          self._type = QtGui.QRegion.Rectangle
          self._factor = 1.0

          self._pos = QtCore.QPointF()
          self._initial_flag = False
          fnt = self.font()
          fnt.setPointSize(20)
          self.setFont(fnt)

          def showEvent(self, event):
          if not self._initial_flag:
          self._pos = self.rect().center()
          self._initial_flag = True

          @QtCore.pyqtSlot(int, int)
          def set_size_squares(self, w, h):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(w, h)
          self._type = QtGui.QRegion.Rectangle
          self.updatePath()

          @QtCore.pyqtSlot(int)
          def set_size_round(self, v):
          self._path = QtGui.QPainterPath()
          self._size = QtCore.QSizeF(v, v)
          self._type = QtGui.QRegion.Ellipse
          self.updatePath()

          def paintEvent(self, event):
          pen = QtGui.QPen()
          brush = QtGui.QBrush(QtCore.Qt.black)
          painter = QtGui.QPainter(self)
          painter.setRenderHint(QtGui.QPainter.Antialiasing)
          painter.setPen(pen)
          painter.setBrush(brush)

          painter.translate(self.rect().center())
          painter.scale(self._factor, self._factor)
          painter.translate(-self.rect().center())

          painter.translate(self._pos)
          painter.drawPath(self._path)
          if self._type == QtGui.QRegion.Rectangle:
          painter.fillRect(self._rect, QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush))
          painter.drawRect(self._rect)
          elif self._type == QtGui.QRegion.Ellipse:
          painter.setBrush(QtGui.QBrush(QtCore.Qt.gray, QtCore.Qt.Dense7Pattern))
          painter.drawEllipse(self._rect)

          def mousePressEvent(self, event):
          QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
          self._initial_pos = event.pos()
          super().mousePressEvent(event)

          def mouseMoveEvent(self, event):
          delta = event.pos() - self._initial_pos
          self._path.translate(delta)
          self._rect.translate(delta)
          self.update()
          self._initial_pos = event.pos()
          super().mouseMoveEvent(event)

          def mouseReleaseEvent(self, event):
          QtWidgets.QApplication.restoreOverrideCursor()
          super().mouseReleaseEvent(event)

          def updatePath(self):
          fm = QtGui.QFontMetrics(self.font())
          r = QtCore.QRectF(QtCore.QPointF(), self._size)
          r.moveCenter(QtCore.QPointF())
          self._rect = QtCore.QRectF(r)
          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(self._size.width()/2 + 75 ,0)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, -16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.lineTo(p)
          self._path.addText(p + QtCore.QPoint(16, 0) , self.font(), "x")

          self._path.moveTo(QtCore.QPointF())
          p = QtCore.QPointF(0, -self._size.height()/2 - 75)
          self._path.lineTo(p)
          self._path.lineTo(p + QtCore.QPoint(16, 16))
          self._path.lineTo(p)
          self._path.moveTo(p)
          self._path.lineTo(p + QtCore.QPoint(-16, 16))
          self._path.addText(p + QtCore.QPoint(0, -16) , self.font(), "y")

          if self._type == QtGui.QRegion.Rectangle:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -40))
          self._path.lineTo(p+ QtCore.QPoint(0, 20))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)

          pt = r.topLeft() + QtCore.QPointF(-75, 0)
          pb = r.bottomLeft() + QtCore.QPointF(-75, 0)
          self._path.moveTo(pt)
          self._path.lineTo(pb)
          for p in (pt, pb):
          self._path.moveTo(p+ QtCore.QPoint(40, 0))
          self._path.lineTo(p+ QtCore.QPoint(-20, 0))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.height())
          p = QtCore.QPointF(r.left() -80 - fm.width(word) , r.center().y() + 0.5*fm.height())
          self._path.addText(p , self.font(), word)
          if self._type == QtGui.QRegion.Ellipse:
          pl = r.bottomLeft() + QtCore.QPointF(0, 75)
          pr = r.bottomRight() + QtCore.QPointF(0, 75)
          self._path.moveTo(pl)
          self._path.lineTo(pr)
          for p in (pl, pr):
          self._path.moveTo(p+ QtCore.QPoint(0, -self._size.height()/2 - 20))
          self._path.lineTo(p+ QtCore.QPoint(0, 10))
          self._path.moveTo(p+ QtCore.QPoint(10, -10))
          self._path.lineTo(p+ QtCore.QPoint(-10, 10))
          word = "{}".format(self._size.width())
          p = QtCore.QPointF(r.center().x() - 0.5*fm.width(word) , r.bottom() + 100)
          self._path.addText(p , self.font(), word)
          self.update()

          def wheelEvent(self, event):
          self._factor *= 1.01**(event.angleDelta().y()/15.0)
          self.update()
          super().wheelEvent(event)






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 2 days ago

























          answered Nov 21 at 19:25









          eyllanesc

          68.6k93052




          68.6k93052












          • Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
            – Zar Kha
            Nov 21 at 20:13










          • @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
            – eyllanesc
            Nov 21 at 20:19










          • @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
            – eyllanesc
            Nov 21 at 20:20










          • My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
            – Zar Kha
            Nov 21 at 20:31












          • @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
            – eyllanesc
            Nov 21 at 20:38


















          • Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
            – Zar Kha
            Nov 21 at 20:13










          • @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
            – eyllanesc
            Nov 21 at 20:19










          • @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
            – eyllanesc
            Nov 21 at 20:20










          • My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
            – Zar Kha
            Nov 21 at 20:31












          • @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
            – eyllanesc
            Nov 21 at 20:38
















          Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
          – Zar Kha
          Nov 21 at 20:13




          Great, you are indeed clever. Thanks. I notes when QGraphicsView runs and autoscrolles appears but this is not the case when Qpainteruses, can a scroll add to Qpainter?.But what is the difference between QPainter and QGraphicsView. I have seen QGraphicsView is been used widely?
          – Zar Kha
          Nov 21 at 20:13












          @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
          – eyllanesc
          Nov 21 at 20:19




          @ZarKha QGraphicsView is a widget specialized in handling items that internally uses QPainter, that is, it is a high level way to paint. The scrollbar appears because QGraphiscView is designed to handle items that may be in larger positions on your screen, it can be disabled. In conclusion with QPainter are in the stone age where it was painted manually and with QGraphicsView you are using MS paint or similar
          – eyllanesc
          Nov 21 at 20:19












          @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
          – eyllanesc
          Nov 21 at 20:20




          @ZarKha If my answer helps you do not forget to mark it as correct, if you do not know how to do it then review the tour, that is the best way to thank.
          – eyllanesc
          Nov 21 at 20:20












          My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
          – Zar Kha
          Nov 21 at 20:31






          My last question according to your answer, I had this code line self._rect = within def paint, in your answer you have brought it outside of function, that indeed gives some errors which I have in my private code. The event wont run! is it a way to keep it inside the function? I really need this to be solved?
          – Zar Kha
          Nov 21 at 20:31














          @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
          – eyllanesc
          Nov 21 at 20:38




          @ZarKha Surely in the old answer do not point out that the rectangle was movable so the rectangle is fixed and used in the paintEvent, but in this case is dynamic although I think it can maintain the previous logic, at a time I will give an alternative. On the other hand I do not know the implementation of your private code so I will not think since you probably have other errors.
          – eyllanesc
          Nov 21 at 20:38


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53418848%2fqpaint-with-mouse-event-panning%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          What visual should I use to simply compare current year value vs last year in Power BI desktop

          Alexandru Averescu

          Trompette piccolo