我的问题是,当我将QFileDialog添加到QVBoxLayout时,它会在新窗口中打开。下面是产生我的问题的代码。
from PyQt5.QtWidgets import QVBoxLayout, QFileDialog, QPushButton, QWidget
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My own MainWindow")
self.fileDialog = QFileDialog()
self.confirmAction = QPushButton("Press me", self)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.fileDialog)
mainLayout.addWidget(self.confirmAction)
self.setLayout(mainLayout)
根据docs:
窗口标志是窗口系统的类型(例如Qt :: Dialog)和零或多个提示的组合(例如Qt :: FramelessWindowHint)。
如果小部件具有类型Qt :: Widget或Qt :: SubWindow并且变成窗口(Qt :: Window,Qt :: Dialog等),则它被放置在桌面上的位置(0,0)。如果窗口小部件是一个窗口并且变为Qt :: Widget或Qt :: SubWindow,则它将相对于其父窗口小部件放置在位置(0,0)。
因此,这些标志用于改变窗口小部件的行为,例如将其转换为窗口,对话框,工具提示等。
在docs中给出以下列表:
Qt :: Widget:这是QWidget的默认类型。这种类型的小部件是子小部件(如果它们有父级),而独立窗口是没有父级的小部件。另请参见Qt :: Window和Qt :: SubWindow。
Qt :: Window:表示窗口小部件是一个窗口,通常带有窗口系统框架和标题栏,无论窗口小部件是否有父窗口。请注意,如果窗口小部件没有父标记,则无法取消设置此标记。
Qt :: Dialog:Window表示窗口小部件是一个应该被装饰为对话框的窗口(即,标题栏中通常没有最大化或最小化按钮)。这是QDialog的默认类型。如果要将其用作模式对话框,则应从另一个窗口启动它,或者使用父窗口并与QWidget :: windowModality属性一起使用。如果将其设置为模态,则对话框将阻止应用程序中的其他顶级窗口获取任何输入。我们引用一个顶级窗口,它将父级作为辅助窗口。
Qt :: Sheet:Window表示该窗口是Macintosh工作表。由于使用工作表意味着窗口模态,推荐的方法是使用QWidget :: setWindowModality()或QDialog :: open()。
Qt :: Drawer:Window表示小部件是Macintosh抽屉。
Qt :: Popup:Window表示窗口小部件是弹出的顶级窗口,即它是模态的,但具有适合弹出菜单的窗口系统框架。
Qt :: Tool:Window表示窗口小部件是工具窗口。工具窗口通常是一个小窗口,其标题栏和装饰比通常小,通常用于工具按钮的集合。如果有父项,则工具窗口将始终保持在其上。如果没有父级,您可以考虑使用Qt :: WindowStaysOnTopHint。如果窗户系统支持它,工具窗口可以用更轻的框架装饰。它也可以与Qt :: FramelessWindowHint结合使用。
在Mac OS X上,工具窗口对应于浮动类窗口。这意味着窗口生活在正常窗口之上;不可能在它上面放一个普通的窗口。默认情况下,当应用程序处于非活动状态时,工具窗口将消失。这可以通过Qt :: WA_MacAlwaysShowToolWindow属性来控制。
Qt :: ToolTip:Window表示窗口小部件是工具提示。这在内部用于实现工具提示。
Qt :: SplashScreen:窗口表示窗口是闪屏。这是QSplashScreen的默认类型。
Qt :: Desktop:Window表示此小部件是桌面。这是QDesktopWidget的类型。
Qt :: SubWindow:表示此窗口小部件是子窗口,例如QMdiSubWindow窗口小部件。
在你的情况下,我们必须将Qt::Dialog
的行为改为Qt::Widget
,在下面的代码中我展示了执行它的代码:
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("My own MainWindow")
self.fileDialog = QFileDialog(self)
self.fileDialog.setOption(QFileDialog.DontUseNativeDialog)
self.fileDialog.setWindowFlags(Qt.Widget)
self.confirmAction = QPushButton("Press me", self)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.fileDialog)
mainLayout.addWidget(self.confirmAction)
self.setLayout(mainLayout)
截图:
我自己一直在研究这个问题,不满意“只使用非原生对话”这一点。我一直在讨论KDE平台文件对话框实现,并且已经(卡住)非常接近我想要的东西。
我发现的唯一附着点就在实际显示对话框之前;在此之前,似乎无法知道实际的父窗口小部件。但我们可以:
毛刺: - 对话框最终可能会有2组OK / Cancel /等。按钮 - 如果没有,这些按钮实际上可能只关闭嵌入的QFD而不是封闭对话框(见上面链接的python示例) - 调整大小工作,但saveSize / restoreSize机制没有--AFAICT所有信号都没有正确连接( Scribus打开文件对话框中的预览不会对选择文件做出反应。文件打开确实有效。
这张BKO门票上有完整补丁:https://bugs.kde.org/show_bug.cgi?id=404833#c15
显然,这只适用于可以发布自己的平台主题插件的黑客和软件(这是KDE平台文件对话框的来源)。幸运的是,这些插件往往相对较小。