1

I want to paint a rectangle in a certain label, I made a GUI with QtDesigner that generates the whole GUI code in one class called "class Ui_MainWindow(QMainWindow):" and I am using three tabs in my window.

I had a problem using the QMouseEvent on my labels, I found a solution using this code

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
import sys
import cv2
from PyQt5.QtWidgets import QMainWindow, QWidget, QLabel
from PyQt5.QtGui import QPixmap, QImage

class Ui_MainWindow(QMainWindow):

    def __init__(self):
        # super(Ui_MainWindow, self).__init__ ()
        super().__init__()
        self.count = 0
        self.frame = 0
        self.fileName="0"
        self.imagesTab2 = []
        self.k = 0
        self.i = 1
        self.w = 0
        self.h = 0
        self.coordPt = []
        self.dictListClasses = {
            "face" :[],
            "car" : [] }
        self.dictColorClasses = {
            "face" :(0, 100, 255),
            "car" : (0,255, 0) }


    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(655, 364)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab)
        self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.pushButton = QtWidgets.QPushButton(self.tab)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout.addWidget(self.pushButton)
        self.verticalLayout_2.addLayout(self.horizontalLayout)
        self.label = QtWidgets.QLabel(self.tab)
        self.label.setText("")
        self.label.setObjectName("label")
        self.label.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.label.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.setMouseEventDelegate(self.label)
        self.verticalLayout_2.addWidget(self.label)
        self.verticalLayout_2.setStretch(1, 1)
        self.tabWidget.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.tabWidget.addTab(self.tab_2, "")
        self.verticalLayout.addWidget(self.tabWidget)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 655, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Open"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Tab 1"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Tab 2"))

        self.pushButton.clicked.connect(self.openFileTab2)

    def setMouseEventDelegate (self, setQWidget):
        def subWidgetMousePressEvent(e: QtGui.QMouseEvent):
            if self.imagesTab2:
                if e.button() == Qt.LeftButton:
                    po = int(e.x()*self.w/self.label.width())
                    pa = int(e.y()*self.h/self.label.height())
                    self.coordPt = [(po, pa)]
                    print("coords click = ", self.coordPt)
                    self.begin = e.pos()
                    self.end = e.pos()
                    self.label.update()
                    print("begin 1= ",self.begin, self.end)

        def subWidgetMouseMoveEvent(e: QtGui.QMouseEvent):
            if self.imagesTab2:
                self.end = e.pos()
                self.label.update()

        def subWidgetMouseReleaseEvent(e: QtGui.QMouseEvent):
            if e.button() == Qt.LeftButton:
                if self.imagesTab2:
                    if e.x() >= 0 and e.y() >= 0 and e.x()<self.label.width() and e.y()<self.label.height():
                        po = int(e.x()*self.w/self.label.width())
                        pa = int(e.y()*self.h/self.label.height())
                        self.coordPt.append((po, pa))
                        print("coords release = ", self.coordPt)
                        self.begin = e.pos()
                        self.end = e.pos()
                        self.label.update()
                        print("begin 2= ",self.begin, self.end)
                        self.dictListClasses["car"].append(self.coordPt)
                        print("LL + ", self.dictListClasses)
        setQWidget.mousePressEvent = subWidgetMousePressEvent
        setQWidget.mouseReleaseEvent = subWidgetMouseReleaseEvent
        setQWidget.mouseMoveEvent = subWidgetMouseMoveEvent

    def openFileTab2(self):
        self.imagesTab2, _ = QtWidgets.QFileDialog.getOpenFileNames(None,"Select one or more images to open", "/Images","Images (*.jpg *.jpeg .*bmp .*png);;All Files (*)")
        if self.imagesTab2:
            self.showImageInLabel(self.imagesTab2[0])
            # self.label_9.setText("Image 1")

    def showImageInLabel(self, img):
        pix = QPixmap(img)
        self.w = pix.width()
        self.h = pix.height()
        print("Image resolution = ", '(',self.w,')', '(',self.h,')')
        pix = pix.scaled(self.size(), aspectRatioMode=QtCore.Qt.KeepAspectRatio, ) # To scale image for example and keep its Aspect Ration  
        self.label.setPixmap(pix)
        self.label.setScaledContents(True)


    def nextImageTab2(self):
        if not self.imagesTab2:
            print("No files, please open one or more images")
            return
        if self.i < len(self.imagesTab2):
            path = self.imagesTab2[self.i]
            self.showImageInLabel(path)
            self.i += 1
            print(self.i)
            x = "Image " + str(self.i)
            # self.label_9.setText(x)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

The code above is to override the three functions : mousePressEvent, mouseReleaseEvent and mouseMoveEvent because if I use only def mouseMoveEvent (self, event): for example, it doesn't work on my label I don't know how to set it to work on a certain label

