Gtk.ProgressBar在Python中不工作
我试图在Python和Gtk3中使用进度条,但它没有得到更新。我在这个论坛上读了一些关于pygtk的文档和问题,但我真的不明白 我编写了一个代码,只用于测试目的。当您单击一个按钮时,它会递归地读取目录的内容。我的意图是在读取所有这些文件时使用进度条 这是全部代码:Gtk.ProgressBar在Python中不工作,python,progress-bar,gtk3,pygobject,Python,Progress Bar,Gtk3,Pygobject,我试图在Python和Gtk3中使用进度条,但它没有得到更新。我在这个论坛上读了一些关于pygtk的文档和问题,但我真的不明白 我编写了一个代码,只用于测试目的。当您单击一个按钮时,它会递归地读取目录的内容。我的意图是在读取所有这些文件时使用进度条 这是全部代码: import os from gi.repository import Gtk class MyWindow(Gtk.Window): """Progress Bar""" def __init__(self):
import os
from gi.repository import Gtk
class MyWindow(Gtk.Window):
"""Progress Bar"""
def __init__(self):
Gtk.Window.__init__(self, title='Progress Bar')
self.set_default_size(300, 75)
self.set_position(Gtk.WindowPosition.CENTER)
self.set_border_width(10)
# read dir contents
mydir = 'Documents'
home_path = os.environ.get('HOME')
dir_path = os.path.join(home_path, mydir)
self.dir_files_list(dir_path)
# create a grid
self.grid = Gtk.Grid(column_homogeneous=True, row_homogeneous=True,
column_spacing=10, row_spacing=10)
self.add(self.grid)
# create a progress bar
self.progressbar = Gtk.ProgressBar()
self.grid.add(self.progressbar)
# create a button
self.button = Gtk.Button(stock=Gtk.STOCK_APPLY)
self.button.connect('clicked', self.on_button_pressed)
self.grid.attach(self.button, 0, 1, 1, 1)
# function to read the dir contents
def dir_files_list(self, dir_path):
self.dir_list = []
for root, dirs, files in os.walk(dir_path):
for fn in files:
f = os.path.join(root, fn)
self.dir_list.append(f)
# function to update the progressbar
def on_button_pressed(self, widget):
self.progressbar.set_fraction(0.0)
frac = 1.0 / len(self.dir_list)
for f in self.dir_list:
new_val = self.progressbar.get_fraction() + frac
print new_val, f
self.progressbar.set_fraction(new_val)
return True
def main():
"""Show the window"""
win = MyWindow()
win.connect('delete-event', Gtk.main_quit)
win.show_all()
Gtk.main()
return 0
if __name__ == '__main__':
main()
任何来自更有经验的程序员的帮助都将不胜感激 首先,问题是上面的代码运行得太快,因此您会看到进度条更新得太快,似乎没有得到更新。这样做是因为您没有在搜索目录的同时显示结果。当类初始化时,您执行搜索,然后单击按钮,列表将以全速读取并显示在进度栏中。我很确定,如果目录很大,那么当你启动脚本时,窗口显示需要几秒钟的时间,而进度条最终也会在几毫秒内完成 基本上,你所面临的问题是,你在同一个线程中做每件事。Gtk在它自己的线程中,监听来自GUI的事件并更新GUI。大多数情况下,您将使用Gtk.ProgressBar完成一些需要一些时间才能完成的任务,您需要同时执行GUI线程和正在执行任务的工作线程,并将更新从工作线程发送到GUI线程,以便它更新进度条。如果像上面的代码一样,在同一个线程中运行所有内容,那么最终会出现此类问题,例如当GUI冻结时,即由于GUI线程突然执行一些与GUI无关的工作而变得无响应 在PyGTK中,您使用了gobject.idle_addfunction方法参数,这样您就可以从工作线程与GUI线程通信,因此当GUI线程空闲时,它将使用这些参数执行该函数,例如,更新Gtk.ProgressBar 我解决该问题的方法在这里实现,请注意,是针对PyGTK的: 基本上,它是整个应用程序共享的加载窗口。当您想要开始加载某些内容或执行一些繁重的工作时,您必须对WorkingRead类进行子类化。然后,您只需使用WorkingRead子类实例作为参数调用show方法,并完成。在WorkingRead子类中,必须实现有效负载函数,即执行繁重工作的函数。您可以直接从WorkingRead调用加载窗口中的pulse方法来更新ProgressBar,并且不应该关心线程通信,因为该逻辑在那里实现 希望解释有帮助 编辑:
我刚刚将上面的代码移植到PyGObject,您可以在这里找到示例:首先,问题是上面的代码运行得太快,所以您看到进度条更新得太快,似乎没有得到更新。这样做是因为您没有在搜索目录的同时显示结果。当类初始化时,您执行搜索,然后单击按钮,列表将以全速读取并显示在进度栏中。我很确定,如果目录很大,那么当你启动脚本时,窗口显示需要几秒钟的时间,而进度条最终也会在几毫秒内完成 基本上,你所面临的问题是,你在同一个线程中做每件事。Gtk在它自己的线程中,监听来自GUI的事件并更新GUI。大多数情况下,您将使用Gtk.ProgressBar完成一些需要一些时间才能完成的任务,您需要同时执行GUI线程和正在执行任务的工作线程,并将更新从工作线程发送到GUI线程,以便它更新进度条。如果像上面的代码一样,在同一个线程中运行所有内容,那么最终会出现此类问题,例如当GUI冻结时,即由于GUI线程突然执行一些与GUI无关的工作而变得无响应 在PyGTK中,您使用了gobject.idle_addfunction方法参数,这样您就可以从工作线程与GUI线程通信,因此当GUI线程空闲时,它将使用这些参数执行该函数,例如,更新Gtk.ProgressBar 我解决该问题的方法在这里实现,请注意,是针对PyGTK的: 基本上,它是整个应用程序共享的加载窗口。当您想要开始加载某些内容或执行一些繁重的工作时,您必须对WorkingRead类进行子类化。然后,您只需使用WorkingRead子类实例作为参数调用show方法,并完成。在WorkingRead子类中,必须实现有效负载函数,即doe 这是一项繁重的工作。您可以直接从WorkingRead调用加载窗口中的pulse方法来更新ProgressBar,并且不应该关心线程通信,因为该逻辑在那里实现 希望解释有帮助 编辑:
我刚刚将上述内容移植到PyGObject,您可以在这里找到示例:问题是,在创建窗口时,您正在处理整个目录。甚至在您将其显示在self.dir\u files\u listdir\u path行之前。在我看来,你似乎想在按下“应用”按钮后调用它 至少有两种可能的解决方案:使用线程或使用迭代器。对于您的特定用例,我认为迭代器就足够了,而且比pythonic更简单。我只会在你真正需要的时候推荐线程 您可以一次处理每个目录中的每个文件,而不是事先遍历整个目录,然后再进行处理 在您的示例中,我会将方法dir_files_list重命名为walk并按下按钮,如下所示: 从gc导入收集 从gi.repository导入Gtk,GObject 我们现在还需要导入GObject以使用idle_add,它在没有更高优先级的事件挂起时调用回调。此外,一旦任务完成,我们需要删除回调以不再调用它。为此,我们需要source_remove 我将您的方法dir_files_list重命名为walk,因为它在语义上更接近迭代器。当我们遍历每个目录和文件时,我们将使用yield临时返回。记住,yield True意味着有待处理的项。yield False意味着我们停止迭代 因此,方法是: def walkself,dir_路径: self.dir_list=[] 对于os.walkdir\u路径中的根目录、目录和文件: i=0.0 self.set_titleos.path.dirnameroot 对于文件中的fn: i=i+1.0 f=os.path.joinroot,fn self.dir\u list.appendf self.progressbar.set_细分/lenfiles 收集 屈服于真实 屈服于真实 GObject.source\u removeself.id 假屈服 现在,我们在这里更新progressbar。在这一部分中,我将更新每个目录中的进度条。也就是说,它将在每个子目录中重新启动,并且进度条将在每个子目录中重新启动。要了解正在访问哪个目录,请使用当前目录设置窗口标题。这里要理解的重要部分是产量。你可以让它适应你想做的任何事情 遍历整个目录后,我们必须返回yield False,但在此之前,我们将删除回调GObject.source\u removeself.id
我认为Self.DriLIST在这里不再有用,但是你可能有不同的想法。
你可能会想知道步行是什么时候,怎么叫的?按下按钮时可以设置:def on_button_pressed(self, button, *args):
homedir = os.path.expanduser('~')
rootdir = os.path.join(homedir, 'Documents')
self.task = self.walk(rootdir)
self.id = GObject.idle_add(self.task.next)
self.task是一个迭代器,它具有从self.task检索下一项的next方法,只要没有idle_add的挂起事件,就会调用self.task。我们获取id以便在完成后删除回调
您必须从_init__方法中删除self.dir_files_listdir_路径行
还有一件事:我手动调用了垃圾收集器gc.collect,因为它在处理大目录时非常有用,具体取决于您对它们所做的操作。问题是,在创建窗口时,您正在处理整个目录。甚至在您将其显示在self.dir\u files\u listdir\u path行之前。在我看来,你似乎想在按下“应用”按钮后调用它 至少有两种可能的解决方案:使用线程或使用迭代器。对于您的特定用例,我认为迭代器就足够了,而且比pythonic更简单。我只会在你真正需要的时候推荐线程 您可以一次处理每个目录中的每个文件,而不是事先遍历整个目录,然后再进行处理 在您的示例中,我会将方法dir_files_list重命名为walk并按下按钮,如下所示: 从gc导入收集 从gi.repository导入Gtk,GObject 我们现在还需要导入GObject以使用idle_add,它在没有更高优先级的事件挂起时调用回调。此外,一旦任务完成,我们需要删除回调以不再调用它。为此,我们需要source_remove 我将您的方法dir_files_list重命名为walk,因为它在语义上更接近迭代器。当我们遍历每个目录和文件时,我们将使用yield临时返回。记住,yield True意味着有待处理的项。yield False意味着我们停止迭代 因此,方法是: def walkself,dir_路径: self.dir_list=[] 对于os.walkdir\u路径中的根目录、目录和文件: i=0.0 self.set_titleos.path。 地黄根 对于文件中的fn: i=i+1.0 f=os.path.joinroot,fn self.dir\u list.appendf self.progressbar.set_细分/lenfiles 收集 屈服于真实 屈服于真实 GObject.source\u removeself.id 假屈服 现在,我们在这里更新progressbar。在这一部分中,我将更新每个目录中的进度条。也就是说,它将在每个子目录中重新启动,并且进度条将在每个子目录中重新启动。要了解正在访问哪个目录,请使用当前目录设置窗口标题。这里要理解的重要部分是产量。你可以让它适应你想做的任何事情 遍历整个目录后,我们必须返回yield False,但在此之前,我们将删除回调GObject.source\u removeself.id
我认为Self.DriLIST在这里不再有用,但是你可能有不同的想法。
你可能会想知道步行是什么时候,怎么叫的?按下按钮时可以设置:def on_button_pressed(self, button, *args):
homedir = os.path.expanduser('~')
rootdir = os.path.join(homedir, 'Documents')
self.task = self.walk(rootdir)
self.id = GObject.idle_add(self.task.next)
self.task是一个迭代器,它具有从self.task检索下一项的next方法,只要没有idle_add的挂起事件,就会调用self.task。我们获取id以便在完成后删除回调
您必须从_init__方法中删除self.dir_files_listdir_路径行
还有一件事:我手动调用了垃圾收集器gc.collect,因为它在处理大目录时可能会很有用,具体取决于您对它们所做的操作。非常感谢。现在有了你的解释,我能够对Gtk+和线程有更多的了解,但我不确定我是否能够在我的程序中实现这一点。。。好吧,至少我要试试。。。我感谢你努力解释我的问题之外隐藏的东西。我更新了答案,检查PyGObject版本:非常感谢你的时间。我要看看这个版本。格雷西亚斯!我放弃了,这对我的技能来说太复杂了。我需要一些更简单的,并在一个文件中,如果可能的话:无论如何,非常感谢!非常感谢。现在有了你的解释,我能够对Gtk+和线程有更多的了解,但我不确定我是否能够在我的程序中实现这一点。。。好吧,至少我要试试。。。我感谢你努力解释我的问题之外隐藏的东西。我更新了答案,检查PyGObject版本:非常感谢你的时间。我要看看这个版本。格雷西亚斯!我放弃了,这对我的技能来说太复杂了。我需要一些更简单的,并在一个文件中,如果可能的话:无论如何,非常感谢!非常感谢@gpoo对您的帮助!我将花一些时间来阅读这篇文章,并尝试理解和吸收一切:-请随意询问任何看起来模糊或需要更多解释的问题。非常感谢@gpoo的帮助!我将花一些时间来阅读这篇文章,并试图理解和吸收所有的东西:-请随意问任何看起来模糊或需要更多解释的问题。