Entry-Widget

Fragen zu Tkinter.
Antworten
titus2000
User
Beiträge: 11
Registriert: Donnerstag 29. September 2011, 13:49

Hey,
in einem Schulprojekt ist aufgegeben worden, einen Rouletttisch mit dem Turtle-Modul zu programmieren. Da ich jedoch mit richtigen Schaltflächen arbeiten möchte, habe ich mich entschlossen tkinter zu lernen.
Ich verwende Python 3.2.1 und verzweifle langsam an diesem Projekt. Ich habe es zwar geschafft Schaltflächen aufzusetzen einen Ball zu programmieren der sich Physikalisch einigermaßen stimmig bewegt, doch wenn es um die Buttons geht sehe ich das Ziel in immer weitere Ferne rücken.


Code: Alles auswählen

def Einsatzerhöhung(event):

        Einsatzaufforderung=Label(text='Gib deinen Einsatz ein für' )
        Einsatzaufforderung.place(x=270,y=180)
        a=StringVar()
        Einsatz=Entry(bg="#00aa33", textvariable=a)
        Einsatz.insert(END,"z.B. 1.40, Mit Eingabe bestätigen!")
        Einsatz.place(x=270,y=200)       
        print(a)
        okbutton=Button(text="Setzen")
        okbutton.place(x=390,y=200)
        okbutton.bind('<ButtonRelease>',Einsatzberechnung)

def Einsatzberechnung(event): 
        print(a)
Alle Hilfen die ich gefunden habe sagen, dass ich einfach Einsatz.get() nutzen soll, doch dann wird mir erzählt, ich hätte Einsatz nicht definiert.

In Einsatzberechnung soll mit der Variabel a weitergerechnet werden. Als Platzhalter für eine Weiterverwendung habe ich jetzt einen Printbefehl genommen. Jedoch funktioniert dies nicht. Auch diese Varibal habe ich angeblich nicht definiert.

Ich bin für jede Hilfe dankbar!

Alex
deets

In Einsatzberechnung hast du a ja auch nicht definiert - das ist ja keine globale Variable, sondern die ist lokal zu Einsatzerhoehung.

Wenn du in Einsatzberechnung an den Wert von a kommen moechtest, musst du irgendwie darauf zugreifen koennen. Eine Moeglichkeit waeren eben globale variablen. Ein

Code: Alles auswählen

global a
in Einsatzerhoehung sollte genuegen, damit du das in Einsatzberechnung referenzieren kannst.

Aber besser noch ist, sowas durch entweder Objektorientierung oder funktionale Programmierung zu erreichen. ZB indem du partial benutzt:

Code: Alles auswählen

from functools import partial
from tkinter import *


def callback(v, event):
    print(v.get())

def setup():
    root = Tk()
    a = StringVar()
    Einsatz = Entry(root, bg="#00aa33", textvariable=a)
    Einsatz.insert(END,"z.B. 1.40, Mit Eingabe bestätigen!")
    Einsatz.pack()
    okbutton=Button(root, text="Setzen")
    okbutton.pack()
    okbutton.bind('<ButtonRelease>',partial(callback, a))
    w = Label(root, text="Hello, world!")
    w.pack()
    root.mainloop()


setup()
BlackJack

@titus2000: Du hast den Namen `a` in `Einsatzerhöhung()` lokal gebunden. Den gibt es also nur innerhalb der Funktion und nur für die Dauer des Programmablaufs innerhalb der Funktion. Das ist ja gerade ein Sinn von Funktionen, dass man Code und Namen darin kapseln kann, damit das Programm nicht mit globalen Namen überfrachtet wird und man überall aufpassen muss, dass man einen Namen nimmt, der nicht an anderer Stelle schon für etwas anderes verwendet wird.

Du müsstest den Wert beim Aufruf von `Einsatzberechnung()` als Argument übergeben. Beziehungsweise in diesem Fall übergeben lassen. Da Du für die Schaltfläche nur eine Funktion übergeben kannst, musst Du eine Funktion übergeben die `Einsatzberechung()` mit dem Wert von `a` übergibt, wenn man sie aufruft. So eine Funktion kannst Du aus `Einsatzberechung` und `a` zum Beispiel mit `functools.partial()` dynamisch erstellen.

