2016-04-15 11 views
1

私はubuntuターミナルから文字列を読み込み、その文字列をボタンのラベルとして設定しようとしています。それはいくつかの反復のために完全に動作し、その後フリーズしたり、エラーで閉じます。私はそれが凍ったり閉じたりするときのパターンを見つけることができませんでした。私はgtkライブラリとPython 2.7を使用しています。ボタンラベルテキストの更新中にPython GUIがフリーズまたは閉じる

UIがフリーズした後のスクリーンショットを以下に示します。上記のスクリーンショットに示されているように

Screenshot of the frozen UI(with error)

、それは正常値234、56を更新した後、213文字列を受信した後、エラーで終了しました。また、UIのボタンも213の値を持つことがわかります。

エラーが表示されたり終了したりすることなく、UIがフリーズすることがあります。

Iは以下のコード

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 

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()) 

上記のコードは、(オフコース上記の3つのファイルを作成した後)python thread.pyを入力して実行することができます。この凍結問題を解決するための解決策を提案してください。

+0

**メインループを実行する同じスレッド以外のスレッドからGTK関数を呼び出さないでください**。その代わりに、 'GLib.idle_add(...)'を使用して、GUIスレッドで関数の実行をスケジュールします。また、 'run'メソッドを決して定義しないので、' gui2'の 'Thrd'クラスは役に立ちません。 – user4815162342

+0

@ user4815162342ご意見ありがとうございます。 'Glib.idle_add()'を追加しようとしましたが、うまくいきませんでした。たぶん、私はまだ何か間違っている。私はPythonとUIの新機能です。私はあなたの答えを受け入れることができるように、あなたは修正されたコードを答えとして掲示してください。 –

+0

あなたの例で他の問題を修正しましたか?まず、 "Exception !!!!"と表示される汎用例外ハンドラを取り除く必要があります。これを削除すると、実際のバックトレースが提供されます。 (Python 2で走っているときは、 'input'を' raw_input'に変更しなければなりませんでした。そうでなければ、任意の文字列で発生させました。) 'vkey1'には構文エラーがあります。これらのエラーを修正したら、 'textinit'の不要なスレッドの作成を' button0.set_label(str(ch)) 'への単純な呼び出しで置き換え、' gui2.textinit() 'の呼び出しを' GLib.idle_add( gui2.textinit) '、あなたの例はうまくいきました。 – user4815162342

答えて

2

クラッシュの最も原因は、コードがdocumentation statesが許可されていないメインループを実行するスレッド以外のスレッドからGTKコードを呼び出すことです。

gui2.textinit()の呼び出しをGLib.idle_add(gui2.textinit)に置き換えてください(textinitの後にかっこがないことに注意してください)。コードに関する

いくつかの発言:

  • 汎用的な例外ハンドラが発生した例外をマスクしています。それを削除すると、何か問題が生じたときに便利なトレースバックが表示されます。

  • あなたは、Python 2の下で実行している場合、あなたはおそらくraw_inputinputを変更したい、それ以外のコードは、有効なPython式ではない任意の入力にチョーク。

  • textinit実際のスレッドを実行しないスレッドオブジェクトを作成します。 threading.Threadから継承する場合、run関数をオーバーライドする必要があります。この関数は、start()が呼び出されると新しいスレッドで呼び出されます。コンストラクタで作業を行うと何も成就しません。

  • thread.start_new_threadは同じ意味を有し、そしてまたThreadオブジェクトを返すthreading.Thread(target=fn)を使用し、通常の状況で使用すべきではないし、それは、Python 3の代わりにthread.start_new_thread(fn,())_threadに降格される低レベルAPIです。

関連する問題