Python 尝试更新按钮标签文本时 GUI 冻结或关闭
Python GUI freezes or closes while trying to update the button label text
我正在尝试从 ubuntu 终端读取一个字符串并将该字符串设置为按钮的标签。它在某些迭代中完美运行,然后因错误而冻结或关闭。我找不到关于它何时冻结或关闭的任何模式。我正在使用 gtk 库和 python 2.7.
下面是 UI 冻结后的屏幕截图。
如上图所示,已成功更新值234、56,收到213字符串后报错退出。您还可以观察到 UI 中的按钮也具有 213 值。
有时 UI 只是冻结而不显示任何错误或退出。
我用过下面的代码
1. thread.py (从终端调用的主程序)
import thread
import time
import gui2
import vkeys1
import os
try:
thread.start_new_thread( vkeys1.main, ( ) )
thread.start_new_thread( gui2.main, ( ) )
except:
print "Error: unable to start thread"
# To stop this script from closing
os.system("mkfifo d1 2> error.log")
fd = os.open('d1', os.O_RDONLY)
ch = os.read(fd,1) # No writer
2. vkeys1.py (它从终端读取输入并调用 textinit() )
import gui2
def main() :
while True:
try :
gui2.ch = str(input('\nInput a string : '))
gui2.textinit()
except :
print(" \n\n Exception!! \n\n")
3. gui2.py (更新按钮标签)
from gi.repository import Gtk, GdkPixbuf, Gdk, GLib
import Image
import os, sys
import time
import vkeys1
import threading
global ch # ch is used at vkeys1.py to store the input
ch = 'dummy content'
button0 = Gtk.Button(label="Initially empty")
class TableWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="String retrieval widget")
self.set_size_request(500,200)
self.connect_after('destroy', self.destroy)
self.main_box=Gtk.VBox()
self.main_box.set_spacing(5)
self.label = Gtk.Label(" ")
table = Gtk.Table(7,4, True)
self.add(self.main_box)
self.main_box.pack_start(self.label, False, False, 0)
self.main_box.pack_start(table, False, False, 0)
table.attach(button0, 0, 4, 0, 1)
self.show_all()
def destroy(window, self):
Gtk.main_quit()
def textinit(): # called from vkeys1.py
class Thrd(threading.Thread) :
def __init__(self) :
threading.Thread.__init__(self)
print('\nReceived string')
print(str(ch))
print('\n')
button0.set_label(str(ch)) # Button label updated here
Thrd2 = Thrd()
Thrd2.start()
return
def main():
app=TableWindow()
app.set_keep_above(True)
app.set_gravity(Gdk.Gravity.SOUTH_WEST)
Gtk.main()
if __name__ == "__main__":# for any error exit
sys.exit(main())
以上代码可以通过输入 python thread.py
得到 运行(在创建上述 3 个文件后)。请提出解决此冻结问题的任何解决方案。
崩溃的最可能原因是您的代码从运行主循环的线程以外的线程调用 GTK 代码,这是不允许的 documentation states。
要解决此问题,请将 gui2.textinit()
的调用替换为 GLib.idle_add(gui2.textinit)
(注意 textinit
后缺少括号)。
关于代码的几点说明:
通用异常处理程序正在屏蔽发生的异常。删除它,当出现问题时你会看到一个有用的回溯。
如果你在 Python 2 下是 运行,你可能想要将 input
更改为 raw_input
,否则代码会在任何输入时阻塞那不是有效的 Python 表达式。
textinit
创建一个从不运行实际线程的线程对象。继承threading.Thread
时,必须覆盖run
函数,一旦调用start()
,就会在新线程中调用该函数。在构造函数中完成工作无济于事。
thread.start_new_thread
是一个低级别的API,一般情况下不应该使用,在Python中被降级为_thread
3 .不用thread.start_new_thread(fn, ())
,用threading.Thread(target=fn)
,意思是一样的,也是returns一个Thread
对象。
我正在尝试从 ubuntu 终端读取一个字符串并将该字符串设置为按钮的标签。它在某些迭代中完美运行,然后因错误而冻结或关闭。我找不到关于它何时冻结或关闭的任何模式。我正在使用 gtk 库和 python 2.7.
下面是 UI 冻结后的屏幕截图。
如上图所示,已成功更新值234、56,收到213字符串后报错退出。您还可以观察到 UI 中的按钮也具有 213 值。
有时 UI 只是冻结而不显示任何错误或退出。
我用过下面的代码
1. thread.py (从终端调用的主程序)
import thread
import time
import gui2
import vkeys1
import os
try:
thread.start_new_thread( vkeys1.main, ( ) )
thread.start_new_thread( gui2.main, ( ) )
except:
print "Error: unable to start thread"
# To stop this script from closing
os.system("mkfifo d1 2> error.log")
fd = os.open('d1', os.O_RDONLY)
ch = os.read(fd,1) # No writer
2. vkeys1.py (它从终端读取输入并调用 textinit() )
import gui2
def main() :
while True:
try :
gui2.ch = str(input('\nInput a string : '))
gui2.textinit()
except :
print(" \n\n Exception!! \n\n")
3. gui2.py (更新按钮标签)
from gi.repository import Gtk, GdkPixbuf, Gdk, GLib
import Image
import os, sys
import time
import vkeys1
import threading
global ch # ch is used at vkeys1.py to store the input
ch = 'dummy content'
button0 = Gtk.Button(label="Initially empty")
class TableWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="String retrieval widget")
self.set_size_request(500,200)
self.connect_after('destroy', self.destroy)
self.main_box=Gtk.VBox()
self.main_box.set_spacing(5)
self.label = Gtk.Label(" ")
table = Gtk.Table(7,4, True)
self.add(self.main_box)
self.main_box.pack_start(self.label, False, False, 0)
self.main_box.pack_start(table, False, False, 0)
table.attach(button0, 0, 4, 0, 1)
self.show_all()
def destroy(window, self):
Gtk.main_quit()
def textinit(): # called from vkeys1.py
class Thrd(threading.Thread) :
def __init__(self) :
threading.Thread.__init__(self)
print('\nReceived string')
print(str(ch))
print('\n')
button0.set_label(str(ch)) # Button label updated here
Thrd2 = Thrd()
Thrd2.start()
return
def main():
app=TableWindow()
app.set_keep_above(True)
app.set_gravity(Gdk.Gravity.SOUTH_WEST)
Gtk.main()
if __name__ == "__main__":# for any error exit
sys.exit(main())
以上代码可以通过输入 python thread.py
得到 运行(在创建上述 3 个文件后)。请提出解决此冻结问题的任何解决方案。
崩溃的最可能原因是您的代码从运行主循环的线程以外的线程调用 GTK 代码,这是不允许的 documentation states。
要解决此问题,请将 gui2.textinit()
的调用替换为 GLib.idle_add(gui2.textinit)
(注意 textinit
后缺少括号)。
关于代码的几点说明:
通用异常处理程序正在屏蔽发生的异常。删除它,当出现问题时你会看到一个有用的回溯。
如果你在 Python 2 下是 运行,你可能想要将
input
更改为raw_input
,否则代码会在任何输入时阻塞那不是有效的 Python 表达式。textinit
创建一个从不运行实际线程的线程对象。继承threading.Thread
时,必须覆盖run
函数,一旦调用start()
,就会在新线程中调用该函数。在构造函数中完成工作无济于事。thread.start_new_thread
是一个低级别的API,一般情况下不应该使用,在Python中被降级为_thread
3 .不用thread.start_new_thread(fn, ())
,用threading.Thread(target=fn)
,意思是一样的,也是returns一个Thread
对象。