Du solltest bei Schaltflächen übrigens nicht das '<ButtonRelease>'-Ereignis binden, sondern das `command`-Argument von `Button()` verwenden.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi titus2000

Hier noch eine Code-Variante zum herumspielen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial
import tkinter as tk

def Einsatzberechnung(a, *args):
    print('Einsatz:',a.get())

app_win = tk.Tk()
#app_win.geometry('300x300')
app_win.title('Einsatz-Dialog')

haupt_rahmen = tk.Frame(app_win)
haupt_rahmen.pack(expand=True, padx=4, pady=4)

einsatz_aufforderung = tk.Label(haupt_rahmen,
    text='Gib deinen Einsatz ein für:')
einsatz_aufforderung.pack(anchor=tk.N+tk.W, padx=4)

einsatz_rahmen = tk.Frame(haupt_rahmen)
einsatz_rahmen.pack(anchor=tk.N+tk.W)

a = tk.StringVar()
einsatz = tk.Entry(einsatz_rahmen, fg='white', bg="#00aa33", textvariable=a,
    highlightthickness=0)
einsatz.pack(side=tk.LEFT, padx=4)
a.set("z.B. 1.40, Mit Eingabe bestätigen!")

ok_button = tk.Button(einsatz_rahmen, text="Setzen",
    command=partial(Einsatzberechnung, a))
ok_button.pack(side=tk.LEFT, padx=4)

app_win.mainloop()
Gruß wuf :wink:
Take it easy Mates!
titus2000
User
Beiträge: 11
Registriert: Donnerstag 29. September 2011, 13:49

Moin,

Danke für die schnellen Antworten. Du hast mir wirklich sehr weitergeholen. Doch stehe ichs chon wieder vor dme nächsten Problem und will keinen neuen Thread auf machen.

Wieder scheint eine Variabel nicht deklariert worden zu sein.

Code: Alles auswählen

def Interface()
      (...)
      wert=tk.Label(text=gesamteinsatz)
      wert.pack()    

def Einsatzberechnung_eins(a, *args):
      Gesamteinsatz()
      wert.configure(text=gesamteinsatz)
      
Ich möchte in meinem Roulettespiel eine Anzeige anbringen, in der das gesetzte Geld eingeblendet wird. Dabei werden die Werte der einzelnen Einsätze in Gesamteinsatz() zusammengezählt. Im Label(wert) möchte ich dann diesen Gesamteinsatz anzeigen lassen. Ich habe versucht wert global zu definieren, doch scheint dies nciht möglich. Wie geht man da am besten vor?

Lg Alex
BlackJack

@titus2000: Am besten schiebt man die GUI erst einmal beiseite und lernt die Grundlagen von Funktionen und Gültigkeitsbereichen von Namen in Python. Wenn Du das kannst, würdest Du nicht behaupten es würde nicht funktionieren den Namen als ``global`` zu deklarieren. Und danach schaut man sich objektorientierte Programmierung an. Denn ``global`` geht zwar, ist aber keine gute Programmierung. Insgesamt stellt sich dann aber die Frage wie viel Zeit Du hast, und wie schnell Du lernst, und ob Du nicht erst einmal die eigentliche Aufgabe löst, bevor Du versuchst zusätzliche Funktionalität zu implementieren. Daran kannst Du Dich ja auch noch setzen wenn die Grundfunktionalität fertig ist, und noch Zeit übrig ist, dass auszubauen.
titus2000
User
Beiträge: 11
Registriert: Donnerstag 29. September 2011, 13:49

Moin,
mein Interface steht bereits, doch habe ich mir einige Sachen überlegt, die nicht fehlen dürfen, damit ich zufrieden bin.
Meine Informatiklehrerin verlangt nicht dieses Programm zu schreiben. Ihr reicht es, dass wir einen Roulettetisch mit der Turtle schreiben und den rest in die Console tippen, doch das finde ich unnütz und langweilig.
So bin ich auf tkinter gekommen.
Ich bin schon stolz soweit überhaupt gekommen zu sein. Denn ich muss mir jetzt schon seit 3 Tagen alles selbst aneignen.

Ich weiß ja auch was ich will und wie es eigentlich aufgebaut sein müsste, doch ist die Syntax für mich größtenteils sehr fremd. Die Erklärungen im Internet helfen mir nur bedingt weiter.

