微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

wxPython 应用程序没有响应

如何解决wxPython 应用程序没有响应

我有一个复杂的应用程序,它的 GUI 需要与一些 I/O 设备和一些 WebAPI 进行对话。我把我的 wx.Frame 类放在主文件中,因为我读到 GUI 应该在主线程中以避免冻结

if __name__ == "__main__":
    app = wx.App()
    frame = Window()
    app.MainLoop()

但 GUI 仍然经常冻结,有时它根本不显示,并且会出现一条消息“My_app 没有响应”。 所有 I/O 和 webAPI 管理都在由 frame 创建的单独线程中完成。唯一不在主文件中的 GUI 元素是组成我的笔记本的页面

from PageOne import PageOne
from PageTwo import PageTwo
from PageThree import PageThree

...

self.page1 = PageOne(self.nb)
self.page2 = PageTwo(self.nb)
self.page3 = PageThree(self.nb)

self.nb.AddPage(self.page1,"Page1")
self.nb.AddPage(self.page2,"Page2")
self.nb.AddPage(self.page3,"Page3")

辅助线程和 GUI 之间的所有通信都使用主文件中的 wx.lib.newevent.NewEvent() 和线程中的 wx.PostEvent(self.parent,my_evt) 完成。

我使用的是 wxpython 4.1.1 和 Ubuntu 20.04.2 LTS。

关于如何防止 GUI 不响应或冻结的任何建议?使用多处理而不是多线程可能是更好的主意吗?我知道线程通常更适合 I/O 应用程序......但在我的线程都是无循环的情况下仍然如此吗?

def run(self):
    while True:
        do_stuff()

解决方法

这本身不是答案。
但是,它可能有助于找到解决方案。
鉴于我们不知道 none,您的代码在做什么,没有人可以回答这样的问题。
这相当于问,How long is a piece of string?

最好的建议是使用类似下面的代码,调整 thread 以执行类似于您的一个/多个线程正在执行的操作,并查看您是否可以复制该行为并希望找到原因。

>
import time
import wx
from threading import Thread

import wx.lib.newevent
progress_event,EVT_PROGRESS_EVENT = wx.lib.newevent.NewEvent()

class ThreadFrame(wx.Frame):

    def __init__(self,title,parent=None):
        wx.Frame.__init__(self,parent=parent,title=title)
        panel = wx.Panel(self)
        self.btn = wx.Button(panel,label='Stop Long running process',size=(200,30),pos=(10,10))
        self.btn.Bind(wx.EVT_BUTTON,self.OnExit)
        self.progress = wx.Gauge(panel,size=(240,10),50),range=240)

        #Bind to the progress event issued by the thread
        self.Bind(EVT_PROGRESS_EVENT,self.OnProgress)
        #Bind to Exit on frame close
        self.Bind(wx.EVT_CLOSE,self.OnExit)
        self.Show()

        self.mythread = TestThread(self)
        #Enable the GUI to be responsive by briefly returning control to the main App
        while self.mythread.isAlive():
            time.sleep(0.1)
            wx.GetApp().Yield()
            continue

        try:
            self.OnExit(None)
        except:
            pass

    def OnProgress(self,event):
        self.progress.SetValue(event.count)
        #or for indeterminate progress
        #self.progress.Pulse()

    def OnExit(self,event):
        if self.mythread.isAlive():
            self.mythread.terminate() # Shutdown the thread
            self.mythread.join() # Wait for it to finish
        self.Destroy()

class TestThread(Thread):
    def __init__(self,parent_target):
        Thread.__init__(self)
        self.parent = parent_target
        self.stopthread = False
        self.time = time.time()
        self.start()    # start the thread

    def run(self):
        # A loop that will run for 2 minutes then terminate
        while self.stopthread == False:
            curr_loop = int(time.time() - self.time)
            if curr_loop < 240:
                time.sleep(0.1)
                evt = progress_event(count=curr_loop)
                #Send back current count for the progress bar
                try:
                    wx.PostEvent(self.parent,evt)
                except: # The parent frame has probably been destroyed
                    self.terminate()
            else:
                self.terminate()

    def terminate(self):
        self.stopthread = True

class MyPanel(wx.Panel):

    def __init__(self,parent):
        wx.Panel.__init__(self,parent)
        self.text_count = 0
        self.thread_count = 0
        self.parent=parent
        btn = wx.Button(self,wx.ID_ANY,label='Start Long running process',10))
        btn.Bind(wx.EVT_BUTTON,self.Thread_Frame)
        btn2 = wx.Button(self,label='Is the GUI still active?',50))
        btn2.Bind(wx.EVT_BUTTON,self.AddText)
        self.txt = wx.TextCtrl(self,style= wx.TE_MULTILINE,90),size=(400,100))

    def Thread_Frame(self,event):
        self.thread_count += 1
        frame = ThreadFrame(title='Threaded Task '+str(self.thread_count),parent=self.parent)

    def AddText(self,event):
        self.text_count += 1
        txt = "Gui is still active " + str(self.text_count)+"\n"
        self.txt.write(txt)

class MainFrame(wx.Frame):

    def __init__(self):
        wx.Frame.__init__(self,None,title='Main Frame',size=(600,400))
        panel = MyPanel(self)
        self.Show()


if __name__ == '__main__':
    app = wx.App(False)
    frame = MainFrame()
    app.MainLoop()

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。