Main Window 中的 Qt Dialog,使背景变暗
Qt Dialog in Main Window, make the background dimmed
我正在尝试创建动态自定义对话框 class。这将中央小部件作为参数,并且该中央小部件将成为此自定义对话框的主要小部件。 (对于动态)
当它显示自己时,它会制作背景dark/dimmed。
可能我应该使用 exec_ 函数来防止在对话框区域之外点击。
重要的是将自己添加到主窗口的布局中,这样当主窗口的size/position发生变化时,它可以自动调整自己。
我可以通过挂钩来做到这一点 resizeEvent/moveEvent 但我正在寻找更好的方法来做到这一点。如果我将这个自定义对话框添加到主窗口的布局中,它会更好。
谢谢。
创建一个 child 在 window 的当前内容上 绘制并在 resizeEvent()
覆盖中调整大小的小部件绝对不是一个问题。事实上,每次使用布局管理器调整小部件的大小时,这实际上就是 Qt 所做的。这种做法的好处是可以完全“覆盖”window的所有内容,包括菜单栏、状态栏和任何dock/toolbar。
如果您仍然希望它们可用并且只想覆盖主要小部件,您可以通过将“覆盖”设置为主要小部件本身的 child 而不是使用window 作为 parent.
另一种方法是使用 QStackedWidget 作为中央小部件,并将布局(即 QStackedLayout)设置为使用 StackAll
stackingMode
,这将允许您显示所有“页”的堆叠布局叠加。
请注意,此方法有一个重要缺点:您必须 处理tab-focus。由于显示并启用了所有小部件(包括属于另一个“页面”的小部件),因此通过 Tab 更改焦点将允许将焦点更改为不属于“对话框”的小部件。
我会给你一个基本的例子,中央小部件是一个 QTableWidget,它会在双击项目时显示“弹出窗口”。
请仔细研究并尝试理解它的作用。
from PyQt5 import QtCore, QtWidgets
class Container(QtWidgets.QWidget):
def showEvent(self, event):
if not event.spontaneous():
self.setFocus()
# certain widgets might want to keep focus on tab
# so we delay the focusNextChild
QtCore.QTimer.singleShot(0, self.focusNextChild)
def focusNextPrevChild(self, isNext):
# keep tab focus on this widget
super().focusNextPrevChild(isNext)
return self.isAncestorOf(QtWidgets.QApplication.focusWidget())
def paintEvent(self, event):
# stylesheets set on QWidget subclasses need this
qp = QtWidgets.QStylePainter(self)
opt = QtWidgets.QStyleOption()
opt.initFrom(self)
qp.drawPrimitive(QtWidgets.QStyle.PE_Widget, opt)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.menuBar().addMenu('Test').addAction('Action')
self.stack = QtWidgets.QStackedWidget(self)
self.setCentralWidget(self.stack)
self.stack.layout().setStackingMode(QtWidgets.QStackedLayout.StackAll)
table = QtWidgets.QTableWidget(20, 30)
self.stack.addWidget(table)
table.cellDoubleClicked.connect(self.showDialog)
self.resize(QtWidgets.QApplication.primaryScreen().size() * 2 / 3)
def showDialog(self, row, column):
background = QtWidgets.QWidget(objectName='background')
background.setStyleSheet('''
#background {
background: rgba(64, 64, 64, 64);
}
Container {
background: palette(window);
border: 1px outset palette(window);
border-radius: 5px;
}
''')
backLayout = QtWidgets.QVBoxLayout(background)
container = Container()
backLayout.addWidget(container, alignment=QtCore.Qt.AlignCenter)
container.setAutoFillBackground(True)
layout = QtWidgets.QVBoxLayout(container)
layout.setContentsMargins(10, 10, 10, 10)
layout.setSpacing(20)
font = self.font()
font.setPointSize(font.pointSize() * 3)
layout.addWidget(QtWidgets.QLabel(
'Hello!', font=font, alignment=QtCore.Qt.AlignCenter))
layout.addWidget(QtWidgets.QLabel(
'You doubleclicked cell {}, {}'.format(row + 1, column + 1)))
button = QtWidgets.QPushButton('Close')
layout.addWidget(button)
self.centralWidget().addWidget(background)
self.centralWidget().setCurrentWidget(background)
# Important! you must always delete the widget when you don't need it
# anymore. Alternatively, hide it if you want to reuse it again later
button.clicked.connect(background.deleteLater)
app = QtWidgets.QApplication([])
win = MainWindow()
win.show()
app.exec()
我正在尝试创建动态自定义对话框 class。这将中央小部件作为参数,并且该中央小部件将成为此自定义对话框的主要小部件。 (对于动态)
当它显示自己时,它会制作背景dark/dimmed。 可能我应该使用 exec_ 函数来防止在对话框区域之外点击。
重要的是将自己添加到主窗口的布局中,这样当主窗口的size/position发生变化时,它可以自动调整自己。
我可以通过挂钩来做到这一点 resizeEvent/moveEvent 但我正在寻找更好的方法来做到这一点。如果我将这个自定义对话框添加到主窗口的布局中,它会更好。
谢谢。
创建一个 child 在 window 的当前内容上 绘制并在 resizeEvent()
覆盖中调整大小的小部件绝对不是一个问题。事实上,每次使用布局管理器调整小部件的大小时,这实际上就是 Qt 所做的。这种做法的好处是可以完全“覆盖”window的所有内容,包括菜单栏、状态栏和任何dock/toolbar。
如果您仍然希望它们可用并且只想覆盖主要小部件,您可以通过将“覆盖”设置为主要小部件本身的 child 而不是使用window 作为 parent.
另一种方法是使用 QStackedWidget 作为中央小部件,并将布局(即 QStackedLayout)设置为使用 StackAll
stackingMode
,这将允许您显示所有“页”的堆叠布局叠加。
请注意,此方法有一个重要缺点:您必须 处理tab-focus。由于显示并启用了所有小部件(包括属于另一个“页面”的小部件),因此通过 Tab 更改焦点将允许将焦点更改为不属于“对话框”的小部件。
我会给你一个基本的例子,中央小部件是一个 QTableWidget,它会在双击项目时显示“弹出窗口”。
请仔细研究并尝试理解它的作用。
from PyQt5 import QtCore, QtWidgets
class Container(QtWidgets.QWidget):
def showEvent(self, event):
if not event.spontaneous():
self.setFocus()
# certain widgets might want to keep focus on tab
# so we delay the focusNextChild
QtCore.QTimer.singleShot(0, self.focusNextChild)
def focusNextPrevChild(self, isNext):
# keep tab focus on this widget
super().focusNextPrevChild(isNext)
return self.isAncestorOf(QtWidgets.QApplication.focusWidget())
def paintEvent(self, event):
# stylesheets set on QWidget subclasses need this
qp = QtWidgets.QStylePainter(self)
opt = QtWidgets.QStyleOption()
opt.initFrom(self)
qp.drawPrimitive(QtWidgets.QStyle.PE_Widget, opt)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.menuBar().addMenu('Test').addAction('Action')
self.stack = QtWidgets.QStackedWidget(self)
self.setCentralWidget(self.stack)
self.stack.layout().setStackingMode(QtWidgets.QStackedLayout.StackAll)
table = QtWidgets.QTableWidget(20, 30)
self.stack.addWidget(table)
table.cellDoubleClicked.connect(self.showDialog)
self.resize(QtWidgets.QApplication.primaryScreen().size() * 2 / 3)
def showDialog(self, row, column):
background = QtWidgets.QWidget(objectName='background')
background.setStyleSheet('''
#background {
background: rgba(64, 64, 64, 64);
}
Container {
background: palette(window);
border: 1px outset palette(window);
border-radius: 5px;
}
''')
backLayout = QtWidgets.QVBoxLayout(background)
container = Container()
backLayout.addWidget(container, alignment=QtCore.Qt.AlignCenter)
container.setAutoFillBackground(True)
layout = QtWidgets.QVBoxLayout(container)
layout.setContentsMargins(10, 10, 10, 10)
layout.setSpacing(20)
font = self.font()
font.setPointSize(font.pointSize() * 3)
layout.addWidget(QtWidgets.QLabel(
'Hello!', font=font, alignment=QtCore.Qt.AlignCenter))
layout.addWidget(QtWidgets.QLabel(
'You doubleclicked cell {}, {}'.format(row + 1, column + 1)))
button = QtWidgets.QPushButton('Close')
layout.addWidget(button)
self.centralWidget().addWidget(background)
self.centralWidget().setCurrentWidget(background)
# Important! you must always delete the widget when you don't need it
# anymore. Alternatively, hide it if you want to reuse it again later
button.clicked.connect(background.deleteLater)
app = QtWidgets.QApplication([])
win = MainWindow()
win.show()
app.exec()