Seite 1 von 1
Entry eingabe als Variable abfragen
Verfasst: Freitag 27. Mai 2011, 19:39
von Sans
Guten Abend.
Ich bin gerade dabei mich in Tkinter einzuarbeiten und wollte mir ein Programm schreiben, das ein primitives Zeichenprogramm imitiert. NUn bin ich dabei, die Funktion der Arbeitsbereichveränderung einzubauen. Dazu muss ich per Entry Widget die Möglichkeit geben Länge und Breite einzugeben.
Hier mein Code
Code: Alles auswählen
# -*- coding: cp1252 -*-
from math import *
from Tkinter import *
from random import *
root = Tk()
root.title(" Pinseln! 1.0! ")
#VARS
laenge=800
breite=300
#DAFS
def hello():
print("Hallo-oo!")
def linie():
xstart=randint(0,laenge)
ystart=randint(0,breite)
xende=randint(0,laenge)
yende=randint(0,breite)
liniebreite=randint(0,10)
Leinwand.create_line(xstart,ystart,xende,yende,width=liniebreite)
def nikolaushaus():
nikostartx=xstart=randint(0,laenge)
nikostarty=ystart=randint(0,breite)
liniebreite=randint(0,10)
Leinwand.create_line(width=liniebreite)
HIER WIRDS WICHTIG
#canvas ändern
def newcanvas():
laenge=Elaenge.get()
breite=Ebreite.get()
Leinwand.config(width=laenge, height=breite)
canvas.quit()
def canvaschange():
canvas=Tk()
canvas.title("Arbeitsbereich ändern")
Ebreite=Entry(canvas)
Ebreite.pack()
Elaenge=Entry(canvas)
Elaenge.pack()
bestaetigen=Button(canvas,text="Bestätigen", command=newcanvas)
bestaetigen.pack()
NUN WIRDS EIGENTLICH WIEDER EGAL
#CANVAS
Leinwand=Canvas(root, width=laenge, height=breite, bg="#333333")
Leinwand.grid(row=10,column=10)
#TOPMENU
topmenu=Menu(root)
#dateimenu
dateimenu=Menu(topmenu, tearoff=0)
dateimenu.add_command(label="Sag Hallo zu mir!", command=hello)
dateimenu.add_command(label="Arbeitsbereich ändern", command=canvaschange)
topmenu.add_cascade(label="Datei", menu=dateimenu)
#funktionsmenu
functionsmenu=Menu(topmenu, tearoff=0)
functionsmenu.add_command(label="Zeichne Linie", command=linie)
topmenu.add_cascade(label="Funktionen", menu=functionsmenu)
root.config(menu=topmenu)
root.mainloop()
Das Problem liegt in der Abfrage der Entryeinträge. Der Fehler ist folgender:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "E:\Informatik\pinseln1.0.py", line 33, in newcanvas
laenge=Elaenge.get()
NameError: global name 'Elaenge' is not defined
Ich weiß nicht so recht wo das Problem liegt. vllt kann mir jemand helfen.
mfg
Sans
Re: Entry eingabe als Variable abfragen
Verfasst: Freitag 27. Mai 2011, 20:05
von numerix
Aus der Tatsache, dass du diesen Fehler nicht selbst identifizieren kannst (sowie manchen anderen Aspekten, auf die vmtl. andere noch hinweisen werden), würde ich u.a. folgern, dass du den Bereich GUI (sprich Tkinter) zunächst einmal zurückstellen und dich mit den Python-Basics beschäftigen solltest, weil du sonst auf Dauer nicht glücklich damit wirst.
Der Grund für den Fehler ist der, dass der Bezeichner Elaenge (der so gar nicht heißen sollte, weil er die Python-Konventionen für Bezeichner verletzt) als lokaler Bezeichner in der Funktion canvaschange() definiert wird und du somit nicht aus einer anderen Funktion heraus darauf zugreifen kannst. Innerhalb der Funktion newcanvas() ist ein solcher Bezeichner unbekannt und im globalen Namensraum (d.h. außerhalb aller Funktionen) ebenfalls.
Mit Tkinter und get() hat das gar nichts zu tun.
Re: Entry eingabe als Variable abfragen
Verfasst: Freitag 27. Mai 2011, 22:21
von Sans
numerix hat geschrieben:Aus der Tatsache, dass du diesen Fehler nicht selbst identifizieren kannst (sowie manchen anderen Aspekten, auf die vmtl. andere noch hinweisen werden), würde ich u.a. folgern, dass du den Bereich GUI (sprich Tkinter) zunächst einmal zurückstellen und dich mit den Python-Basics beschäftigen solltest, weil du sonst auf Dauer nicht glücklich damit wirst.
Der Grund für den Fehler ist der, dass der Bezeichner Elaenge (der so gar nicht heißen sollte, weil er die Python-Konventionen für Bezeichner verletzt) als lokaler Bezeichner in der Funktion canvaschange() definiert wird und du somit nicht aus einer anderen Funktion heraus darauf zugreifen kannst. Innerhalb der Funktion newcanvas() ist ein solcher Bezeichner unbekannt und im globalen Namensraum (d.h. außerhalb aller Funktionen) ebenfalls.
Mit Tkinter und get() hat das gar nichts zu tun.
Danke für die Motivation^^ Ich finds immer unglaublich witzig, wenn man in Foren Fragen stellt und dann gesagt bekommt, dass das was man da gemacht hat nicht funktioniert. Ich mein das wusst ich auch vorher ?!? Für alle die den Thread mal über die SuFU finden: Gelöst wird das Problem mit
"Tut mir Leid", dass ich die dumme Frage gestellt habe. Die Pythonbasics habe ich grundsätzlich drauf. Da ich neu bei Tkinter war wusste ich aber nicht, dass für Widgets das gleiche gilt wie für normale Variablen. Auf irgendwelche "Python-Konventionen für Bezeichner" lege ich, abgesehen davon dass ich sie wohl kaum kenne, keinen Wert. Wie auch immer, das Problem habe ich nun gelöst, danke für den Hinweis, kann geclosed werden.
mfg
sans
Re: Entry eingabe als Variable abfragen
Verfasst: Samstag 28. Mai 2011, 08:55
von Leonidas
Also wenn du ``globals`` als gute Lösung ansiehst muss ich dir widersprechen und sagen dass, du Python-Basics noch nicht drauf hast. Aber du wirst auch nicht sonderlich kooperativ und interessiert dein Programm auszubessern, von daher...
Re: Entry eingabe als Variable abfragen
Verfasst: Samstag 28. Mai 2011, 16:22
von wuf
Hallo Sans
Obwohl der Dialog in unserem Forum manchmal verda.....mt rauh geführt wird lohnt es sich weiterhin dabei zu bleiben.
Hier dein Skript etwas abgeändert.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from functools import partial
from math import *
from random import *
import Tkinter as tk
#DAFS
def hello():
print("Hallo-oo!")
def linie(app):
xstart = randint(0, app.height)
ystart = randint(0, app.width)
xende = randint(0, app.height)
yende = randint(0, app.width)
liniebreite = randint(0, 10)
app.leinwand.create_line(xstart, ystart, xende, yende, width=liniebreite)
def nikolaus_haus(app):
niko_startx = xstart = randint(0,app.height)
niko_starty = ystart = randint(0,app.width)
liniebreite = randint(0, 10)
app.leinwand.create_line(width=liniebreite)
def new_canvas(app, dialog, *args):
"""canvas ändern"""
width = app.entry_canvas_width.get()
height = app.entry_canvas_height.get()
app.leinwand.config(width=width, height=height)
dialog.destroy()
# canvas.quit()
def canvas_change(app):
"""Aendere Arbeitsbereich"""
canvas_change_dialog = tk.Toplevel()
canvas_change_dialog.title("Arbeitsbereich ändern")
dialog_frame = tk.Frame(canvas_change_dialog, padx=5, pady=5)
dialog_frame.pack()
label_width = tk.Label(dialog_frame, text='Leinwand-Breite:')
label_width.grid(column=0, row=0, padx=4)
app.entry_canvas_width = tk.Entry(dialog_frame, bd=1, highlightthickness=0,
bg='white')
app.entry_canvas_width.grid(column=1, row=0, pady=5)
app.entry_canvas_width.insert(0, app.width)
app.entry_canvas_width.focus_set()
label_height = tk.Label(dialog_frame, text='Leinwand-Höhe:')
label_height.grid(column=0, row=1, padx=4)
app.entry_canvas_height = tk.Entry(dialog_frame, bd=1, highlightthickness=0,
bg='white')
app.entry_canvas_height.grid(column=1, row=1, pady=5)
app.entry_canvas_height.insert(0, app.height)
cmd_new_canvas = partial(new_canvas, app, canvas_change_dialog)
bestaetigen = tk.Button(dialog_frame, text="Bestätigen", bd=1,
command=cmd_new_canvas)
bestaetigen.grid(column=0, row=3, columnspan=2, pady=5)
bestaetigen.bind('<Return>', cmd_new_canvas)
root = tk.Tk()
root.title("Pinseln! 1.0!")
app = root
#VARS
app.width=800
app.height=300
#CANVAS
app.leinwand = tk.Canvas(root, width=app.width, height=app.height,
bg='steelblue3') #"#333333")
app.leinwand.grid(row=10,column=10)
#TOPMENU
topmenu = tk.Menu(root)
#dateimenu
dateimenu = tk.Menu(topmenu, tearoff=0)
dateimenu.add_command(label="Sag Hallo zu mir!", command=hello)
cmd_canvas_change = partial(canvas_change, app)
dateimenu.add_command(label="Arbeitsbereich ändern", command=cmd_canvas_change)
topmenu.add_cascade(label="Datei", menu=dateimenu)
#funktionsmenu
functionsmenu = tk.Menu(topmenu, tearoff=0)
cmd_line = partial(linie, app)
functionsmenu.add_command(label="Zeichne Linie", command=cmd_line)
topmenu.add_cascade(label="Funktionen", menu=functionsmenu)
root.config(menu=topmenu)
root.mainloop()
Das Skript ist natürlich nur ein grober Wurf und kann jederzeit verfeinert und verbessert werden.
Gruß wuf

