PyQt5 - 在 QMainMenu 中,如何使 QWidget 成为父级(暂时)?
Posted
技术标签:
【中文标题】PyQt5 - 在 QMainMenu 中,如何使 QWidget 成为父级(暂时)?【英文标题】:PyQt5 - in a QMainMenu, how to make a QWidget the parent (temporarily)? 【发布时间】:2018-08-01 14:07:58 【问题描述】:我有一个QMainWindow
,我用QWidget
进行了初始化。我希望每次按下按钮New
在我的QMainWiindow
中,它会暂时打开QWidget
(在我的情况下,直到鼠标按钮释放)。
我无法与QMainWindow
与QWidget
交互。我尝试了很多选项,但似乎我尝试的所有方法都将QWidget
绑定到QMainWindow
屏幕,我不希望这样。
举个例子会更容易:
TempWidgetMenu.py
是我的QMainWindow
班级。当我按下New
时,会出现一个QWidget
,它会将屏幕着色为灰色,并且会为从按下按钮到释放按钮的矩形着色(就像在 Windows 截图工具中一样)。
我希望每次按下New
时,我都能够从屏幕的每个点绘制一个矩形,并且第一次就这样做了。
当我第二次(或之后)按下New
时,它将为除主菜单屏幕之外的所有内容着色,并且不会响应按钮操作。
我希望每次按下按钮时小部件都成为屏幕中程序的“父级”。
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
选择另一个矩形,你就会明白问题出在哪里了。
【问题讨论】:
【参考方案1】:我不太明白会发生什么,
但我添加并更改了一些代码行。
单击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() # +++
【讨论】:
【参考方案2】:如果我理解正确,您希望Menu.opac_rect
在按下鼠标按钮时在单独的窗口中打开。我看到这有几个问题。首先,如果您希望 QWidget
在单独的窗口中打开,您应该将 Qt.windowFlags
参数传递给 QWidget
构造函数,即
self.opac_rect = TempWidget.TempOpacWidget(None, QtCore.Qt.Window)
不要忘记导入 QtCore
命名空间。
其次,QAction
没有您需要的信号。只有从QWidget
继承的对象才会有mousePressEvent
和mouseReleaseEvent
。如果你必须在工具栏中保留东西,QToolBar
有QToolBar.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)
您可能不得不摆弄QLabel
样式以使其看起来正确,但我认为这将实现您所寻找的。p>
【讨论】:
不完全是。当我按下 New 时,我希望它为整个屏幕着色,并且只有在不同的按钮释放后屏幕才会恢复正常(与按下 New 无关)。我修改了代码示例,如果你运行它,它会更有意义。 @TheCrystalShip 与新闻和发布相关联而不是点击有多重要?彩色小部件(部分透明?)是否覆盖了您正在绘制的图像? 这很重要。我更新了我的代码。按New,选择一个矩形,然后再按New,你就会明白是什么问题了。以上是关于PyQt5 - 在 QMainMenu 中,如何使 QWidget 成为父级(暂时)?的主要内容,如果未能解决你的问题,请参考以下文章
pyqt5如何使复选框将两个Qslider锁定在一起[关闭]