PyQt5 - 在 QMainMenu 中,如何使 QWidget 成为父级(暂时)?

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

我有一个 QMainWindow,我用 QWidget 初始化了它。我希望每次按下按钮 New 在我的 QMainWiindow 中,它会暂时打开 QWidget(在我的情况下,直到鼠标按钮释放)。

我在 QMainWindowQWidget 互动时遇到问题。我尝试了很多选项,但似乎我尝试的所有选项都将 QWidget 绑定到 QMainWindow 屏幕,我不希望这样。

举个例子会更容易:

TempWidgetMenu.py 是我的 QMainWindow class。当我按下 New 时,会出现一个 QWidget,它会将屏幕着色为灰色,并且将从按钮按下到按钮释放的矩形着色(如 windows 剪切工具)。

我希望每次按下 New 时,我都能够从屏幕的每个点绘制一个矩形,这是第一次。 当我第二次(或之后)按 New 时,它将为除主菜单屏幕以外的所有内容着色,并且不会响应按钮操作。

我希望每次按下按钮时小部件都是屏幕中程序的"parent"。

TempWidgetMenu.py(主要):

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()

我意识到我在一开始就初始化了 TempOpacWidget。我只想初始化一次,因为它在做同样的事情。

我怎样才能解决这个问题,让 TempOpacWidget 每次调用他时都是父级?

编辑:如果有什么不清楚的地方,运行 代码将非常有意义。按New,选择一个矩形(用鼠标),然后再按New选择另一个矩形,你就会明白是什么问题了。

如果我没理解错的话,您希望 Menu.opac_rect 在按下鼠标按钮时在单独的 window 中打开。我看到了几个问题。首先,如果您希望 QWidget 在单独的 window 中打开,您应该将 Qt.windowFlags 参数传递给 QWidget 构造函数,即

self.opac_rect = TempWidget.TempOpacWidget(None, QtCore.Qt.Window)

不要忘记导入 QtCore 命名空间。

其次,QAction没有您需要的信号。只有从 QWidget 继承的对象才会有 mousePressEventmouseReleaseEvent。如果您必须将东西保留在工具栏中,QToolBarQToolBar.addWidget,因此您可以使用 QLabel 而不是 QAction,并覆盖必要的事件处理程序。

self.opac_rect = TempWidget.TempOpacWidget(None, QtCore.Qt.Window)
newAct = QLabel('New')
newAct.mousePressEvent = lambda e: self.opac_rect.start()
newAct.mouseReleaseEvent = lambda e: self.opac_rect.stop() # You'll need to write this
self.toolbar.addWidget(newAct)

您可能必须 fiddle 使用 QLabel 样式才能使它看起来正确,但我认为这将实现您正在寻找的东西。

我不太明白会发生什么, 但我添加并更改了一些代码行。 单击 New 按钮并绘制一个矩形。 你应该有新的想法。 祝你好运。

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()                         # +++