Re: Entry eingabe als Variable abfragen
Verfasst: Montag 30. Mai 2011, 14:10
von Sans
Leonidas hat geschrieben:Also wenn du ``globals`` als gute Lösung ansiehst muss ich dir widersprechen und sagen dass, du Python-Basics noch nicht drauf hast. Aber du wirst auch nicht sonderlich kooperativ und interessiert dein Programm auszubessern, von daher...
Im Gegensatz, ich bin sehr wohl gewillt, mein Programm auszubessern. Ich will an diesem Projekt lernen, dafür muss ich es bessern. Ich verstehe nicht warum man hier immer angegangen wird als ob man irgendwen mit seinen Fragen ärgern will. Was spricht gegen global? Mag seind ass das nicht die beste Lösung ist, aber ich würde dann gern auch wissen warum

Die Pythonbasics beherrsche ich nicht perfekt, das gebe ich zu, allerdings habe ich Python auch mehr im "learning-by-doing" Stil gelernt.
wuf hat geschrieben:Hallo Sans
Obwohl der Dialog in unserem Forum manchmal verda.....mt rauh geführt wird lohnt es sich weiterhin dabei zu bleiben.
Hier dein Skript etwas abgeändert.
Das Skript ist natürlich nur ein grober Wurf und kann jederzeit verfeinert und verbessert werden.
Gruß wuf

