如何稳定我的wx.Gauge的速度

问题描述 投票:0回答:3

我的量规的速度根据与它一起运行的线程的指示而变化。当说明很简单时,我的仪表速度很快,但是当需要读取文件时,我的仪表速度很慢。我想以同样的速度稳定下来。更糟的是,当您必须从图像文件中提取文本时,仪表会崩溃。并植入GUI

wx.Gauge(self, -1, 20, pos=(150, 300), size=(250, 25), style = wx.GA_HORIZONTAL)

我已经用更大的值(Range)更改了now Range=20,但什么也没有

wxpython python-3.5 wxpython-phoenix
3个回答
0
投票

此仪表与读取文件的线程一起运行。当您必须读取Txt文件时,仪表会快速运行,但是当您必须读取Docx时,仪表的速度会变慢,当您必须读取图像文本时仪表会导致GUI崩溃。我想避免GUI崩溃。如果可能,请稳定仪表的速度。

import time
import datetime
class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.gspeed = 20
        self.timer = wx.Timer(self)
        self.timer.Start(self.gspeed)

        self.star = True
        self.start_time = time.time()

        self.InitUI()

    def InitUI(self):

        pnl = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        hbox3 = wx.BoxSizer(wx.HORIZONTAL)


        self.btn2 = wx.Button(pnl, wx.ID_STOP)
        self.text = wx.StaticText(pnl)
        self.count = wx.StaticText(pnl)

        self.Bind(wx.EVT_BUTTON, self.OnStop, self.btn2)
        self.gauge = wx.Gauge(pnl,20, size=(250, -1), style = wx.GA_HORIZONTAL)
        hbox1.Add(self.gauge, proportion=1, flag=wx.ALIGN_CENTRE)

        hbox2.Add(self.btn2, proportion=1)
        hbox3.Add(self.text, proportion=1, flag=wx.RIGHT, border=50)
        hbox3.Add(self.count, proportion=1)

        vbox.Add((0, 30))

        vbox.Add(hbox1, flag=wx.ALIGN_CENTRE)

        vbox.Add((0, 20))

        vbox.Add(hbox2, proportion=1, flag=wx.ALIGN_CENTRE)
        vbox.Add(hbox3, proportion=1, flag=wx.ALIGN_CENTRE)

        pnl.SetSizer(vbox)

        self.SetTitle('Gauge')
        self.Centre()


    def OnStop(self, e):

        self.timer.Stop()
        self.text.SetLabel('Task Interrupted')

    def OnTimer(self, e):

        self.gauge.Pulse()
        self.SetTimeLabel()

    def get_elapsed_time(self):
        val = round(time.time() - self.start_time, 1)
        hours = val/3600
        minutes = (val%3600)/60
        seconds = val%60
        strs = ("%lu:%02lu:%02lu")%(hours, minutes, seconds)

        return strs

    def SetTimeLabel(self):

        self.text.SetLabel("{elapsed} seconds elapsed".format(elapsed=self.get_elapsed_time()))


def main():

    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()


0
投票

您的示例没有包含任何显示您如何读取文件的内容,但是我将基于对问题的描述,假定它们是从主线程调用的。关于如何以及为什么需要从另一个线程运行阻止功能以保持UI响应的很多examples。如果从主线程运行一个函数,它将阻止事件循环,这意味着直到该函数完成之前,不会调用任何常规事件(例如EVT_TIMER)。这是您的示例,该示例在其自己的线程中模拟了长期运行的任务。

import time
import datetime
import wx
import threading


class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw)

        self.Bind(wx.EVT_TIMER, self.OnTimer)
        self.gspeed = 20
        self.timer = wx.Timer(self)
        self.timer.Start(self.gspeed)

        self.star = True
        self.start_time = time.time()
        self.thread = None

        self.InitUI()
        self.start_long_running_task()


    def start_long_running_task(self):
        """
        :return: starts the long running task in its own thread to keep the UI responsive
        :rtype:
        """
        self.thread = threading.Thread(target=self.long_running_task)
        self.thread.start()

    def long_running_task(self):
        """
        :return:  simulated long running task
        :rtype:
        """
        print("long running task has started")
        # checks if the window has been closed and if the timer is still running
        while bool(self) and self.timer.IsRunning():
            # do something
            time.sleep(1)
        # the timer was stopped or the window was closed
        print("long running task is exiting")

    def InitUI(self):
        pnl = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        hbox3 = wx.BoxSizer(wx.HORIZONTAL)

        self.btn2 = wx.Button(pnl, wx.ID_STOP)
        self.text = wx.StaticText(pnl)
        self.count = wx.StaticText(pnl)

        self.Bind(wx.EVT_BUTTON, self.OnStop, self.btn2)
        self.gauge = wx.Gauge(pnl, 20, size=(250, -1), style=wx.GA_HORIZONTAL)
        hbox1.Add(self.gauge, proportion=1, flag=wx.ALIGN_CENTRE)

        hbox2.Add(self.btn2, proportion=1)
        hbox3.Add(self.text, proportion=1, flag=wx.RIGHT, border=50)
        hbox3.Add(self.count, proportion=1)

        vbox.Add((0, 30))

        vbox.Add(hbox1, flag=wx.ALIGN_CENTRE)

        vbox.Add((0, 20))

        vbox.Add(hbox2, proportion=1, flag=wx.ALIGN_CENTRE)
        vbox.Add(hbox3, proportion=1, flag=wx.ALIGN_CENTRE)

        pnl.SetSizer(vbox)

        self.SetTitle('Gauge')
        self.Centre()

    def OnStop(self, e):
        self.timer.Stop()
        self.text.SetLabel('Task Interrupted')

    def OnTimer(self, e):
        self.gauge.Pulse()
        self.SetTimeLabel()

    def get_elapsed_time(self):
        val = round(time.time() - self.start_time, 1)
        hours = val / 3600
        minutes = (val % 3600) / 60
        seconds = val % 60
        strs = ("%lu:%02lu:%02lu") % (hours, minutes, seconds)

        return strs

    def SetTimeLabel(self):
        self.text.SetLabel("{elapsed} seconds elapsed".format(elapsed=self.get_elapsed_time()))


