WingIde NameError

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
webglider
User
Beiträge: 11
Registriert: Samstag 17. Januar 2009, 11:01

Montag 9. Februar 2009, 11:25

Hallo zusammen,

ich versuche mit der WingIDE 101 ein simples Tkinter-Skript zu starten, erhalte dabei allerdings immer folgenden Fehler:

Code: Alles auswählen

Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)]
Type "help", "copyright", "credits" or "license" for more information.
>>> 
Evaluating Tkinter.py
Traceback (most recent call last):
  File "Z:\<string>", line 1, in <module>
  File "Z:\Tkinter.py", line 19, in <module>
NameError: name 'Tk' is not defined
Wenn ich den gleichen Code in der IDLE ausführe, erhalte ich keinen Fehler.

So sieht das Skript aus:

Code: Alles auswählen

from Tkinter import *

class App:

    def __init__(self, master):

        frame = Frame(master)
        frame.pack()

        self.button = Button(frame, text="QUIT", fg="red", command=frame.quit)
        self.button.pack(side=LEFT)

        self.hi_there = Button(frame, text="Hello", command=self.say_hi)
        self.hi_there.pack(side=LEFT)

    def say_hi(self):
        print "hi there, everyone!"

root = Tk()

app = App(root)

root.mainloop()
Muss in der WingIde noch etwas eingestellt werden? Wie kommt die IDE auf den Pfad Z:\...? Mein Skript liegt im Ordner G:\Entwicklung\PYT\Tkinter. Python ist in C:\Python25 installiert.

Jemand eine Idee?

Michael
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Montag 9. Februar 2009, 11:31

Gibt es denn auf deinem System ein Laufwerk Z:?
Du hast dein Skript nicht zufällig Tkinter.py genannt?
Benutzeravatar
webglider
User
Beiträge: 11
Registriert: Samstag 17. Januar 2009, 11:01

Montag 9. Februar 2009, 11:55

Ja, es gibt ein Laufwerk Z: und ja ich hab mein Skript auch noch Tkinter.py genannt...

Habe mein Skript umbenannt. Nun klappts. Allerdings kann ich es nicht sauber beenden, wenn ich es über die WingIDE gestartet habe. Sobald ich das Fenster versuche zu schließen, hängt sich die IDE und auch das Skript auf.

Mir scheint, da fehlt im Skript noch eine Prozedur zum sauberen beenden der Anwendung.

Edit: Mit dem Original-Beispiel aus der Python-Doku klappt dann auch das beenden einwandfrei, folgende Variante funktioniert:

Code: Alles auswählen

from Tkinter import *

class Application(Frame):
    def say_hi(self):
        print "hi there, everyone!"

    def createWidgets(self):
        self.QUIT = Button(self)
        self.QUIT["text"] = "QUIT"
        self.QUIT["fg"]   = "red"
        self.QUIT["command"] =  self.quit

        self.QUIT.pack({"side": "left"})

        self.hi_there = Button(self)
        self.hi_there["text"] = "Hello",
        self.hi_there["command"] = self.say_hi

        self.hi_there.pack({"side": "left"})

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

root = Tk()
app = Application(master=root)
app.mainloop()
root.destroy()
Danke für den Hinweis auf den Skriptnamen.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Montag 9. Februar 2009, 15:48

So ist es aber etwas schräg. Wenn root deine Tk-Instanz ist, dann sollte auf dieser Instanz auch die mainloop()-Methode aufgerufen werden. Ein destroy() braucht es überhaupt nicht.

In IDLE bleibt ein Tkinter-Programm auch ohne explizites mainloop() geöffnet, weil IDLE selbst ein Tkinter-Programm ist und die mainloop() schon läuft.

Noch ein paar Anmerkungen zum Quelltext:
Du scheinst eine uralte Doku zu verwenden, denn z.B. die Dictionary-Schreibweise in der pack()-Methode stammt noch aus der Zeit von Python 1.x, bevor Schlüsselwort-Parameter eingeführt wurden.

Deine Zeilen 8ff würde man so schreiben:

Code: Alles auswählen

self.quit = tk.Button(self, text="QUIT", fg="red", command=self.quit)
self.quit.pack(side=tk.LEFT)   # oder: side="left"
Und: Sternchenimporte gar nicht erst angewöhnen. Bewährt hat sich:

Code: Alles auswählen

import Tkinter as tk
Benutzeravatar
webglider
User
Beiträge: 11
Registriert: Samstag 17. Januar 2009, 11:01

