【问题标题】:tkinter freezing with pywinauto importtkinter 冻结与 pywinauto 导入
【发布时间】:2020-06-16 11:08:40
【问题描述】:

问题:
当我单击运行的按钮时,我的 python gui (tkinter) 冻结:
filename = filedialog.askdirectory()
当我在另一个脚本中有from pywinauto import application 时,这只发生。如果我注释掉 pywinauto 导入,askdirectory 工作得很好。没有冻结,窗口按预期弹出。发生这种情况时,我没有看到任何错误。

抱歉,顺便说一句,我想提供尽可能多的细节。让我知道是否需要更多以及您在寻找什么。理想情况下,我希望使用 askdirectory,但我认为我可以只使用 askopenfilename 并从中获取目录。

Python 版本:
Python 3.4.4

Windows 版本:
Windows Server 2012 R2(无法更改)

我尝试过的事情:
1. 通过教程进行基本线程处理(每次仍然卡住,代码示例在底部)
2. 注释掉代码部分以缩小问题范围。
3. 尝试使用 PyCharms 调试器,但如果出现错误,我没有看到它。
4.不同的IDE。

  • 空闲 = 失败
  • Pycharm = fail(据我所知,与空闲相同的解释器,所以不足为奇)
  • Pythonwin = 工作正常)

  • 以下代码块:
    如果你愿意的话,我已经按照它们如何交互的顺序将代码块放在下面。它从第一个开始,然后到第二个(中间),最后到第三个。

    问题:
    有没有办法让我检查错误? 我在这里做错了什么导致这种情况发生吗? 为什么 askopenfilename 可以正常工作,但 askdirectory 不行?

    包含冻结窗口的文件:

    from InstallMenu import MainMenu
    from tkinter import *
    from tkinter import filedialog
    
    """
    This is where it freezes.  If I change askdirectory to openaskfilename it 
    works without any issues.  If I comment out the from pywinauto import 
    application from opusite.py, askdirectory works without issue.
    """
    def chooseInstallFolder(installFolderPath):
        filename = filedialog.askdirectory()
        installFolderPath.config(text=filename)
    
    def submitFolder(installFolderApp, installFolderPath, setObj):
        installFolderApp.destroy()
        MainMenu(installFolderPath, setObj)
    
    def chooseInstall(setObj):
        installFolderApp = Tk()
        installFolderApp.title("Find Install Folder")
        installFolderApp.geometry("300x200")
    
        #Gui items
        pickAFolder = Label(installFolderApp, text = "Select your Install Folder")
        pickInstallerButton = Button(installFolderApp, text="Browse", command = lambda : chooseInstallFolder(installFolderPath))
        installFolderPath = Label(installFolderApp, text = " ")
        submit = Button(installFolderApp, text="Submit", command = lambda : submitFolder(installFolderApp, installFolderPath, setObj))
    
        #Packing
        pickAFolder.pack()
        installFolderPath.pack()
        pickInstallerButton.pack()
        submit.pack()
    
        installFolderApp.mainloop()
    

    上面的提交按钮转到的菜单脚本:
    我已将 iParcPro 注释掉,因为它使用相同的导入导致冻结。

    import opusite
    #from iParcPro import *
    from Sql import *
    from tkinter import *
    
    def OPUSiteInstall(installFolderPath):
        opusite.OPUSiteInstall(installFolderPath, setObj)
        opusite.rs485Install(installFolderPath, setObj)
    
    def MainMenu(installFolderPath, setObj):
        menuWindow = Tk()
        menuWindow.title("Auto Installer Menu")
        menuWindow.geometry("325x250")
    
        #Create variables
        ChooseAButton = Label(menuWindow, text = "Choose an option")
    
        OPUSiteButton = Button(menuWindow, text="OPUSite Install", height = 1, 
        width 
        = 15, command = lambda : OPUSiteInstall(installFolderPath, setObj))
    
        #Pack
        ChooseAButton.pack()
        OPUSiteButton.pack()
    
        menuWindow.mainloop()
    

    包含似乎冻结此导入的代码:

    import pyautogui as ag
    """
    This import here freezes it.  If I comment out just the import, the 
    askdirectory works fine.
    """
    from pywinauto import application
    
    def OPUSiteInstall(installFolderPath, setObj):
        path = installFolderPath + '\\OPUSite\\AMI.OPUSite.Setup.msi'
        app = application.Application().Start(r'msiexec.exe /i ' + path)
        Wizard = app['OPUSite Setup']
        Wizard.NextButton.Wait('enabled', 50000)
        Wizard.NextButton.Click()
        Wizard['I &accept the terms in the License 
        Agreement'].Wait('enabled').CheckByClick()
        Wizard.NextButton.Click()
        Wizard.NextButton.Click()
        ag.typewrite(setObj.databaseName)
        ag.press('tab')
        ag.press('space')
        ag.press('tab')
        ag.press('tab')
        ag.typewrite(setObj.password)
        ag.press('tab')
        ag.typewrite(setObj.password)
        ag.press('tab')
        ag.typewrite(setObj.password)
        Wizard.NextButton.Click()
        Wizard.Install.Click()
    
        Wizard.Finish.Wait('visible', 50000)
        Wizard.Finish.Click()
    
    def rs485Install(installFolderPath, setObj):
        path = installFolderPath + '\\OPUSite\\AMI.RS485AdapterSvc.Setup.msi'
        app = application.Application().Start(r'msiexec.exe /i ' + path)
        Wizard = app['RS485Adapter Setup']
        Wizard.NextButton.Wait('enabled', 50000)
        Wizard.NextButton.Click()
        Wizard['I &accept the terms in the License 
        Agreement'].Wait('enabled').CheckByClick()
        Wizard.NextButton.Click()
        Wizard.NextButton.Click()
        Wizard.Install.Click()
    
        Wizard.Finish.Wait('visible', 50000)
        Wizard.Finish.Click()
    

    这是我尝试过的线程。它不起作用:

    from InstallMenu import MainMenu
    from tkinter import *
    from tkinter import filedialog
    import threading
    
    def chooseInstallFolder(installFolderPath):
        def callback(installFolderPath):
            filename = filedialog.askdirectory()
            installFolderPath.config(text=filename)
        t = threading.Thread(target=callback, args=(installFolderPath,))
        t.start()
    
    def submitFolder(installFolderApp, installFolderPath, setObj):
        installFolderApp.destroy()
        MainMenu(installFolderPath, setObj)
    
    def chooseInstall(setObj):
        installFolderApp = Tk()
        installFolderApp.title("Find Install Folder")
        installFolderApp.geometry("300x200")
    
        #Gui items
        pickAFolder = Label(installFolderApp, text = "Select your Install 
        Folder")
        pickInstallerButton = Button(installFolderApp, text="Browse", command = 
        lambda : chooseInstallFolder(installFolderPath))
        installFolderPath = Label(installFolderApp, text = " ")
        submit = Button(installFolderApp, text="Submit", command = lambda : 
        submitFolder(installFolderApp, installFolderPath, setObj))
    
        #Packing
        pickAFolder.pack()
        installFolderPath.pack()
        pickInstallerButton.pack()
        submit.pack()
    
        installFolderApp.mainloop()
    

    【问题讨论】:

    • from pywinauto import Application 之前尝试import sys; sys.coinit_flags = 0。它允许使用comtypes 包对 COM 对象进行多线程处理。
    • 我之前添加了您的建议,所以现在看起来是这样。 import pyautogui as ag import sys; sys.coinit_flags = 0 from pywinauto import application 我的 chooseInstallFolder 设置类似于我原来帖子中的线程示例。我仍然遇到同样的冻结问题。
    • 好的,这可能是基本的线程问题,因为 Python 是单线程的,线程按时间分开运行。在 Python 3.5+ 中使用新的 async/await 语法可以实现真正的并行线程。

    标签: python-3.x tkinter freeze pywinauto


    【解决方案1】:

    我能够解决这个问题。我想指出,我仍然不确定为什么会这样。我所做的只是将 pywinauto 导入到我的函数中,现在 askdirectory 工作正常。

    import pyautogui as ag
    
    def OPUSiteInstall(installFolderPath, setObj):
        from pywinauto import application
        path = installFolderPath + '\\OPUSite\\AMI.OPUSite.Setup.msi'
        app = application.Application().Start(r'msiexec.exe /i ' + path)
        Wizard = app['OPUSite Setup']
        Wizard.NextButton.Wait('enabled', 50000)
        Wizard.NextButton.Click()
        Wizard['I &accept the terms in the License 
        Agreement'].Wait('enabled').CheckByClick()
        Wizard.NextButton.Click()
        Wizard.NextButton.Click()
        ag.typewrite(setObj.databaseName)
        ag.press('tab')
        ag.press('space')
        ag.press('tab')
        ag.press('tab')
        ag.typewrite(setObj.password)
        ag.press('tab')
        ag.typewrite(setObj.password)
        ag.press('tab')
        ag.typewrite(setObj.password)
        Wizard.NextButton.Click()
        Wizard.Install.Click()
    
        Wizard.Finish.Wait('visible', 50000)
        Wizard.Finish.Click()
    
    def rs485Install(installFolderPath, setObj):
        from pywinauto import application
        path = installFolderPath + '\\OPUSite\\AMI.RS485AdapterSvc.Setup.msi'
        app = application.Application().Start(r'msiexec.exe /i ' + path)
        Wizard = app['RS485Adapter Setup']
        Wizard.NextButton.Wait('enabled', 50000)
        Wizard.NextButton.Click()
        Wizard['I &accept the terms in the License 
        Agreement'].Wait('enabled').CheckByClick()
        Wizard.NextButton.Click()
        Wizard.NextButton.Click()
        Wizard.Install.Click()
    
        Wizard.Finish.Wait('visible', 50000)
        Wizard.Finish.Click()
    `
    

    【讨论】:

      【解决方案2】:

      遇到同样的问题,在下面找到解决方案

      https://github.com/pywinauto/pywinauto/issues/517 https://pywinauto.readthedocs.io/en/latest/HowTo.html#com-threading-model

      import sys
      sys.coinit_flags = 2  # COINIT_APARTMENTTHREADED
      import pywinauto
      

      【讨论】:

        猜你喜欢
        • 2020-09-13
        • 2015-04-08
        • 1970-01-01
        • 1970-01-01
        • 2021-06-24
        • 1970-01-01
        • 1970-01-01
        • 2019-12-16
        • 2021-07-04
        相关资源
        最近更新 更多