wxPython状态栏中的moviepy进度栏
在Windows10上的Python3.x上运行 我正在编写一个脚本,帮助将.tiff图像序列自动编译成视频。我正在使用wxPython构建GUI。首先,我创建window类并为窗口设置一个全局变量wxPython状态栏中的moviepy进度栏,python,python-3.x,wxpython,moviepy,Python,Python 3.x,Wxpython,Moviepy,在Windows10上的Python3.x上运行 我正在编写一个脚本,帮助将.tiff图像序列自动编译成视频。我正在使用wxPython构建GUI。首先,我创建window类并为窗口设置一个全局变量 global main_window main_window = self 然后,我有一个函数,用于写入状态栏,并将值打印到控制台(有时我还添加代码,从发送到此函数的文本中写入日志文件) 这是我编写的moviePy函数,用于将图像序列转换为ta视频 def video_from_sequence(
global main_window
main_window = self
然后,我有一个函数,用于写入状态栏,并将值打印到控制台(有时我还添加代码,从发送到此函数的文本中写入日志文件)
这是我编写的moviePy函数,用于将图像序列转换为ta视频
def video_from_sequence(image_sequence, video, fps):
img = []
update_status_bar(main_window, 'Getting Image Directory')
path = os.path.dirname(os.path.realpath(image_sequence))
print(path)
update_status_bar(main_window, 'Getting List of Image Files')
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith('.tiff'):
img.append(file)
os.chdir(path)
update_status_bar(main_window, 'Creating Video From Image Sequence')
clip = ImageSequenceClip(img, fps=fps)
update_status_bar(main_window, clip.write_videofile(video, fps=fps))
print to console(打印到控制台)确实显示了进度,但是状态栏中没有填充流程的当前进度。因为我希望最终以.pyw的形式运行,其中状态栏显示进度,所以让进度栏显示在状态栏中对我来说很重要,但是我很难找到这样做的方法
更新(2020年1月6日):
我成功地使用了两个函数来启动和停止进度条,并创建了带有两个面板(而不是一个)的状态栏
状态栏的MainWindow类中的我的代码已更改为:
self.statusbar = self.CreateStatusBar(2)
self.progress_bar = wx.Gauge(self.statusbar, -1, size=(280,25), style=wx.GA_PROGRESS)
self.progress_bar_active = False
self.Show()
self.progress_bar.SetRange(50)
self.progress_bar.SetValue(0)
我的启动动画的功能:
def start_busy_statusbar(window):
window.count = 0
window.proc = subprocess.Popen(['ping', '127.0.0.1', '-i', '0.2'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
wx.Yield()
try:
list_data = window.proc.stdout.readline()
wx.Yield()
except:
break
if len(list_data) == 0:
break
window.progress_bar.Pulse()
wx.Yield()
window.count += 1
def stop_busy_statusbar(window):
window.progress_bar.Destroy()
window.progress_bar = wx.Gauge(window.statusbar, -1, size=(280, 25), style=wx.GA_PROGRESS)
以及我停止动画的功能:
def start_busy_statusbar(window):
window.count = 0
window.proc = subprocess.Popen(['ping', '127.0.0.1', '-i', '0.2'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
wx.Yield()
try:
list_data = window.proc.stdout.readline()
wx.Yield()
except:
break
if len(list_data) == 0:
break
window.progress_bar.Pulse()
wx.Yield()
window.count += 1
def stop_busy_statusbar(window):
window.progress_bar.Destroy()
window.progress_bar = wx.Gauge(window.statusbar, -1, size=(280, 25), style=wx.GA_PROGRESS)
这确实感觉有点粗糙,但确实有效
因此,我的convert()函数调用video_from_sequence()函数如下所示:
def convert(self, event):
start_busy_statusbar(main_window)
image_sequence = str(self.text_image_sequence_dir.GetValue())
original_video = str(self.text_original_video_dir.GetValue())
if image_sequence.endswith('.tiff') and original_video.endswith('.mkv'):
try:
new_video = str(original_video)[:-4] + '_1080p.mkv'
temp_video = str(original_video)[:-4] + '_temp.mkv'
print(image_sequence)
print(original_video)
print(new_video)
fps = get_frame_rate(original_video)
print(fps)
video_from_sequence(image_sequence, temp_video, fps)
except FileNotFoundError as e:
e = str(e).replace('Errno 2] ', '')
e = e.replace('directory:', 'directory:\n')
warning(e)
update_status_bar(self, 'Finished')
else:
warning('You must enter valid paths for both a tiff sequence and original video.')
stop_busy_statusbar(main_window)
我现在遇到的是,窗口在处理图像序列时会锁定。有人建议我使用一个单独的线程或利用wx.Yield。我不太清楚如何执行这些事情。我尝试过CallAfter(function(vars)),但似乎不起作用
我复制了一些代码片段来演示它在wxPython中的工作原理,但我并不真正理解它是如何工作的,也无法在我的脚本中使用它。这里是一个在状态栏中实现进度栏的非常古老的示例。
它应该给你足够的时间和你一起工作
import wx
import subprocess
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title='Statusbar progress')
panel = wx.Panel(self)
self.start_btn = wx.Button(panel, label='Start')
self.start_btn.Bind(wx.EVT_BUTTON, self.OnStart)
self.stop_btn = wx.Button(panel, label='Stop')
self.stop_btn.Bind(wx.EVT_BUTTON, self.OnStop)
self.Bind(wx.EVT_CLOSE, self.OnExit)
self.text = wx.TextCtrl(panel, -1, 'Type text here')
btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
btn_sizer.Add(self.start_btn)
btn_sizer.Add(self.stop_btn)
btn_sizer.Add(self.text)
panel.SetSizer(btn_sizer)
self.statusbar = self.CreateStatusBar(3)
self.text1 = wx.StaticText(self.statusbar,-1,("Static text"))
self.text2 = wx.StaticText(self.statusbar,-1,("Count Text"))
self.progress_bar = wx.Gauge(self.statusbar, -1, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.text1, 0, wx.ALL, 5)
sizer.Add(self.text2, 1, wx.ALL, 5)
sizer.Add(self.progress_bar, 2, wx.ALL, 5)
self.statusbar.SetSizer(sizer)
self.Show()
self.progress_bar.SetRange(50)
self.progress_bar.SetValue(0)
def OnStart(self,event):
self.start_btn.Enable(False)
self.text1.SetLabelText("Started")
self.count = 0
self.proc = subprocess.Popen(['ping','127.0.0.1','-i','0.2'],stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
while True:
try:
list_data = self.proc.stdout.readline()
except:
break
if len(list_data) == 0:
break
self.progress_bar.Pulse()
self.count+=1
self.text2.SetLabelText("Count "+str(self.count))
wx.GetApp().Yield()
def OnStop(self,event):
self.start_btn.Enable(True)
self.text1.SetLabelText("Stopped")
try:
self.proc.kill()
except:
pass
def OnExit(self,event):
try:
self.proc.kill()
except:
pass
self.Destroy()
if __name__ == '__main__':
app = wx.App()
frame = MainFrame()
app.MainLoop()
谢谢你。我不知道如何在启动进程和进程结束之间的函数期间调用它。我是否将
def\uuuu init\uuuu(self)
添加到当前窗口?或者可能只是将该类的函数添加到我当前为窗口创建的类中?好的,我已经成功启动了progressbar动画,但是我无法停止它。.proc.kill()
实际上似乎并没有关闭状态栏。我还注意到,当我开始一个较长的过程(在本例中是将帧编译成视频)时,进度条会冻结。如果看不到您的代码,几乎不可能进行评论。但是,proc.kill
只是终止一个子进程,因此您的等效程序将停止图像转换。当您处理长时间运行的任务时,整个gui将发生冻结。您可以在适当的时候使用wx.Yield()
,或者如果您正在对progressbar执行线程,则可以定期使用wx.Yield
,并为线程创建stop
方法。我发现我可以使用window.progress\u bar.Destroy()
和window.progress\u bar=wx.Gauge(window.statusbar,-.1,size=(280,25),style=wx.GA_PROGRESS)
以停止动画。我不确定wx.Yield()
或wx.Yield
的合适位置。不过我会继续玩,如果可以的话,我很想避免冰冻。或者我只是需要学习如何在另一个线程中运行它。我已经更新了页面以包含更多要评估的代码。