首页 > 解决方案 > 在 PyQt5(Python)中将小部件(QCheckBox)添加到 QFileDialog 不起作用

问题描述

我想将 QCheckBox 添加到 QFileDialog。我想使用静态方法 QFileDialog.getSaveFileName() 来显示对话框。

我发现了几个类似的问题,都在 c++ 中:

  1. 如何在 QT3 的 QFileDialog 窗口中添加复选框?
  2. 在 QFileDialog 中添加一个小部件
  3. https://www.qtcentre.org/threads/42858-Creating-a-Custom-FileOpen-Dialog
  4. https://forum.qt.io/topic/103964/add-checkbox-to-qfiledialog/7

我尽力将这些讨论翻译成 python,但还没有找到解决方案。我的代码运行,但复选框没有显示,即使我使用 QFileDialog.DontUseNativeDialog。

这就是我继承 QFileDialog 的方式:

from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QCheckBox

class ChkBxFileDialog(QFileDialog):
    def __init__(self, chkBxTitle=""):
        super().__init__()
        self.setOption(QFileDialog.DontUseNativeDialog)
        chkBx = QCheckBox(chkBxTitle)
        self.layout().addWidget(chkBx)
    #end __init__
#end ChkBxFileDialog

我以两种方式运行它。

选项 1(带有额外的 QFileDialog.DontUseNativeDialog):

import sys    
from PyQt5.QtWidgets import QApplication
if __name__ == "__main__":
        app = QApplication(sys.argv)
        fileDialog = ChkBxFileDialog(chkBxTitle="Chkbx")
        fileName = fileDialog.getSaveFileName(filter='*.txt', initialFilter='*.txt',
                                              options=QFileDialog.DontUseNativeDialog)[0]
        sys.exit(app.exec_())

选项 2(没有额外的 QFileDialog.DontUseNativeDialog):

import sys    
from PyQt5.QtWidgets import QApplication    
if __name__ == "__main__":
        app = QApplication(sys.argv)
        fileDialog = ChkBxFileDialog(chkBxTitle="Chkbx")
        fileName = fileDialog.getSaveFileName(filter='*.txt', initialFilter='*.txt')[0]
        sys.exit(app.exec_())

该复选框不会与任一选项一起显示。选项 1 使用不同的窗口样式。选项 2 显示了典型的 PyQt QFileDialog。

有谁知道我错过了什么?

标签: pythonpyqtpyqt5qfiledialog

解决方案


问题是 getSaveFileName 是一个静态方法,因此它们不从 ChkBxFileDialog 继承,因此没有自定义行为。

有2个选项:

  • 不要使用 getSaveFileName 而是直接使用 QFileDialog 实现逻辑:

    import sys
    
    from PyQt5.QtWidgets import QApplication, QCheckBox, QDialog, QFileDialog
    
    
    class ChkBxFileDialog(QFileDialog):
        def __init__(self, chkBxTitle="", filter="*.txt"):
            super().__init__(filter=filter)
            self.setSupportedSchemes(["file"])
            self.setOption(QFileDialog.DontUseNativeDialog)
            self.setAcceptMode(QFileDialog.AcceptSave)
            self.selectNameFilter("*.txt")
            chkBx = QCheckBox(chkBxTitle)
            self.layout().addWidget(chkBx)
    
    
    def main():
        app = QApplication(sys.argv)
        dialog = ChkBxFileDialog()
        if dialog.exec_() == QDialog.Accepted:
            filename = dialog.selectedUrls()[0].toLocalFile()
            print(filename)
    
    
    if __name__ == "__main__":
        main()
    
  • 使用一些技巧来获取 QFileDialog 实例,例如获取所有 topLevels 并验证它是否是 QFileDialog。

    import sys
    from functools import partial
    
    from PyQt5.QtCore import QTimer
    from PyQt5.QtWidgets import QApplication, QCheckBox, QDialog, QFileDialog
    
    
    def add_checkbox(chkBxTitle):
        for tl in QApplication.topLevelWidgets():
            if isinstance(tl, QFileDialog):
                tl.setOption(QFileDialog.DontUseNativeDialog)
                chkBx = QCheckBox(chkBxTitle)
                tl.layout().addWidget(chkBx)
    
    
    def main():
        app = QApplication(sys.argv)
    
        QTimer.singleShot(1000, partial(add_checkbox, ""))
        fileName, _ = QFileDialog.getSaveFileName(
            filter="*.txt", initialFilter="*.txt", options=QFileDialog.DontUseNativeDialog
        )
    
    
    if __name__ == "__main__":
        main()
    

推荐阅读