Entry eingabe als Variable abfragen

Fragen zu Tkinter.
Antworten
Sans
User
Beiträge: 19
Registriert: Dienstag 28. September 2010, 16:31

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
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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.
Sans
User
Beiträge: 19
Registriert: Dienstag 28. September 2010, 16:31

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

Code: Alles auswählen

global Ebreite
global Elaenge
...
"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
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Sans

Obwohl der Dialog in unserem Forum manchmal verda.....mt rauh geführt wird lohnt es sich weiterhin dabei zu bleiben. :wink:

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 :wink:
Take it easy Mates!
Sans
User
Beiträge: 19
Registriert: Dienstag 28. September 2010, 16:31

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. :wink:

Hier dein Skript etwas abgeändert.

Das Skript ist natürlich nur ein grober Wurf und kann jederzeit verfeinert und verbessert werden.

Gruß wuf :wink:
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
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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.
Das Leben ist wie ein Tennisball.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

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 :wink:
Take it easy Mates!
Antworten