尝试更新按钮标签文本时,Python GUI会冻结或关闭

时间:2016-04-15 20:09:17

标签: python user-interface gtk pygtk freeze

我正在尝试从ubuntu终端读取一个字符串,并将该字符串设置为按钮的标签。它适用于某些迭代,然后冻结或关闭错误。我找不到任何关于何时冻结或关闭的模式。我使用的是gtk库和python 2.7。

下面可以看到UI冻结后的屏幕截图。

Screenshot of the frozen UI(with error)

如上面的屏幕截图所示,它已成功更新值234,56,然后在收到213字符串后退出并显示错误。您还可以观察到UI中的按钮也具有213值。

有时,用户界面会冻结而不会显示任何错误或退出。

我使用了以下代码

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个文件之后)来运行上述代码。请提出任何解决方案以克服这种冻结问题。

1 个答案:

答案 0 :(得分:2)

崩溃的最可能原因是您的代码从运行主循环的线程以外的线程调用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 3中降级为_thread。而不是thread.start_new_thread(fn, ()),请使用{{ 1}},具有相同的含义,并返回一个threading.Thread(target=fn)对象。