2016-04-15 5 views
1

Я пытаюсь прочитать строку с терминала ubuntu и установить эту строку как метку кнопки. Он отлично работает для некоторой итерации, а затем замерзает или закрывается с ошибкой. Я не мог найти никакого шаблона, когда он зависает или закрывается. Я использую библиотеки gtk и python 2.7.Python GUI зависает или закрывается при попытке обновить текст метки кнопки

Снимок экрана пользовательского интерфейса после его заморозки можно увидеть ниже.

Screenshot of the frozen UI(with error)

Как видно на рисунке выше, она успешно обновила значение 234, 56, а затем вышел с ошибкой после получения 213 строки. Вы также можете заметить, что кнопка в пользовательском интерфейсе также имеет значение 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 файлов отклонения от курса). Пожалуйста, предложите любое решение для преодоления этой проблемы с замораживанием.

+0

** Никогда ** не вызывайте функции GTK из потока, отличного от того же потока, который запускает основной цикл. Вместо этого используйте 'GLib.idle_add (...)' для планирования выполнения функции в потоке графического интерфейса. Кроме того, класс 'Thrd' в' gui2' бесполезен, поскольку вы никогда не определяете метод 'run'. – user4815162342

+0

@ user4815162342 Спасибо за ваше предложение. Я попытался добавить 'Glib.idle_add()', но это не сработало. Может быть, я все еще делаю что-то неправильно. Я новичок в python и пользовательском интерфейсе. Можете ли вы отправить измененный код в качестве ответа, чтобы я мог принять ваш ответ. –

+0

У вас были проблемы с вашим примером? Во-первых, вы должны избавиться от универсального обработчика исключений, который просто печатает «Exception !!!!»; его удаление обеспечит фактическую обратную трассировку. (При работе с Python 2 мне приходилось менять 'input' на' raw_input', иначе он поднимался на произвольные строки.) Кроме того, 'vkey1' содержал синтаксические ошибки. Как только я исправил эти ошибки, заменил ненужное создание потока в 'textinit' простым вызовом' button0.set_label (str (ch)) 'и заменил вызов' gui2.textinit() 'на' GLib.idle_add (gui2.textinit) ', ваш пример работал отлично. – user4815162342

ответ

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 низкого уровня, которые не должны использоваться в нормальных условиях и что понижен _thread в Python 3. Вместо thread.start_new_thread(fn,()), используйте threading.Thread(target=fn), который имеет тот же смысл, а также возвращает Thread объект.