Das ist doch endlich mal was, womit ich was anfangen kann! Leider würde ich nur spekulieren was da jetzt was bedeutet, deshalb währe ich dir dankbar wenn du das auskommentzieren könntest
danke
sans
Re: Entry eingabe als Variable abfragen
Verfasst: Montag 30. Mai 2011, 14:33
von EyDu
Sans hat geschrieben:Was spricht gegen global? Mag seind ass das nicht die beste Lösung ist, aber ich würde dann gern auch wissen warum

Da gibt es gleich mehrere gute gründe: Zum einen sorgst du mit `global` dafür, dass viele, an sich unabhängige Teile, gekoppelt werden. Das möchtest man, zum Beispiel aus Gründen der Wiederverwendbarkeit, nur ungerne haben. Du die Koppelung ergibt sich direkt ein weiteres Problem: der Programmfluß ist nur noch sehr schwer bis gar nicht mehr nachvollziehbar, da an allen Ecken und Enden etwas am globalen Zustand verändert wird. Damit wird eine Wartbarkeit der Programm irgendwann unmöglich. Ein weiterer Nachteil ist, dass du dir den Namensraum mit vollkommen unnötigen Namen zumüllst. Das ist meistens nicht so schlimm, kann aber sehr unübersichtlich werden. Besonders dann, wenn du nicht weißt woher der Name kommt und du ggf. erst im Code danach suche musst. Wann immer du also in die Verlegenheit kommen solltest `global` zu benutzen, dann denke darüber nach, wie du das Problem mit Parametern und Rückgabewerten lösen kannst. Als Faustregel für Namen: halte sie so lokal wie möglich.
Re: Entry eingabe als Variable abfragen
Verfasst: Montag 30. Mai 2011, 21:03
von wuf
Hallo Sans
Hier noch zwei Änderungen an meinem Skript:
a) Damit werden die Random-Linien sicher innerhalb der verfügbaren Canvasfläche gezeichnet.
Code: Alles auswählen
def linie(app):
xstart = randint(0, app.width)
ystart = randint(0, app.height)
xende = randint(0, app.width)
yende = randint(0, app.height)
liniebreite = randint(0, 10)
app.leinwand.create_line(xstart, ystart, xende, yende, width=liniebreite)
b) Damit werden die Breite und Höher der Canvas gespeichert damit sie beim nächsten Aufruf des Änderungsdialoges in die Eingabefelder übernommen werden.
Code: Alles auswählen
def new_canvas(app, dialog, *args):
"""canvas ändern"""
width = app.entry_canvas_width.get()
height = app.entry_canvas_height.get()
app.leinwand.config(width=width, height=height)
app.width = int(width)
app.height = int(height)
dialog.destroy()
Gruß wuf
