user3023715
user3023715

Reputation: 1619

PyQT Drawing in a Custom QGraphicsView showing on a QMainWindow

The basic idea is that I can't use a QGraphicsView class to draw while inside a QMainWindow. I can see the painEvent firing and that the information is flowing to the method that performs the drawing, but in the end nothing gets displayed. Here is the Class with the QGraphicsView:

class Display_Pixels(QGraphicsView):

    def __init__(self, parent=None):
        QGraphicsView.__init__(self, parent=parent)
        #super().__init__()
        self.initUI()
        self.img = cv2.imread('roi.jpg')

    def initUI(self):      
        self.setGeometry(100, 100, 650, 650)
        #self.setWindowTitle('By Pixel')
        #self.setMouseTracking(True)
        #self.show()
        res = 40 
        self.grid = np.array([ [-1] * res  for n in range(res)]) # list comprehension
        #print(self.grid.shape)


    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.drawRectangles(qp)
        qp.end()


    def drawRectangles(self, qp, w = 16):
        print("Drawing")
        mode = 0
        x,y = 0,0 # starting position
        lr = 20
        hr = 35
        col = QColor(0, 0, 0)
        col.setNamedColor('#d4d4d4')
        qp.setPen(col)
        #print(self.img.shape)

        for g_row, img_row in zip(self.grid, self.img):
            #print(img_row.shape)
            for g_col, img_col in zip(g_row, img_row):
                r, g, b = (img_col[0], img_col[1], img_col[2])
                #print(r,g,b)

                if g_col == 1:
                    if mode == 0:
                        r = int(math.log(r)*lr)
                        g = int(math.log(g)*hr)
                        b = int(math.log(b)*lr)
                    elif mode == 1:
                        if r+50 <= 220: r = r+50
                        if g+80 <= 255: g = g+80
                        if b+50 <= 220: b = b+50
                    else:
                        if r+70 <= 220: r = r+70
                        if g+140 <= 255: g = g+140
                        if b+70 <= 220: b = b+70

                    qp.setBrush(QColor(r, g, b))
                    qp.drawRect(x, y, w, w)
                else:
                    qp.setBrush(QColor(r, g, b))
                    qp.drawRect(x, y, w, w)

                #qp.setBrush(QColor(200, 0, 0))
                #qp.drawRect(x, y, w, w)
                x = x + w  # move right
            y = y + w # move down
            x = 0 # rest to left edge


    def mousePressEvent(self, QMouseEvent):
        w = 16.0

        #print("MOUSE:")
        #print('(', int(QMouseEvent.x()/w), ', ', int(QMouseEvent.y()/w), ')')
        #print (QMouseEvent.pos())
        x = float(QMouseEvent.x())
        y = float(QMouseEvent.y())
        self.grid[int(y/w)][int(x/w)] = -1 * self.grid[int(y/w)][int(x/w)]

        #print(img[int(y/w), int(x/w), :])

        self.repaint()
        #self.update()

And also the code for the main window:

class Window(QMainWindow):
    def __init__(self, parent=None):
        #This initializes the main window or form
        super(Window,self).__init__(parent=parent)
        self.setGeometry(1,31,900,900)
        self.setWindowTitle("Pre-Alignment system")

def run():
    app = QApplication.instance()
    if app is None: 
        app = QApplication(sys.argv)
    GUI = Window()
    view = Display_Pixels(GUI)
    #view = MyView(GUI)
    GUI.show()
    sys.exit(app.exec_())

run()

Upvotes: 1

Views: 878

Answers (1)

eyllanesc
eyllanesc

Reputation: 243887

QGraphicsView inherits from QAbstractScrollArea so the QPainter must set in the viewport(), that is:

def paintEvent(self, e):
    qp = QPainter()
    qp.begin(self.viewport())
    self.drawRectangles(qp)
    qp.end()

Although I would paint it is not the best since QGraphicsView has a paint layer that uses the items. In this case it is best to implement a custom item, also I have improved your algorithm.:

import sys
import numpy as np
import cv2
from PyQt5 import QtCore, QtGui, QtWidgets

class OpenCVItem(QtWidgets.QGraphicsItem):
    def __init__(self, img, parent=None):
        super(OpenCVItem, self).__init__(parent)
        res = 40
        self.grid = -np.ones((res, res))
        self._img = img
        height, width, channel = self._img.shape
        bytesPerLine = 3 * width
        self._qimage = QtGui.QImage(self._img.data, 
            width, height, 
            bytesPerLine, 
            QtGui.QImage.Format_RGB888).rgbSwapped()

    def boundingRect(self):
        w, h, _ = self._img.shape
        return QtCore.QRectF(0, 0, w, h)

    def paint(self, painter, option, widget):
        painter.drawImage(0, 0, self._qimage)
        self.drawRectangles(painter)

    def drawRectangles(self, painter):
        mode = 0
        lr = 20
        hr = 35
        painter.save()
        painter.setPen(QtGui.QPen(QtGui.QColor("#d4d4d4")))
        w1, h1 = self.grid.shape
        fw = self.boundingRect().width()/w1
        fh = self.boundingRect().height()/h1
        s = QtCore.QSizeF(fw, fh)
        for idx, v in np.ndenumerate(self.grid):            
            if v == 1:
                r_ = QtCore.QRectF(fw*QtCore.QPointF(*idx), s)
                r_int = r_.toRect()
                (r, g, b), _ = cv2.meanStdDev(self._img[r_int.left():r_int.right(), 
                    r_int.top():r_int.bottom()])
                if mode == 0:
                    r = np.log(r+1)*lr
                    g = np.log(g+1)*hr
                    b = np.log(b+1)*lr
                elif mode == 1:
                    if r+50 <= 220: r = r+50
                    if g+80 <= 255: g = g+80
                    if b+50 <= 220: b = b+50
                else:
                    if r+70 <= 220: r = r+70
                    if g+140 <= 255: g = g+140
                    if b+70 <= 220: b = b+70
                painter.setBrush(QtGui.QColor(*(int(x) for x in (r, g, b))))
                painter.drawRect(r_)
        painter.restore()

    def mousePressEvent(self, event):
        w1, h1 = self.grid.shape
        fw = self.boundingRect().width()/w1
        fh = self.boundingRect().height()/h1
        xi = int(event.pos().x()/fw) 
        yi = int(event.pos().y()/fh)
        self.grid[xi][yi] = -self.grid[xi][yi]
        self.update()
        super(OpenCVItem, self).mousePressEvent(event)

class Display_Pixels(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(Display_Pixels, self).__init__(parent)
        scene = QtWidgets.QGraphicsScene(self)
        self.setScene(scene)
        item = OpenCVItem(cv2.imread("roi.jpg"))
        scene.addItem(item)

class Window(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Window,self).__init__(parent=parent)
        self.setGeometry(1,31,900,900)
        self.setWindowTitle("Pre-Alignment system")

def run():
    app = QtWidgets.QApplication.instance()
    if app is None: 
        app = QtWidgets.QApplication(sys.argv)
    GUI = Window()
    view = Display_Pixels(GUI)
    GUI.setCentralWidget(view)
    GUI.show()
    sys.exit(app.exec_())

run()

Upvotes: 3

Related Questions