Search code examples
pythonpyqtpyqt5qwidgetqmainwindow

PyQt5 - in a QMainMenu, how to make a QWidget the parent (temporarily)?


I have a QMainWindow that I initialize with a QWidget. I want that each Time I'll press the button New In my QMainWiindow, it will open the QWidget temporarily (in my case, until mouse button release).

I'm having trouble interacting QMainWindow with the QWidget. I tried many options, but it seemed like everything I tried tied the QWidget to the QMainWindow screen, and I don't want that.

It will be easier with an example:

TempWidgetMenu.py is my QMainWindow class. When I press New, a QWidget will appear, it Will color the screen gray-ish, and will color a rectangle from a button press, to the button release (like in windows snipping tool).

I Want that that every time I press on New, I'll be able to draw a rectangle from every point of the screen, and so it does the first time. When I press New for the second time (or afterwards), it will color everything but the main menu screen, and will not respond to the button actions.

I want the widget to be the "parent" of the program in the screen every time I press the button.

TempWidgetMenu.py (main):

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QAction
from PyQt5.QtGui import QPixmap, QPainter
import TempWidget


class Menu(QMainWindow):

    def __init__(self):
        super().__init__()
        newAct = QAction('New', self)
        newAct.triggered.connect(self.new_image_window)
        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(newAct)
        self.opac_rect = TempWidget.TempOpacWidget()
        self.image = QPixmap("background.png")
        self.setGeometry(100, 100, 500, 300)
        self.resize(self.image.width(), self.image.height())
        self.show()

    def new_image_window(self):
        self.opac_rect.start()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.drawPixmap(self.rect(), self.image)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainMenu = Menu()
    sys.exit(app.exec_())

TempWidget.py :

import tkinter as tk
from PyQt5 import QtWidgets, QtCore, QtGui


class TempOpacWidget(QtWidgets.QWidget):

    def __init__(self):
        super().__init__()
        root = tk.Tk()
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        self.setGeometry(0, 0, screen_width, screen_height)
        self.setWindowTitle(' ')
        self.begin = QtCore.QPoint()
        self.end = QtCore.QPoint()
        self.busy = False

    def start(self):

        self.busy = True
        self.setWindowOpacity(0.3)
        self.show()

    def paintEvent(self, event):
        if self.busy:
            brush_color = (128, 128, 255, 100)
            opacity = 0.3
        else:
            brush_color = (0, 0, 0, 0)
            opacity = 0

        self.setWindowOpacity(opacity)
        qp = QtGui.QPainter(self)
        qp.setBrush(QtGui.QColor(*brush_color))
        qp.drawRect(QtCore.QRectF(self.begin, self.end))

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

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

    def mouseReleaseEvent(self, event):
        self.busy = False
        self.repaint()

I realize I'm initializing the TempOpacWidget once at the start. I want to initialize it only once, because it is doing the same thing.

How can I fix it, such that the TempOpacWidget will be the parent every time I call him?

Edit: If something is not clear, run the code it will make perfect sense. Press New, Choose a rectangle (with mouse), and then press New again to choose another rectangle, and you will understand what is the problem.


Solution

  • I do not quite understand what's going to happen, but I added and changed some lines of code. Click the New button and draw a rectangle. You should have new ideas. Good luck.

    TempWidgetMenu.py

    import sys
    from PyQt5.QtWidgets import QMainWindow, QApplication, QAction
    from PyQt5.QtGui     import QPixmap, QPainter
    from PyQt5.QtCore    import Qt                             # +++
    import TempWidget
    
    class Menu(QMainWindow):
        def __init__(self):
            super().__init__()
            newAct = QAction('New', self)
            newAct.triggered.connect(self.new_image_window)
            self.toolbar = self.addToolBar('Exit')
            self.toolbar.addAction(newAct)
    
            self.opac_rect = TempWidget.TempOpacWidget(self)   # +++ self
    
            self.imageShow()                                   # +++  
    
        def imageShow(self):
            self.setWindowFlags(Qt.WindowStaysOnTopHint)       # +++ 
    
            self.image = QPixmap("background.png")
            self.setGeometry(100, 100, 500, 300)
            self.resize(self.image.width(), self.image.height())
            self.show()
    
        def new_image_window(self):
            self.opac_rect.start()
    
        def paintEvent(self, event):
            painter = QPainter(self)
            painter.drawPixmap(self.rect(), self.image)
    
        # +++    
        def closeEvent(self, event):
            self.opac_rect.close()
            event.accept()
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        mainMenu = Menu()
        sys.exit(app.exec_())
    

    TempWidget.py

    import tkinter as tk
    from PyQt5        import QtWidgets, QtCore, QtGui
    from PyQt5.QtCore import Qt                                 # +++
    
    class TempOpacWidget(QtWidgets.QWidget):
    
    #    def __init__(self):
    #        super().__init__()
        def __init__(self, parent=None):
            super(TempOpacWidget, self).__init__()              # no (parent)
            self.parent = parent                                # +++
            print("self=`{}`, \nparent=`{}`".format(self, self.parent))
            self.setWindowFlags(Qt.WindowStaysOnTopHint)        # +++
    
            root = tk.Tk()
            screen_width  = root.winfo_screenwidth()
            screen_height = root.winfo_screenheight()
            self.setGeometry(0, 0, screen_width, screen_height)
    #        self.setWindowTitle('')
            self.begin = QtCore.QPoint()
            self.end   = QtCore.QPoint()
            self.busy  = False
    
        def start(self):
            self.setWindowFlags(Qt.WindowStaysOnTopHint)        # +++
            self.busy = True
            self.setWindowOpacity(0.5) # 0.3
            self.show()
    
        def paintEvent(self, event):
            if self.busy:
                brush_color = (128, 128, 255, 100)
                opacity = 0.5          # 0.3
            else:
                brush_color = (0, 0, 0, 0)
    
                opacity = 0.5          # 0       <<<---------
                # or try  `0`, how suits you !?  <<<---------
                #opacity = 0                    #<<<--------- 
    
            self.setWindowOpacity(opacity)
            qp = QtGui.QPainter(self)
            qp.setBrush(QtGui.QColor(*brush_color))
            qp.drawRect(QtCore.QRectF(self.begin, self.end))
    
        def mousePressEvent(self, event):
            #self.parent.hide()
            self.begin = event.pos()
            self.end   = self.begin
            self.update()
    
        def mouseMoveEvent(self, event):
            self.end = event.pos()
            self.update()
    
        def mouseReleaseEvent(self, event):
            print("def mouseReleaseEvent(self, event):---")
            self.busy = False
            self.repaint()
            self.parent.imageShow()                         # +++
    

    enter image description here