Montag 9. Februar 2009, 19:42

Danke für deine Hinweise.

Gut wenn man schlechte Angewohnheiten gar nicht erst annimmt. Ist aber nicht so einfach, es existieren wirklich eine Menge mieser Dokumentationen im Netz. Ist aber keine Python-Besonderheit... Ist mir von einigen anderen Sprachen ebenfalls bestens bekannt.

Wenn ich allerdings deinen Sternchen-Tipp bezüglich des Imports befolge:

Code: Alles auswählen

import Tkinter as tk

class Application(Frame):
    def say_hi(self):
        print "hi there, everyone!"

    def createWidgets(self):
        self.QUIT = Button(self)
        self.QUIT["text"] = "QUIT"
        self.QUIT["fg"]   = "red"
        self.QUIT["command"] =  self.quit

        self.QUIT.pack({"side": "left"})

        self.hi_there = Button(self)
        self.hi_there["text"] = "Hello",
        self.hi_there["command"] = self.say_hi

        self.hi_there.pack({"side": "left"})

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

root = Tk()
app = Application(master=root)
app.mainloop()
root.destroy()
erhalte ich folgenden Fehler:

Code: Alles auswählen

NameError:name 'Frame' is not defined
?
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Montag 9. Februar 2009, 20:02

Der Sternchenimport hat alle Funktionen und Klassen von Tkinter in denselben Namensraum geladen, darum heißt die Klasse dann einfach nur ``Frame``, aber jetzt hast du sie in den Namensraum ``tk`` geladen (import as), folglich heißt es jetzt ``tk.Frame``. Das selbe gilt dann auch für alle anderen Funktionen und Klassen und Variablen und sonstiges, was von Tkinter stammt.
Benutzeravatar
webglider
User
Beiträge: 11
Registriert: Samstag 17. Januar 2009, 11:01

Montag 9. Februar 2009, 21:13

So sieht das Skript jetzt aus:

Code: Alles auswählen

import Tkinter as tk

class Application(tk.Frame):
    def say_hi(self):
        print "hi there, everyone!"

    def createWidgets(self):
        self.quit = tk.Button(self, text="QUIT", fg="red", command=self.quit)
        self.quit.pack(side=tk.LEFT)

        self.hi_there = tk.Button(self, text="Hello", command=self.say_hi)
        self.hi_there.pack(side=tk.LEFT)

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

root = tk.Tk()
app = Application(master=root)
app.mainloop()
Noch Verbesserungsvorschläge?
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Montag 9. Februar 2009, 21:15

mbzdega hat geschrieben:So sieht das Skript jetzt aus:

Code: Alles auswählen

import Tkinter as tk

class Application(tk.Frame):
    def say_hi(self):
        print "hi there, everyone!"

    def createWidgets(self):
        self.quit = tk.Button(self, text="QUIT", fg="red", command=self.quit)
        self.quit.pack(side=tk.LEFT)

        self.hi_there = tk.Button(self, text="Hello", command=self.say_hi)
        self.hi_there.pack(side=tk.LEFT)

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

root = tk.Tk()
app = Application(master=root)
app.mainloop()
Noch Verbesserungsvorschläge?
Application is ein imho unguenstiger Name. Und ich bins gewoehnt das die __init__ immer das erste is, aber vllt bin das nur ich.
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Montag 9. Februar 2009, 21:38

Ich würde name zustimmen: __init__ immer als erste Methode. Das ist eine gute Konvention und normalerweise geht man davon aus, dass es keine __init__()-Methode gibt, wenn am Anfang keine steht.

Auf jeden Fall gegenüber dem ersten Code deutlich besser jetzt.
Mit der mainloop() ist es immer noch nicht sauber und eigentlich bräuchte man für so ein kleines Progrämmchen auch noch keine Klasse. Einen Frame bzw. eine davon abgeleitete Klasse braucht man eigentlich auch nicht. Ich hätte es etwa so gemacht:

Code: Alles auswählen

import Tkinter as tk 

def say_hello():
    print "hi there"

root = tk.Tk()
tk.Button(root, text="Quit", fg="red", command=root.quit).pack(side="left")
tk.Button(root, text="Hello", command=say_hello).pack(side="left")
root.mainloop()
Was die Doku angeht, so gibt es zu Tkinter Brauchbares:
http://effbot.org/tkinterbook/tkinter-index.htm
http://infohost.nmt.edu/tcc/help/pubs/tkinter/
Antworten