在一个 Gtk 应用程序中,希望在运行函数期间显示一个 Gtk 的 Spinner 控件,但是在函数运行期间,Spinner 控件不会出现,而是窗口变暗,就像窗口没有响应一样。
2、解决方案
出现这种情况是因为主循环被正在运行的函数锁住了。一种解决方案是通过异步的方式调用函数,一种方式是使用Python的线程,另一种方式是使用 Gtk 的 idle_add 方法,该方法会在主循环的空闲时间调用函数。
下面是使用Python的线程实现异步函数调用的代码示例:
import threading
class Thread(threading.Thread):
def __init__(self,callback,*args,**kwargs):
self.__callback = callback
threading.Thread.__init__(self,*args,**kwargs)
def run(self):
try:
if self.__target:
print('thread')
_self = self.__kwargs.get('self',self.__args[0])
self.__callback(_self, self.__target(*self.__args, **self.__kwargs))
finally:
# Avoid a refcycle if the thread is running a function with
# an argument that has a member that points to the thread.
del self.__target, self.__args, self.__kwargs
def background(callback):
print('background')
def wrapper(fun):
print('wrapper')
def inner(*args,**kwargs):
print('inner')
Thread(callback=callback,target=fun,args=args,kwargs=kwargs).start()
return inner
return wrapper
def spinner(fun):
def inner(self,*args,**kwargs):
self.show()
result = fun(self,*args,**kwargs)
self.hide()
return result
return inner
def spinner_hide(fun):
def inner(self,*args,**kwargs):
result = fun(self,*args,**kwargs)
self.hide()
return result
return inner
def spinner_show(fun):
def inner(self,*args,**kwargs):
self.show()
result = fun(self,*args,**kwargs)
return result
return inner
class A(object):
@spinner_hide
def my_function_callback(self,data):
print('callback')
print(data)
@spinner_show
@background(my_function_callback)
def my_function(self, input):
# do something here that takes long time
print(input)
output=input
return output
def show(self): print('showed')
def hide(self): print('hidden')
a=A()
a.my_function('gogo')
当调用 a.my_function('gogo')
时,my_function
函数会被异步地执行,在函数执行期间,spinner
会显示,函数执行完成后,spinner
会隐藏。
另一种方式是使用 Gtk 的 idle_add 方法,代码示例如下:
import gobject
def async(func):
"""Make a function mainloop friendly. the function will be called at the
next mainloop idle state."""
def new_function(*args, **kwargs):
def async_function():
func(*args, **kwargs)
return False
gobject.idle_add(async_function)
return new_function
class A(object):
def __init__(self):
self.spinner = gtk.Spinner()
self.spinner.hide()
@async
def my_function(self, input):
self.spinner.show()
# do something here that takes long time
print(input)
output=input
self.spinner.hide()
return output
def show(self):
self.spinner.show()
def hide(self):
self.spinner.hide()
def main(self):
a.my_function('gogo')
if __name__ == "__main__":
a = A()
a.main()
gtk.main()
当调用 a.main()
时,my_function
函数会被异步地执行,在函数执行期间,spinner
会显示,函数执行完成后,spinner
会隐藏。