Das global nicht sauber ist wusste ich auch, doch schien es mir das einfachste ohne großartige classen zu basteln.
Am liebsten würde ich einfach

global wert

schreiben, doch das ist scheinbar die falsche Syntax und, da google mir nicht weiterhilft bin ich hier. Die Tipps die mir hier bereits gegeben worden sind und anderen bereits gegeben wurdne haben mir schon sehr viel weiter geholfen als die Tutorien im Internet.

Lg Alex
BlackJack

@titus2000: ``global name`` ist schon die richtige Syntax und ich sehe hier auch nirgends ein Problem mit der Syntax, sondern eher dass Du die Semantik noch nicht überall verstanden hast. IMHO ist das komplex genug, dass man es nicht ordentlich ohne Klassen lösen kann. Von ``global`` müsste mehrfach gebrauch machen und so etwas sollte man sich IMHO gar nicht angewöhnen. Saubere Programme haben keinen Quelltext auf Modulebene ausser Konstanten-, Funktions- und Klassendefinitionen und schon gar kein ``global``.
titus2000
User
Beiträge: 11
Registriert: Donnerstag 29. September 2011, 13:49

Moin,

die Klassen sind denke icha uch sehr schön und machen das ganze übersichtlich, doch kann ich diese nicht verwenden, da ich die Syntax nicht finde um meine Fenster nicht einstürzen zu lassen. Mit f=tk.Tk() habe ich mein Master-Fenster deklariert und wenn ich Fenster außerhalb der Funktion mit dieser Zeile hab, kann ich keine Fenster mehr erstellen, da wenn ich f.mainloop() ans ende setzte kein Interface mehr habe.
BlackJack

@titus2000: Es gibt keine Syntax die Fenster einstürzen lässt. Die Syntax zum Definieren von Klassen findet sich zum Beispiel im Tutorial in der Python-Dokumentation.

Was soll es bedeuten dass Du kein Interface mehr hast wenn Du `f.mainloop()` ausführst? Und was meinst Du mit Fenstern ausserhalb der Funktion mit der Zeile? Es darf im Programmablauf grundsätzlich nur *ein* Exemplar von `Tk` geben! Wenn Du weitere Fenster erstellen möchtest, musst Du `Toplevel` dafür verwenden!
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi titus2000

Hier ist noch mehr Code zum herumspielen:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial
import tkinter as tk

def Einsatzberechnung():
    
    try:
        einsatz_wert = float(einsatz_var.get())
        app_win.einsatz_total += einsatz_wert
        wert.config(fg='darkolivegreen')
        wert_var.set("%.2f" % app_win.einsatz_total)
    except:
        wert.config(fg='red')
        wert_var.set('Falscheingabe')
        
app_win = tk.Tk()
#app_win.geometry('300x300')
app_win.title('Einsatz-Dialog')

app_win.einsatz_total = 0.00

haupt_rahmen = tk.Frame(app_win)
haupt_rahmen.pack(expand=True, padx=4, pady=4)

einsatz_aufforderung = tk.Label(haupt_rahmen,
    text='Gib deinen Einsatz ein für:')
einsatz_aufforderung.pack(anchor=tk.N+tk.W, padx=4)

einsatz_rahmen = tk.Frame(haupt_rahmen)
einsatz_rahmen.pack(anchor=tk.N+tk.W)

einsatz_var = tk.StringVar()
einsatz = tk.Entry(einsatz_rahmen, fg='white', bg="#00aa33",
    textvariable=einsatz_var, highlightthickness=0)
einsatz.pack(side=tk.LEFT, padx=4)
einsatz_var.set("z.B. 1.40, Mit Eingabe bestätigen!")

ok_button = tk.Button(einsatz_rahmen, text="Setzen",
    command=Einsatzberechnung)
ok_button.pack(side=tk.LEFT, padx=4)

wert_var = tk.StringVar()
wert = tk.Label(haupt_rahmen, textvariable=wert_var, fg='darkolivegreen',
    font=('helvetica', 20, 'bold'))
wert.pack(anchor=tk.N+tk.W, padx=4)
wert_var.set("%.2f" % app_win.einsatz_total)

app_win.mainloop()
Gruß wuf :wink:
Take it easy Mates!
Antworten