def main():
    app = wx.App()
    ex = Example(None)
    ex.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

0
投票

这是一个基于我在评论中建议的代码的示例。“开始/停止”按钮将开始或停止文件加载。Other task按钮只是打印textctrl框的内容,以证明程序没有被文件加载线程锁定。

import wx
import time
from threading import Thread
import wx.lib.newevent
progress_event, EVT_PROGRESS_EVENT = wx.lib.newevent.NewEvent()
load_status=["File Loading","File Loaded","Cancelled"]

class Model(Thread):
    def __init__(self,parent):
        Thread.__init__(self)
        self.stopthread = 0
        self.target = parent
        #self.start()

    def run(self):
        line_counter = 0
        with open('../xxx.html', 'r') as f:
            while not self.stopthread:
                    line = f.readline()
                    if not line:
                        break
                    line_counter += 1
                    print(line_counter)
                    if self.stopthread:
                        break
                    time.sleep(0.05)
                    evt = progress_event(count=line_counter, status=self.stopthread)
                    wx.PostEvent(self.target, evt)
            if self.stopthread == 0:
                self.stopthread = 1
        evt = progress_event(count=line_counter, status=self.stopthread)
        wx.PostEvent(self.target, evt)

    def terminate(self):
        self.stopthread = 2

class View(wx.Frame):
    def __init__(self, parent, title):
        super(View, self).__init__(parent, title=title, size=(400, 400))
        self.InitUI()

    def InitUI(self):
        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.fgs = wx.FlexGridSizer(6, 2, 10, 25)
        id = wx.StaticText(self, label="ID:")
        firstName = wx.StaticText(self, label="First name:")
        lastName = wx.StaticText(self, label="Last name:")
        self.id = wx.TextCtrl(self)
        self.firstName = wx.TextCtrl(self)
        self.lastName = wx.TextCtrl(self)
        self.stop = wx.Button(self, -1, "Start")
        self.other = wx.Button(self, -1, "Other task")

        self.fgs.AddMany([id, (self.id, 1, wx.EXPAND),
                         firstName, (self.firstName, 1, wx.EXPAND),
                         lastName, (self.lastName, 1, wx.EXPAND),
                         (self.stop,1,wx.EXPAND),
                         (self.other,1,wx.EXPAND)])

        self.vbox.Add(self.fgs, proportion=1, flag=wx.ALL | wx.EXPAND,border=15)
        #Bind to the progress event issued by the thread
        self.Bind(EVT_PROGRESS_EVENT, self.OnProgress)
        #Bind to Stop button
        self.stop.Bind(wx.EVT_BUTTON, self.OnStartStop)
        #Bind to Other task button
        self.other.Bind(wx.EVT_BUTTON, self.OnOther)
        #Bind to Exit on frame close
        self.Bind(wx.EVT_CLOSE, self.OnExit)
        self.SetSizer(self.vbox)
        self.Layout()

        self.statusbar = self.CreateStatusBar(2)
        self.text = wx.StaticText(self.statusbar,-1,("No File loaded"))
        self.progress = wx.Gauge(self.statusbar, range=20)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.text, 0, wx.ALIGN_TOP|wx.ALL, 5)
        sizer.Add(self.progress, 1, wx.ALIGN_TOP|wx.ALL, 5)
        self.statusbar.SetSizer(sizer)
        #wx.BeginBusyCursor()
        self.loadthread = Model(self)


    def OnProgress(self, event):
        self.text.SetLabel(load_status[event.status])
        #self.progress.SetValue(event.count)
        #or for indeterminate progress
        self.progress.Pulse()
        if event.status != 0:
            wx.EndBusyCursor()
            self.Update()
            time.sleep(1)
            #self.statusbar.Hide()
            #Re-set thread in case it needs to be restarted
            self.loadthread = Model(self)
            self.stop.SetLabel("Start")
            self.progress.SetValue(0)
            self.text.SetLabel("")

    def OnStartStop(self, event):
        if self.loadthread.isAlive():
            self.loadthread.terminate() # Shutdown the thread
            self.loadthread.join() # Wait for it to finish
            #Re-set thread in case it needs to be restarted
            self.loadthread = Model(self)
            self.stop.SetLabel("Start")
            self.progress.SetValue(0)
            self.text.SetLabel("")
        else:
            wx.BeginBusyCursor()
            self.loadthread.start()
            self.stop.SetLabel("Stop")

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

    def OnOther(self, event):
        print("Other Task")
        print(self.id.GetValue())
        print(self.firstName.GetValue())
        print(self.lastName.GetValue())

class Controller:
    def __init__(self):
        self.view = View(None, title='Test')
        self.view.Show()

def main():
    app = wx.App()
    controller = Controller()
    app.MainLoop()

if __name__ == '__main__':
    main()

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.