2016-04-15 12 views
1

Ich versuche, eine Zeichenfolge aus dem Ubuntu-Terminal zu lesen und diese Zeichenfolge als Beschriftung einer Schaltfläche festzulegen. Es funktioniert perfekt für einige Iteration und dann friert oder schließt mit Fehler. Ich konnte kein Muster finden, wenn es gefriert oder schließt. Ich benutze gtk Bibliotheken und Python 2.7.Python GUI friert ein oder wird geschlossen, während versucht wird, den Button-Label-Text zu aktualisieren

Ein Screenshot der Benutzeroberfläche, nachdem es eingefroren ist, kann unten gesehen werden.

Screenshot of the frozen UI(with error)

Wie in der obigen Screenshot sehen ist, hat sie erfolgreich den Wert 234, 56 aktualisiert, und verließ dann mit Fehlern nach 213 Zeichenfolge empfängt. Sie können auch beobachten, dass die Schaltfläche in der Benutzeroberfläche ebenfalls 213 hat.

Manchmal erstarrt die Benutzeroberfläche, ohne dass Fehler angezeigt oder beendet werden.

ich verwendet habe, die folgenden Codes

1. thread.py (Hauptprogramm von Terminal genannt)

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 (Er liest den Eingang von Terminal und Anrufe 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 (Aktualisiert das Button-Beschriftung)

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

Die obigen Codes können durch Eingabe von python thread.py ausgeführt werden (nach den oben genannten drei Dateien off-Kurs erstellen). Bitte schlagen Sie eine Lösung vor, um dieses Gefrierproblem zu lösen.

+0

** Niemals ** GTK-Funktionen von einem anderen Thread als dem Thread aufrufen, der die Hauptschleife ausführt. Verwenden Sie stattdessen 'GLib.idle_add (...)', um die Ausführung der Funktion im GUI-Thread zu planen. Außerdem ist die 'Thrd'-Klasse in' gui2' nutzlos, da Sie niemals die 'run'-Methode definieren. – user4815162342

+0

@ user4815162342 Vielen Dank für Ihren Vorschlag. Ich habe versucht, 'Glib.idle_add()' hinzuzufügen, aber es hat nicht funktioniert. Vielleicht mache ich immer noch etwas falsch. Ich bin neu in Python und UI. Können Sie den geänderten Code bitte als Antwort posten, damit ich Ihre Antwort annehmen kann. –

+0

Haben Sie andere Probleme mit Ihrem Beispiel behoben? Zuerst sollten Sie den generischen Exception-Handler loswerden, der nur "Exception !!!!" ausgibt; Entfernen wird das tatsächliche Backtrace bereitstellen. (Wenn ich mit Python 2 arbeite, musste ich 'input' in' raw_input' ändern, ansonsten in willkürlichen Strings.) Auch 'vkey1' enthielt Syntaxfehler. Nachdem ich diese Fehler behoben hatte, ersetzte ich die unnötige Thread-Erstellung in 'textinit' durch einen einfachen Aufruf von' button0.set_label (str (ch)) 'und ersetzte den Aufruf durch 'GLib.idle_add() in gui2.textinit()'. gui2.textinit) ', Ihr Beispiel hat gut funktioniert. – user4815162342

Antwort

2

Die wahrscheinlichste Ursache für den Absturz ist, dass Ihr Code GTK-Code von anderen Threads als dem Thread aufruft, der die Hauptschleife ausführt, die documentation states nicht zulässig ist.

Um das Problem zu beheben, ersetzen Sie den Anruf von gui2.textinit() durch GLib.idle_add(gui2.textinit) (beachten Sie das Fehlen von Klammern nach textinit).

Mehrere Bemerkungen über den Code:

  • Die allgemeine Ausnahme-Handler Ausnahmen maskiert, die auftreten. Entfernen Sie es und Sie werden eine nützliche Rückverfolgung sehen, wenn etwas schief geht.

  • Wenn Sie unter Python 2 ausgeführt werden, möchten Sie wahrscheinlich input in raw_input ändern, andernfalls wird der Code bei jeder Eingabe gedrosselt, die kein gültiger Python-Ausdruck ist.

  • textinit erstellt ein Thread-Objekt, das nie einen tatsächlichen Thread ausführt. Beim Erben von threading.Thread muss man die Funktion run überschreiben, die im neuen Thread aufgerufen wird, sobald start() aufgerufen wird. Die Arbeit im Konstruktor macht nichts.

  • thread.start_new_thread ist ein Low-Level-API, die unter normalen Umständen nicht verwendet werden sollen, und dass zu _thread in Python degradierten 3. Statt thread.start_new_thread(fn,()) verwenden threading.Thread(target=fn), die die gleiche Bedeutung hat, und gibt auch ein Thread Objekt.