代码之家  ›  专栏  ›  技术社区  ›  mike rodent

“此插件不支持propagateSizeHints()”/在QDialog子类上调用`exec`

  •  0
  • mike rodent  · 技术社区  · 3 年前

    NB OS是 W10 .

    这里的上下文是pytest qt。我发现 this answer 并尝试使用它(见下文)。

    当测试方法调用创建 QFileDialog 然后打电话 exec 然后控制台发出此消息,控制台将挂起。我别无选择,只能手动关闭控制台。

    此处涉及的一个因素是此设置(在运行测试之前的测试期间设置):

    os.environ['QT_QPA_PLATFORM'] = 'offscreen'
    

    …没有这条线 QFileDialog 显示OK on exec ,测试结束,控制台不会挂起。

    我当然不知道哪个插件是罪魁祸首…在谷歌上搜索了“propagateSizeHints”后,什么都没有出现。 pip freeze 输出如下:

    atomicwrites==1.4.0
    attrs==21.2.0
    colorama==0.4.4
    coloredlogs==15.0.1
    concurrent-log-handler==0.9.19
    humanfriendly==10.0
    iniconfig==1.1.1
    packaging==21.2
    pluggy==1.0.0
    portalocker==2.3.2
    py==1.11.0
    pyparsing==2.4.7
    PyQt5==5.15.6
    PyQt5-Qt5==5.15.2
    PyQt5-sip==12.9.0
    pyreadline3==3.3
    pytest==6.2.5
    pytest-qt==4.0.2
    pywin32==302
    toml==0.10.2
    

    搜索了的问题 exec 我找到了eyllanesc的上述答案。所以我试了一下:

    def test_file_dialog_should_do_x(request, qtbot):
        t_logger.info(f'\n>>>>>> test name: {request.node.originalname}')
        main_win = main_window.AutoTransMainWindow() 
        proj = project.Project(main_win)
        def on_timeout():
            proj.modify_working_files()
            print('A1')
            assert proj.file_dlg.windowTitle() == 'Nonsense'
            print('A2')
        print('A3')
        QtCore.QTimer.singleShot(0, on_timeout)
        print('A4')
        assert proj.file_dlg.windowTitle() == 'Nonsense'
    

    (这些断言注定要失败)

    应用程序代码尽可能简单:

    def modify_working_files(self):
        self.file_dlg = QtWidgets.QFileDialog()
        self.file_dlg.exec()
    

    …但我再次收到相同的“This plugin not…”消息,控制台再次挂起。只有“A3”和“A4”被打印出来。

    一个解决方案可能只是模拟 exec 普遍地。但是eyllanesc知道他的洋葱,如果是这样的话,他大概会这么说的。如果是这样的话,我不知道怎么可能通过 qtbot .

    到目前为止,我对“屏幕外”设置没有任何问题。但也许有局限性。。。 this post 似乎表明这可能是问题的根源。

    MRE:

    import os
    
    from PyQt5 import QtWidgets, QtCore, QtGui
    
    os.environ['QT_QPA_PLATFORM'] = 'offscreen'
    
    QtWidgets.QApplication([])
    
    class MainWin(QtWidgets.QMainWindow):
        pass
    
    class Project():
        def __init__(self, main_win):
            self.main_win = main_win
            
        def modify_working_files(self):
            self.file_dlg = QtWidgets.QFileDialog()
            self.file_dlg.exec()        
            
            
    def test_file_dialog_should_do_x(request, qtbot):
        print(f'\n>>>>>> test name: {request.node.originalname}')
        
        main_win = MainWin() 
        proj = Project(main_win)
        def on_timeout():
            proj.modify_working_files()
            print('A1')
            assert proj.file_dlg.windowTitle() == 'Nonsense'
            print('A2')
        print('A3')
        QtCore.QTimer.singleShot(0, on_timeout)
        print('A4')
        assert proj.file_dlg.windowTitle() == 'Nonsense'
    

    在我的机器上,这会(如预期的那样)在功能中的行上产生FAIL on_timeout 如果QT_QPA_平台行被注释掉。

    如果后者没有被注释掉,我会收到插件错误消息,控制台会挂起。

    即使 MainWin 被制作为 show() 在其构造函数中,即使 QFileDialog 创建时使用 QtWidgets.QFileDialog(self.main_win) ,错误仍然会发生。

    我也试过 class Project(object) 甚至(长镜头) class Project(QtCore.QObject) 。没有快乐。

    注意:我还在我的虚拟环境中的所有文件和我的核心Python安装(v.3.9.4)的所有文件中搜索字符串“propagatesize”。没有什么

    0 回复  |  直到 3 年前
        1
  •  1
  •   mike rodent    3 年前

    此消息的来源似乎是 here :

    void QPlatformWindow::propagateSizeHints() {qWarning("This plugin does not support propagateSizeHints()"); }
    

    因此,它是关于在Windows平台上使用PyQt5(或Qt5)。从我的实验中可以看出,这是一种症状,但不是所指出的失败的原因。不幸地 this page ,旨在列出“所有Qt5类”(不仅仅是PyQt5),但不包括它。

    从…起 here ,可以通过将此消息放在所有测试文件导入的文件中来抑制此特定消息:

    def qt_message_handler(mode, context, message):
        if mode == QtCore.QtInfoMsg:
            mode = 'INFO'
        elif mode == QtCore.QtWarningMsg:
            mode = 'WARNING'
            if 'propagateSizeHints' in message:
                return
        elif mode == QtCore.QtCriticalMsg:
            mode = 'CRITICAL'
        elif mode == QtCore.QtFatalMsg:
            mode = 'FATAL'
        else:
            mode = 'DEBUG'
        print('qt_message_handler: line: %d, func: %s(), file: %s' % (
              context.line, context.function, context.file))
        print('  %s: %s\n' % (mode, message))
    
    QtCore.qInstallMessageHandler(qt_message_handler)
    

    克服的问题 exec ,以下是一种变通方法。我从Qt5文档中注意到:

    QDialog.exec()

    注意:避免使用此功能;相反,请使用open()。与exec()不同, open()是异步的,不会旋转额外的事件循环。 这可以防止一系列危险的错误发生(例如删除 对话框的父级,而对话框是通过exec()打开的)。使用时 open()可以连接到QDialog的finished()信号 对话框关闭时通知。

    换言之,我仍然收到消息“此插件不支持propagateSizeHints()”。。。但是控制台没有挂起。

    exec() 返回 int 值,但是 open 没有。这是一个小小的代价。

    但是。。。事实上,在我的机器上, 打开 总是导致非模态对话框,即使我 setModal(True) (在它之前)。

    幸运地 show() 荣誉 setModal(...) …并且不会导致控制台崩溃。似乎是一个使用。