So I tried to override the QPaintEvent function but if I use the code like above and use this setQWidget.paintEvent = subWidgetPaintEvent the label disappears and i find only a rectangle

Can anyone helps me to use the events on my Label like in this code and thanks

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QColor, QBrush
from PyQt5 import QtWidgets, QtCore, QtGui

class Labella(QLabel):

    def __init__(self, parent):
        super().__init__(parent=parent)
        self.setStyleSheet('QFrame {background-color:white;}')
        self.resize(300, 300)
        self.begin = QtCore.QPoint()
        self.end = QtCore.QPoint()

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        br = QtGui.QBrush(QtGui.QColor(100, 10, 10, 40))  
        qp.setBrush(br)   
        qp.drawRect(QtCore.QRect(self.begin, self.end))       

    def mousePressEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()
        print("beegin = ", self.begin)
        print("end 1 = ", self.end)

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()

    def mouseReleaseEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()

    def drawRectangles(self, qp):    
        qp.setBrush(QColor(255, 0, 0, 100))
        qp.save() # save the QPainter config

        qp.drawRect(10, 15, 20, 20)

        qp.setBrush(QColor(0, 0, 255, 100))
        qp.drawRect(50, 15, 20, 20)

        qp.restore() # restore the QPainter config            
        qp.drawRect(100, 15, 20, 20)

class Example(QWidget):

    def __init__(self):
        super().__init__()

    lb = Labella(self)

    self.setGeometry(300, 300, 350, 300)
    self.setWindowTitle('Colours')
    self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
BouuuH
  • 13
  • 1
  • 4
  • Yes I want it to remain in the last code, but that's not the main problem, that's just a sample code that I was testing.. My main code is another one that is generated by QtDesigner and it has one class like I mentioned above and I want to do the same thing as in the last code but it doesn't work in my main code, is there a way that how to draw in a certain Label while having this label in a tabWidget which is in a QMainWindow ? and thanks for your replay – BouuuH Aug 09 '18 at 13:44
  • If my problem isn't clear enough I can add an image or two to explain more – BouuuH Aug 09 '18 at 13:45
  • here is my original code... I edited it above.. I already cut the code for the second tabWidget so it won't be long, which I don't have a problem in it – BouuuH Aug 09 '18 at 16:36
  • yeah sure, do I send it in an email or I share the code here too ? I think the comment wouldn't fit the whole code – BouuuH Aug 09 '18 at 16:39
  • here it is on pastebin because the code is so long https://pastebin.com/5dw6L0kZ – BouuuH Aug 09 '18 at 16:45

1 Answers1

2

The solution is to promote the Labella to be used in Qt Designer, for this you must first create the file labella.py.

labella.py

from PyQt5 import QtCore, QtGui, QtWidgets

class Labella(QtWidgets.QLabel):
    def __init__(self, parent):
        super().__init__(parent=parent)
        self.setStyleSheet('QFrame {background-color:white;}')
        self.resize(300, 300)
        self.begin = QtCore.QPoint()
        self.end = QtCore.QPoint()

    def paintEvent(self, event):
        super().paintEvent(event)
        qp = QtGui.QPainter(self)
        br = QtGui.QBrush(QtGui.QColor(100, 10, 10, 40))  
        qp.setBrush(br)   
        qp.drawRect(QtCore.QRect(self.begin, self.end))       

    def mousePressEvent(self, event):
        self.begin = event.pos()
        self.end = event.pos()
        self.update()
        print("beegin = ", self.begin)
        print("end 1 = ", self.end)

    def mouseMoveEvent(self, event):
        self.end = event.pos()
        self.update()

    def drawRectangles(self, qp):    
        qp.setBrush(QColor(255, 0, 0, 100))
        qp.save() # save the QPainter config
        qp.drawRect(10, 15, 20, 20)
        qp.setBrush(QColor(0, 0, 255, 100))
        qp.drawRect(50, 15, 20, 20)
        qp.restore() # restore the QPainter config            
        qp.drawRect(100, 15, 20, 20)

Then we place in the same folder the labella.py and the .ui that will call mainwindow.ui

.
├── labella.py
└── mainwindow.ui

You open the .ui file by obtaining the following:

enter image description here

Press the right click on the QLabel and select the option: Promote to ...

enter image description here

Fill in the fields as shown in the following image, then press the Add button and then the Promote button:

enter image description here

and finally generate the .py again with the help of pyuic5:

pyuic5 mainwindow.ui -o mainwindow.py -x

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thank you it is working, but the problem is that it covers the pixmap so there is no image shown, how can i fix that please – BouuuH Aug 09 '18 at 17:49
  • Thank you so much it was so helpful, I have on last thing if possible, I want the rectangle to last remain because it disappears after I release the mouse, can you help me with that, I'm sorry I know I asked a lot but it was a bit hard as a beginner – BouuuH Aug 09 '18 at 18:06