Seite 1 von 1

Skript läuft nur, wenn ich es in der IDE starte (Mod thread)

Verfasst: Sonntag 6. Februar 2011, 16:51
von ChristofArn
Bitte entschuldigt, falls dieses Problem schon besprochen wurde. Es geht um das Modul "thread", aber wenn ich nach "Thread" suche, gibt es viel zu viele Suchergebnisse, die damit nichts zu tun haben.

Ich experimentiere ein bisschen, u.a. mit Threads. Folgendes Skript läuft, wenn ich es von von der Python IDE "Eric" aus starte tiptop. Wenn ich das Skript aber von einer Konsole aus starte, geht es nicht. Woran liegt das?

Skript:

#!/usr/bin/python

import thread
from Tkinter import *

class Projektor(object):
def __init__(self):
self.fenster = Tk()
self.fenster.mainloop()

def starter():
p = Projektor()

thread.start_new_thread(starter, ())



Wenn ich das Skript von Eric aus starte, zeigt es brav ein Fenster ohne nichts an.
Wenn ich das Skript von der Konsole aus starte, kriege ich diese nicht sehr hilfreiche Fehlermeldung:

Unhandled exception in thread started by
Error in sys.excepthook:

Original exception was:

Also, damit man mich richtig verstehen kann: Nach den Doppelpunkten ist einfach leer. Kann mir da jemand weiterhelfen?

Schönen Abend!

Christof


PS: Wenn ich das Skript so abändere, dass es ohne thread gemacht ist, läuft es auch wenn ich es von der Konsole aus starte. Darum denke ich, hängt es mit dem Modul "thread" zusammen. So läuft es tiptop:

#!/usr/bin/python

import thread
from Tkinter import *

class Projektor(object):
def __init__(self):
self.fenster = Tk()
self.fenster.mainloop()

def starter():
p = Projektor()

starter()

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Sonntag 6. Februar 2011, 17:32
von Xynon1
1. Willkommen im Forum
2. Nutze bei Code Beispielen bitte die dafür vorgesehenen Python-Tags
3. GUIs vertragen sich recht selten mit verschiedenen Threads, da sie immer ihre eigene Mainloop haben.
4. Es ist sehr unklug in Tkinter überhaupt eine Mainloop an ein Objekt zu binden, es sollte Grundsätzlich nur eine Mainloop existieren und diese in der Main - das selbe gilt für ein Tkinter.Tk-Widget

Dies ist so ziemlich das schlechteste Beispiel um in Tkinter mit Threads arbeiten zu können, was willst du eigentlich machen? - Um mit Threads einfach nur zu üben solltest du die GUI raushalten.

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Sonntag 6. Februar 2011, 18:12
von BlackJack
Anstelle von `thread` sollte man das `threading`-Modul verwenden. Da wird in der Dokumentation auch drauf hingewiesen.

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Montag 7. Februar 2011, 11:38
von ChristofArn
Grossen Dank für die raschen Reaktionen! Das ist ja super.

@Xynon1:
1. Danke!
2. Merk ich mir, sorry, hätte ich wissen können.
3. Schade
4. Da bin ich nicht sicher, ob ich Dich richtig verstehe. Heisst das: Besser keine mainloop innerhalb einer Klasse/einem Objekt? Die Tk-Beispiele, die ich im Python-Buch von Michael Weigend gefunden habe, sind aber immer so. Oder verstehe ich Dich falsch?

PS: Machen will ich eine Diashow, die immer mehrere Bilder gleichzeitig anzeigt und diese zufallsmässig und zeitgesteuert laufend gegen andere austauscht. - Bin aber auch sonst dabei, mit Python zu experimentieren. Django läuft jetzt auf meinem Server und eine erste dynamische Seite mit spezieller Kalenderfunktion habe ich dort hingekriegt.

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Montag 7. Februar 2011, 11:48
von BlackJack
@ChristofArn: Für die Diaschau brauchst Du keine Threads. Das Bilder austauschen kannst Du mittels der `after()`-Methode, die es auf jedem Widget gibt, zeitverzögert ausführen lassen.

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Montag 7. Februar 2011, 12:04
von Xynon1
Dieses Buch kenne ich leide nicht, aber kurze Grundlage. Du brauchst in Tkinter nur eine einzige "tkinter.Tk" Instanz, diese wird meist als "root" oder "main" bezeichnet. Diese hat ausschließlich in deiner Main im Programm zu stehen und sollte auch als einzige Instanz die "mainloop" ausführen.

Kurzes Beispiel:

Code: Alles auswählen

import Tkinter as tkinter

if __name__ == "__main__":
    root = tkinter.Tk()
    lb = tkinter.Label(root, text="Hello World")
    lb.pack() 
    #...
    root.mainloop()
Alles was du an Widgets auf deinem Hauptfenster brauchst sollte nun direkt oder indirekt auf "root" gelegt werden. Sollte man ein zweites Fenster benötigen, so sollte man das "tkinter.Toplevel" Widget nutzen.

Eine Ableitung von einem Widget, wenn man sich an die Tkinter API hält könnte zB. so aussehen.

Code: Alles auswählen

import Tkinter as tkinter

class LabelEntry(tkinter.Frame):
    
    def __init__(self, master, text="", cnf=()):
        tkinter.Frame.__init__(self, master, cnf)
        self._value = ""
        self._control = tkinter.StringVar()
        
        self.label = tkinter.Label(self, text=text.title())
        self.label.pack(side="left")
        
        options = {"textvariable" : self._control,
                   "justify" : "right",
                   "width" : 30,
                   "relief" : "flat"}
        self.entry = tkinter.Entry(self, options)
        self.entry.bind("<FocusIn>", self._focus_in)
        self.entry.bind("<Escape>", self._escape)
        self.entry.bind("<Any-Enter>", self._forget_focus)
        self.entry.pack(side="right")
    
    def _focus_in(self, event=None):
        self._value = self._control.get()
        
    def _forget_focus(self, event=None):
        self.master.focus_set()
        self.master.update()
    
    def _escape(self, event):
        self.control.set(self._value)
        self.forget_focus()
        
    def get(self):
        return self._control.get()

    def set(self, value):
        self._control.set(value)


if __name__ == "__main__":
    root = tkinter.Tk()
    le = LabelEntry(root, "Eingabe:")
    le.pack()
    root.mainloop()
Und deine Diashow sollte auch ohne Threads funktionieren, sie dir mal die "after"-Methode an.

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Dienstag 8. Februar 2011, 11:07
von ChristofArn
Super, herzlichen Dank für die Hilfe. Ich habe es nun mit der Methode "after" gemacht und es klappt wunderbar. Damit kann ich auf threads verzichten.

Es ist toll, in einem Forum eine solche Unterstützung so rasch zu kriegen.

Noch eine Frage zum Schluss: Gibt es irgendwelche Ideen, warum das Skript gelaufen ist, wenn ich es von Eric aus gestartet habe - und sonst nicht?

Re: Skript läuft nur, wenn ich es in der IDE starte (Mod thr

Verfasst: Dienstag 8. Februar 2011, 11:22
von Xynon1
Ich würde jetzt einfach mal behaupten, das Eric die Exception ignoriert hat.
In PyDev geht es genauso wenig wie im Terminal.
und wenn man es von IDLE aus startet, wird die Exception meist ignoriert, aber da IDLE eine Tkinter Application ist und eine eigene Mainloop besitzt wo durch es manchmal wenn man Tkinter davon aus startet ein paar miese Problem gibt, führte das in ungefähr 2 von 3 Startversuchen zum Absturz von IDLE.