wxPython 设置为 Pulse() 时如何正确关闭 wxProgressDialog
wxPython How to correctly close wxProgressDialog when set to Pulse()
我最近将应用程序从 python2.7.15 (wx 3.0.2.0) 迁移到 python 3.7.9 (wx 4.1.1)
应用程序在等待某些任务完成时使用 wx.ProgressDialog 设置为 Pulse()
然后使用 Destroy() 尝试关闭 ProgressDialog window.
它在 Python27 上运行没有错误,但在 Python37 上崩溃了。
在两者中 ProgressDialog.Destroy() 实际上似乎并没有关闭对话框,但是当显示下一个 wx 元素时它会关闭。
import wx
from time import sleep
def main():
app = wx.App()
progress_dlg = wx.ProgressDialog("Model Manager", "Connecting...")
progress_dlg.Pulse()
sleep(5) # some long tasks are done here
progress_dlg.Destroy()
print("waiting")
sleep(5)
extracted_names = ["ONE", "TWO", "THREE"]
CANDialog = wx.SingleChoiceDialog(None, "Please select:", "Selection", extracted_names)
CANDialog.SetSelection(0)
if CANDialog.ShowModal() == wx.ID_OK:
choosen_can = CANDialog.GetSelection()
else:
return
print(extracted_names[choosen_can])
if __name__ == '__main__':
main()
在 python37 中出现以下错误:
if CANDialog.ShowModal() == wx.ID_OK:
wx._core.wxAssertionError: C++ assertion ""wxEventLoopBase::GetActive() == m_tempEventLoop"" failed at ..\..\src\generic\progdlgg.cpp(718) in wxGenericProgressDialog::~wxGenericProgressDialog(): current event loop must not be changed during wxGenericProgressDialog lifetime
如果我将 Destroy() 替换为 Update(),则对话框会自动正确关闭:
progress_dlg = wx.ProgressDialog("Model Manager", "Connecting...", maximum=1)
progress_dlg.Pulse()
sleep(5)
progress_dlg.Update(1)
虽然我可以解决我的问题,但我想了解这是否是正确的方法以及为什么 Destroy() 不起作用?
提前感谢您的任何建议。
Gabbo CH
我认为不应该在 ProgressDialog 上调用 Destroy。
具有最大值的 Update() 是正确的方法。 (默认样式为 PD_AUTO_HIDE。)
然后,删除对对话框的引用。最好的方法是使用上下文管理器。
如果您查看 wxPython 演示和 wxWidgets C++ 示例,就会发现没有 Show()、ShowModal() 或 Destroy()。
最近有一个wxPython的相关票证,我也添加了一个使用示例。
https://github.com/wxWidgets/Phoenix/issues/1610#issuecomment-1090664834
https://docs.wxwidgets.org/trunk/classwx_generic_progress_dialog.html
Dietmar 为您指明了正确的方向,我将专注于其他问题。
您的代码不会创建 wx MainLoop
并且您不允许在视觉上更新仪表。虽然您的代码在那个小代码示例中可能会异常运行,但稍后会在代码增加时出现问题。
这是您的代码,稍作更改。它包括设置 MainLoop 并在 long task
期间回退到该循环以允许进度表更新。
import wx
from time import sleep
def main():
progress_dlg = wx.ProgressDialog("Model Manager", "Connecting...", maximum=100)
for i in range(5):
progress_dlg.Pulse()
sleep(1) # some long tasks are done here
wx.GetApp().Yield()
progress_dlg.Update(100)
print("waiting")
wx.GetApp().Yield()
sleep(5)
extracted_names = ["ONE", "TWO", "THREE"]
CANDialog = wx.SingleChoiceDialog(None, "Please select:", "Selection", extracted_names)
CANDialog.SetSelection(0)
if CANDialog.ShowModal() == wx.ID_OK:
choosen_can = CANDialog.GetSelection()
else:
return
print(extracted_names[choosen_can])
if __name__ == '__main__':
app = wx.App()
main()
app.MainLoop()
我最近将应用程序从 python2.7.15 (wx 3.0.2.0) 迁移到 python 3.7.9 (wx 4.1.1)
应用程序在等待某些任务完成时使用 wx.ProgressDialog 设置为 Pulse() 然后使用 Destroy() 尝试关闭 ProgressDialog window.
它在 Python27 上运行没有错误,但在 Python37 上崩溃了。 在两者中 ProgressDialog.Destroy() 实际上似乎并没有关闭对话框,但是当显示下一个 wx 元素时它会关闭。
import wx
from time import sleep
def main():
app = wx.App()
progress_dlg = wx.ProgressDialog("Model Manager", "Connecting...")
progress_dlg.Pulse()
sleep(5) # some long tasks are done here
progress_dlg.Destroy()
print("waiting")
sleep(5)
extracted_names = ["ONE", "TWO", "THREE"]
CANDialog = wx.SingleChoiceDialog(None, "Please select:", "Selection", extracted_names)
CANDialog.SetSelection(0)
if CANDialog.ShowModal() == wx.ID_OK:
choosen_can = CANDialog.GetSelection()
else:
return
print(extracted_names[choosen_can])
if __name__ == '__main__':
main()
在 python37 中出现以下错误:
if CANDialog.ShowModal() == wx.ID_OK:
wx._core.wxAssertionError: C++ assertion ""wxEventLoopBase::GetActive() == m_tempEventLoop"" failed at ..\..\src\generic\progdlgg.cpp(718) in wxGenericProgressDialog::~wxGenericProgressDialog(): current event loop must not be changed during wxGenericProgressDialog lifetime
如果我将 Destroy() 替换为 Update(),则对话框会自动正确关闭:
progress_dlg = wx.ProgressDialog("Model Manager", "Connecting...", maximum=1)
progress_dlg.Pulse()
sleep(5)
progress_dlg.Update(1)
虽然我可以解决我的问题,但我想了解这是否是正确的方法以及为什么 Destroy() 不起作用?
提前感谢您的任何建议。
Gabbo CH
我认为不应该在 ProgressDialog 上调用 Destroy。 具有最大值的 Update() 是正确的方法。 (默认样式为 PD_AUTO_HIDE。) 然后,删除对对话框的引用。最好的方法是使用上下文管理器。
如果您查看 wxPython 演示和 wxWidgets C++ 示例,就会发现没有 Show()、ShowModal() 或 Destroy()。 最近有一个wxPython的相关票证,我也添加了一个使用示例。
https://github.com/wxWidgets/Phoenix/issues/1610#issuecomment-1090664834
https://docs.wxwidgets.org/trunk/classwx_generic_progress_dialog.html
Dietmar 为您指明了正确的方向,我将专注于其他问题。
您的代码不会创建 wx MainLoop
并且您不允许在视觉上更新仪表。虽然您的代码在那个小代码示例中可能会异常运行,但稍后会在代码增加时出现问题。
这是您的代码,稍作更改。它包括设置 MainLoop 并在 long task
期间回退到该循环以允许进度表更新。
import wx
from time import sleep
def main():
progress_dlg = wx.ProgressDialog("Model Manager", "Connecting...", maximum=100)
for i in range(5):
progress_dlg.Pulse()
sleep(1) # some long tasks are done here
wx.GetApp().Yield()
progress_dlg.Update(100)
print("waiting")
wx.GetApp().Yield()
sleep(5)
extracted_names = ["ONE", "TWO", "THREE"]
CANDialog = wx.SingleChoiceDialog(None, "Please select:", "Selection", extracted_names)
CANDialog.SetSelection(0)
if CANDialog.ShowModal() == wx.ID_OK:
choosen_can = CANDialog.GetSelection()
else:
return
print(extracted_names[choosen_can])
if __name__ == '__main__':
app = wx.App()
main()
app.MainLoop()