Search code examples
pythonqtpyqtqgraphicsviewqmainwindow

How to draw on QGraphicsView from QMainWindow


Current design shown below of QgraphicsView and QMainWindow class is an example of the design I have in a different software.

I had to add scrollbars to the QGraphicsView. The original software has all mouse events handled in QMainWindow.

Questions: What is the way to draw on QGraphicsView through QMainWindow?

import sys

from PyQt4 import QtGui
from PyQt4 import QtCore

class Window(QtGui.QGraphicsView):

  def __init__(self, parent=None):

        QtGui.QGraphicsView.__init__(self, parent)
        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.darkGray, QtCore.Qt.SolidPattern))
        self.setScene(self.scene)

        #self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)
        self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
        #self.viewport().setCursor(QtCore.Qt.CrossCursor)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)

        print "sdsads"


  def mousePressEvent(self, ev):
        item = QtGui.QGraphicsTextItem("")
        item.setPos(ev.x(), ev.y())
        self.scene.addItem(item)

        print "ev.x() ", ev.x()


class CityscapesLabelTool(QtGui.QMainWindow):
    def __init__(self, parent=None):

        QtGui.QMainWindow.__init__(self, parent)
        centralwidget = Window()
        self.setCentralWidget(centralwidget) 

        centralwidget.scene.addPixmap(QtGui.QPixmap("exit.png"))



app = QtGui.QApplication(sys.argv)
GUI = CityscapesLabelTool()
GUI.show()
sys.exit(app.exec_())

Solution

  • In a QGraphicsView it is normal to add items to the scene, for example in case you want to draw a polygon you must use QGraphicsPolygonItem, also if you want to get correct points you must use QGraphicsScene instead of QGraphicsView.

    In the following example you can indicate the polygon points by left clicking and finish the drawing with the right click.

    import sys
    
    from PyQt4 import QtCore, QtGui
    
    class GraphicsScene(QtGui.QGraphicsScene):
        def __init__(self, *args, **kwargs):
            QtGui.QGraphicsScene.__init__(self, *args, **kwargs)
            self.polygon = None
    
        def mousePressEvent(self, ev):
            if ev.button() == QtCore.Qt.RightButton:
                self.polygon << ev.scenePos()
                item = QtGui.QGraphicsPolygonItem(self.polygon)
                item.setPen(QtGui.QPen(QtCore.Qt.red))
                item.setBrush(QtGui.QBrush(QtCore.Qt.red))
                self.addItem(item)
                # or
                # self.addPolygon(self.polygon, QtGui.QPen(QtCore.Qt.red), QtGui.QBrush(QtCore.Qt.red))
                self.polygon = None
    
            else:
                if self.polygon is None:
                    self.polygon = QtGui.QPolygonF()
                self.polygon << ev.scenePos()
    
    class Window(QtGui.QGraphicsView):
        def __init__(self, parent=None):
            QtGui.QGraphicsView.__init__(self, parent)
            self.scene =GraphicsScene(QtCore.QRectF(0, 0, 640, 480), self)
            self.scene.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.darkGray, QtCore.Qt.SolidPattern))
            self.setScene(self.scene)
            #self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)
            self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
            #self.viewport().setCursor(QtCore.Qt.CrossCursor)
            self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
            self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
    
    
    class CityscapesLabelTool(QtGui.QMainWindow):
        def __init__(self, parent=None):
    
            QtGui.QMainWindow.__init__(self, parent)
            centralwidget = Window()
            self.setCentralWidget(centralwidget) 
    
            centralwidget.scene.addPixmap(QtGui.QPixmap("exit.png"))
    
    
    app = QtGui.QApplication(sys.argv)
    GUI = CityscapesLabelTool()
    GUI.show()
    sys.exit(app.exec_())
    

    Output:

    enter image description here


    You have an XY problem, where you are looking for the solution for a solution of the main problem without knowing that it is the correct one, according to what you comment your main problem is to add QScrollBar to the QMainWindow, and in that element you want to make drawings, so for that it is not necessary to use a QGraphicsView but a QScrollArea.

    import sys
    
    from PyQt4 import QtCore, QtGui
    
    
    class Window(QtGui.QWidget):
        def __init__(self, parent=None):
            QtGui.QWidget.__init__(self, parent)
            self.polygon = None
            self.setFixedSize(640, 480)
            self.pixmap = None
    
        def mousePressEvent(self, ev):
            if self.polygon is None:
                self.polygon = QtGui.QPolygon()
            self.polygon << ev.pos()
            self.update()
    
        def paintEvent(self, ev):
            painter = QtGui.QPainter(self)
            painter.fillRect(self.rect(), QtGui.QBrush(QtCore.Qt.darkGray, QtCore.Qt.SolidPattern))
            painter.drawPixmap(QtCore.QPoint(0, 0), QtGui.QPixmap("exit.png"))
            if self.polygon is not None:
                painter.setPen(QtCore.Qt.blue)
                painter.drawPolyline(self.polygon)
    
    
    
    class CityscapesLabelTool(QtGui.QMainWindow):
        def __init__(self, parent=None):
    
            QtGui.QMainWindow.__init__(self, parent)
            scroll = QtGui.QScrollArea()
    
            scroll.setBackgroundRole(QtGui.QPalette.Dark)
            scroll.setWidget(Window())
            scroll.setWidgetResizable(True)
            self.setCentralWidget(scroll)
    
    
    
    app = QtGui.QApplication(sys.argv)
    GUI = CityscapesLabelTool()
    GUI.show()
    sys.exit(app.exec_())
    

    enter image description here