如何在 GUI 线程上调用方法?
how to call a method on the GUI thread?
我正在制作一个从网上商店获取最新收入的小程序,如果它比以前的收入多,它就会发出声音,我正在使用 Pyglet,但我得到了错误,因为它不是从主线程调用的。我想知道如何在主线程上调用方法。请参阅以下错误:
'thread that imports pyglet.app' RuntimeError: EventLoop.run() must
be called from the same thread that imports pyglet.app
def work ():
threading.Timer(5, work).start()
file_Name = "save.txt"
lastRevenue = 0
data = json.load(urllib2.urlopen(''))
newRevenue = data["revenue"]
if (os.path.getsize(file_Name) <= 0):
with open(file_Name, "wb") as f:
f.write('%d' % newRevenue)
f.flush()
with open(file_Name, "rb") as f:
lastRevenue = float(f.readline().strip())
print lastRevenue
print newRevenue
f.close()
if newRevenue > lastRevenue:
with open(file_Name, "wb") as f:
f.write('%f' % newRevenue)
f.flush()
playsound()
def playsound():
music = pyglet.resource.media('cash.wav')
music.play()
pyglet.app.run()
work()
这不是特别奇怪。 work
正在作为导入 pyglet
的单独线程执行。
pyglet.app
导入时设置了很多上下文变量,什么没有。我说什么不是因为我实际上没有费心去深入检查它实际设置的内容。
而且 OpenGL 不能在它自己的上下文(它所在的主线程)之外执行事情。因为不允许您从相邻线程四处查看 OpenGL。如果说得通。
但是,如果您创建自己的 .run()
函数并使用基于 class 的激活 Pyglet 的方法,您可以从线程启动 GUI。
这是您如何设置它的工作示例:
import pyglet
from pyglet.gl import *
from threading import *
# REQUIRES: AVBin
pyglet.options['audio'] = ('alsa', 'openal', 'silent')
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(300, 300, fullscreen = False)
self.x, self.y = 0, 0
self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
self.music = pyglet.resource.media('cash.wav')
self.music.play()
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def render(self):
self.clear()
self.bg.draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
if not self.music.playing:
self.alive = 0
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
class ThreadExample(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
x = main()
x.run()
Test_One = ThreadExample()
请注意,您仍然需要从线程中启动实际的 GUI 代码。
我强烈建议您改为这样做
鉴于混合线程和 GUI 调用是一个滑坡,我建议您走一条更谨慎的道路。
from threading import *
from time import sleep
def is_main_alive():
for t in enumerate():
if t.name == 'MainThread':
return t.isAlive()
class worker(Thread):
def __init__(self, shared_dictionary):
Thread.__init__(self)
self.shared_dictionary
self.start()
def run(self):
while is_main_alive():
file_Name = "save.txt"
lastRevenue = 0
data = json.load(urllib2.urlopen(''))
newRevenue = data["revenue"]
if (os.path.getsize(file_Name) <= 0):
with open(file_Name, "wb") as f:
f.write('%d' % newRevenue)
f.flush()
with open(file_Name, "rb") as f:
lastRevenue = float(f.readline().strip())
print lastRevenue
print newRevenue
f.close()
if newRevenue > lastRevenue:
with open(file_Name, "wb") as f:
f.write('%f' % newRevenue)
f.flush()
#playsound()
# Instead of calling playsound() here,
# set a flag in the shared dictionary.
self.shared_dictionary['Play_Sound'] = True
sleep(5)
def playsound():
music = pyglet.resource.media('cash.wav')
music.play()
pyglet.app.run()
shared_dictionary = {'Play_Sound' : False}
work_handle = worker(shared_dictionary)
while 1:
if shared_dictionary['Play_Sound']:
playsound()
shared_dictionary['Play_Sound'] = False
sleep(0.025)
这是您要找的内容的草稿。
基本上是某种 event/flag 驱动的后端,Thread 和 GUI 可以用来相互通信。
本质上你有一个工作线程(就像你以前做的那样),它每 5 秒检查一次你想要的任何文件,如果它检测到 newRevenue > lastRevenue
,它会将一个特定的标志设置为 True
。您的主循环将检测到此更改,播放声音并将标志恢复为 False。
我绝不是故意在此处包含任何错误处理,我们在这里提供帮助而不是创建完整的解决方案。我希望这能帮助你朝着正确的方向前进。
我正在制作一个从网上商店获取最新收入的小程序,如果它比以前的收入多,它就会发出声音,我正在使用 Pyglet,但我得到了错误,因为它不是从主线程调用的。我想知道如何在主线程上调用方法。请参阅以下错误:
'thread that imports pyglet.app' RuntimeError: EventLoop.run() must be called from the same thread that imports pyglet.app
def work ():
threading.Timer(5, work).start()
file_Name = "save.txt"
lastRevenue = 0
data = json.load(urllib2.urlopen(''))
newRevenue = data["revenue"]
if (os.path.getsize(file_Name) <= 0):
with open(file_Name, "wb") as f:
f.write('%d' % newRevenue)
f.flush()
with open(file_Name, "rb") as f:
lastRevenue = float(f.readline().strip())
print lastRevenue
print newRevenue
f.close()
if newRevenue > lastRevenue:
with open(file_Name, "wb") as f:
f.write('%f' % newRevenue)
f.flush()
playsound()
def playsound():
music = pyglet.resource.media('cash.wav')
music.play()
pyglet.app.run()
work()
这不是特别奇怪。 work
正在作为导入 pyglet
的单独线程执行。
pyglet.app
导入时设置了很多上下文变量,什么没有。我说什么不是因为我实际上没有费心去深入检查它实际设置的内容。
而且 OpenGL 不能在它自己的上下文(它所在的主线程)之外执行事情。因为不允许您从相邻线程四处查看 OpenGL。如果说得通。
但是,如果您创建自己的 .run()
函数并使用基于 class 的激活 Pyglet 的方法,您可以从线程启动 GUI。
这是您如何设置它的工作示例:
import pyglet
from pyglet.gl import *
from threading import *
# REQUIRES: AVBin
pyglet.options['audio'] = ('alsa', 'openal', 'silent')
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(300, 300, fullscreen = False)
self.x, self.y = 0, 0
self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
self.music = pyglet.resource.media('cash.wav')
self.music.play()
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def render(self):
self.clear()
self.bg.draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
if not self.music.playing:
self.alive = 0
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
class ThreadExample(Thread):
def __init__(self):
Thread.__init__(self)
self.start()
def run(self):
x = main()
x.run()
Test_One = ThreadExample()
请注意,您仍然需要从线程中启动实际的 GUI 代码。
我强烈建议您改为这样做
鉴于混合线程和 GUI 调用是一个滑坡,我建议您走一条更谨慎的道路。
from threading import *
from time import sleep
def is_main_alive():
for t in enumerate():
if t.name == 'MainThread':
return t.isAlive()
class worker(Thread):
def __init__(self, shared_dictionary):
Thread.__init__(self)
self.shared_dictionary
self.start()
def run(self):
while is_main_alive():
file_Name = "save.txt"
lastRevenue = 0
data = json.load(urllib2.urlopen(''))
newRevenue = data["revenue"]
if (os.path.getsize(file_Name) <= 0):
with open(file_Name, "wb") as f:
f.write('%d' % newRevenue)
f.flush()
with open(file_Name, "rb") as f:
lastRevenue = float(f.readline().strip())
print lastRevenue
print newRevenue
f.close()
if newRevenue > lastRevenue:
with open(file_Name, "wb") as f:
f.write('%f' % newRevenue)
f.flush()
#playsound()
# Instead of calling playsound() here,
# set a flag in the shared dictionary.
self.shared_dictionary['Play_Sound'] = True
sleep(5)
def playsound():
music = pyglet.resource.media('cash.wav')
music.play()
pyglet.app.run()
shared_dictionary = {'Play_Sound' : False}
work_handle = worker(shared_dictionary)
while 1:
if shared_dictionary['Play_Sound']:
playsound()
shared_dictionary['Play_Sound'] = False
sleep(0.025)
这是您要找的内容的草稿。
基本上是某种 event/flag 驱动的后端,Thread 和 GUI 可以用来相互通信。
本质上你有一个工作线程(就像你以前做的那样),它每 5 秒检查一次你想要的任何文件,如果它检测到 newRevenue > lastRevenue
,它会将一个特定的标志设置为 True
。您的主循环将检测到此更改,播放声音并将标志恢复为 False。
我绝不是故意在此处包含任何错误处理,我们在这里提供帮助而不是创建完整的解决方案。我希望这能帮助你朝着正确的方向前进。