Eingabefelder je nach Gebrauch hinzufügen und löschen

Fragen zu Tkinter.
Antworten
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Also, ich probiere gerade ein Zufallsgenerator zu erstellen. Man soll zB in verschiedene Eingabefelder verschiedene Namen eingeben, und wenn man dann auf "Go" klickt, soll das Programm zufällig einen Namen davon nennen. Allerdings ist die Anzahl der Eingabefelder dann ja jedesmal anders, und ich wollte das man dort einstellen kann wie viele man haben möchte. Ich habe es hiermit mal versucht:

Code: Alles auswählen

while a>0:
		x = Entry(window)
		x.pack()
		a=a-1
		return
a ist hierbei die Anzahl der Eingabefelder.
Das Poblem ist aber das man hierbei die Felder nicht mehr löschen kann. Kann mir vielleicht jemand andere Möglichkeiten nennen oder passende docs geben?
BlackJack

@secretwz: Aus der ``while``-Schleife sollte man eine ``for``-Schleife machen. Und `a` und `x` sind in diesem Fall keine besonders aussagekräftigen Namen.

Docs: Die Python-Dokumentation samt enthaltenem Tutorial. Das wird unter anderem erklärt was Listen sind. Da kann man Objekte ablegen, die man später noch braucht. Zum Beispiel um Methoden auf ihnen aufzurufen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

BlackJack hat geschrieben:@secretwz: Aus der ``while``-Schleife sollte man eine ``for``-Schleife machen.
Oder gleich ein if-Statement. Das return macht es möglich ^^
Das Leben ist wie ein Tennisball.
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Das return gehört eigentlich garnicht mehr dahin^^ Hat ja sonst nicht viel Sinn.
Allerdings kann man mit der for-Schleife doch genauso wenig wieder Felder löschen oder?

Gibt es evtl. ein Befehl mit dem man das Programm wieder auf Anfang setzt? Weil wenn ich das Programm starte und "4" eingebe, entstehen 4 neue Eingabefelder. Wenn ich dann nochmal "3" eingebe, entstehen weitere 3 Felder. Ich möchte aber dass die anderen 4 davor gelöscht werden und es dann 3 und nicht insgesamt 7 sind.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

secretwz hat geschrieben:Gibt es evtl. ein Befehl mit dem man das Programm wieder auf Anfang setzt? Weil wenn ich das Programm starte und "4" eingebe, entstehen 4 neue Eingabefelder. Wenn ich dann nochmal "3" eingebe, entstehen weitere 3 Felder. Ich möchte aber dass die anderen 4 davor gelöscht werden und es dann 3 und nicht insgesamt 7 sind.
Nein gibt es nicht (würde ja auch keinen Sinn machen, so ein Befehl). Du musst die Felder selbst löschen und neu anlegen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Ich habe jetzt mal x.destroy() ausprobiert und es funktionierte. Ein Eingabefeld wurde gelöscht. Habe dies jetzt ins Programm eingebaut allerdings funktioniert das nicht so. Es wird irgendwie nichts gelöscht wenn neu_entry vorhanden ist... Auch wenn ich nach dem else: print "aa" passiert nichts, die neuen entry-Felder werden immer wieder hinzugefügt.

Code: Alles auswählen

from Tkinter import *
window = Tk()
entry1 = Entry(window)
entry1.pack()

def anzahl():
	anzahl_entry = entry1.get()
	anzahl_entry = float(anzahl_entry)
	try: 
		neu_entry
	except:
		while anzahl_entry>0:
			neu_entry = Entry(window)
			neu_entry.pack()
			anzahl_entry=anzahl_entry-1
        else:
		neu_entry.destroy()	
		
button1=Button(window, text="Go!", command=anzahl)
button1.pack()
window.mainloop()
Leoniads hat geschrieben:Du musst die Felder selbst löschen und neu anlegen.
Also das ganze Programm beenden und neustarten?[/code]
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo secretwz

Hier ein Grundgerüst zum herumspielen:

Code: Alles auswählen

import Tkinter as tk
from random import randint

def anzahl():
    #~~ Bestimme eine zufaellige Anzahl von Entry-Objekte
    num_entry_obj = randint(1,9)

    #~~ Entferne bestehende Entry-Objekte
    if window.entry_obj_list != ():
        for entry_obj in window.entry_obj_list:
            entry_obj.destroy()
        window.entry_obj_list = list()

    #~~ Erzeuge Entry-Objekte
    for obj in xrange(num_entry_obj):
        entry_obj = tk.Entry(entry_frame, text='', width=10, bg='white')
        entry_obj.pack(side='top', pady=1)

        window.entry_obj_list.append(entry_obj)

window = tk.Tk()

#~~ Sammelliste fuer Entry-Objekte
window.entry_obj_list = list()

#~~ Rahmen fuer die Aufnahme der Entry-Widgets
entry_frame = tk.Frame(window)
entry_frame.pack(side='top')

#~~ Rahmen fuer die Aufnahme der Schaltflaechen
button_frame = tk.Frame(window)
button_frame.pack()

button1 = tk.Button(button_frame, text="Go!", width=10, command=anzahl)
button1.pack()

window.mainloop()
Gruss wuf :wink:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Meine Variante:

Code: Alles auswählen

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

####

import Tkinter as tk

####

class Gui(object):

  def __init__(self, n=3):

    self.root = tk.Tk()
    self.nvar = tk.StringVar()

    self.go_frame = tk.LabelFrame(self.root, text='How much?')
    self.go_entry = tk.Entry(self.go_frame, textvariable=self.nvar, width=30)
    self.go_entry.pack(padx=10, pady=7, fill=tk.X)
    self.go_frame.pack(padx=4, pady=8, fill=tk.X)
    self.go_but = tk.Button(self.go_frame, text='GO', command=self.new_entries)
    self.go_but.pack(fill=tk.X)
    self.make_entries(self.root, n)


  def make_entries(self, parent, n):
    
    self.eframe = tk.LabelFrame(parent)
    self.svars = [tk.StringVar() for _ in xrange(n)]
 
    self.entries = []
    for i, s in enumerate(self.svars):
      s.set(i)
      entry = tk.Entry(self.eframe, textvariable=s)
      entry.pack(fill=tk.BOTH, expand=True)
      self.entries.append(entry)
      
    self.eframe.pack()

    
  def new_entries(self):

    try:
      n = int(self.go_entry.get())
    except ValueError:
      n = 5
    n = min(n, 16)

    for e in self.entries:
      e.destroy()

    self.eframe.destroy()
    self.make_entries(self.root, n)


  def run(self):

    self.root.mainloop()

####

if __name__ == '__main__':

  Gui(7).run()
:wink:
yipyip
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo secretwz!

Falls eine mögliche Anzahl vorgegeben ist, könnte es auch mit grid, pack und grid_forget, pack_forget gehen.

Gruß Frank
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Vielen Dank für eure Antworten ;)

@wuf
ich habe deine version mal übernommen und nur verändert, dass man selbst die zahl eingibt. Funktioniert auch super! Danke!
Allerdings habe ich jetzt Probleme beim erstellen des Zufallsgenerators:

Code: Alles auswählen

from Tkinter import *
from random import randint

window = Tk()
entry1 = Entry(window)
entry1.pack()

def anzahl():
    #~~ Bestimme eine zufaellige Anzahl von Entry-Objekte
    num_entry_obj = entry1.get()
    num_entry_obj = float(num_entry_obj)
    test.append(num_entry_obj)

    #~~ Entferne bestehende Entry-Objekte
    if window.entry_obj_list != ():
        for entry_obj in window.entry_obj_list:
            entry_obj.destroy()
        window.entry_obj_list = list()

    #~~ Erzeuge Entry-Objekte
    for obj in xrange(num_entry_obj):
        entry_obj = Entry(entry_frame, text='', width=10, bg='white')
        entry_obj.pack(side='top', pady=1)
	test.append(entry_obj)

        window.entry_obj_list.append(entry_obj)

def go():
	for i in xrange(test[0]):
		entryy = entry_obj.get()
		liste_entry.append(entryy)
		print liste_entry

#~~ Sammelliste fuer Entry-Objekte
window.entry_obj_list = list()

#~~ Rahmen fuer die Aufnahme der Entry-Widgets
entry_frame = Frame(window)
entry_frame.pack(side='top')

#~~ Rahmen fuer die Aufnahme der Schaltflaechen
button_frame = Frame(window)
button_frame.pack()

button1 = Button(button_frame, text="Anzahl!", width=10, command=anzahl)
button1.pack()

button2 = Button(button_frame, text="Go!", width=10, command=go)
button2.pack()
liste_entry = list()
test = list()
window.mainloop()
Unzwar erscheint der Fehler in der Funktion "go" bei "entryy = entry_obj.get()", dass die variable entry_obj noch nicht definiert wurde. Stimmt ja eigentlich auch da die Funktion "go" unabhängig von FUnktion "anzahl" ist und entry_obj dort ja erstellt wird. Oder liege ich da falsch?
Ich wollte halt, die Dinge die man dann in die Entry-Felder eingibt in eine Liste speichern.

@yipyip
Danke auch für deine Version ;) Ich hab sie mir noch nicht genau angeschaut, werde mich aber nochmal später damit befassen!

@kaytec
Danke! Ich habe mal nach diesen Anweisungen geschaut, und es klingt sehr interessant in der Situation von löschen der Entry's. Habe bis jetzt allerdings noch nichts ausprobiert, werde ich später aber nochmal machen ;)
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo secretwz

So wie ich dich verstehe hast du ein Eingabefeld in welches du die gewünschte Anzahl für die Erstellung weiterer Eingabefelder eingibst. Die gewünschten Eingabefelder werden mit aktivieren der Schaltfläche 'Anzahl!' erstellt. In die erstellten Eingabefelder gibst du dann Informationen ein. Mit aktivieren der Schaltfläche 'Go!' werden diese Informationen aus den Eingabefeldern in eine Liste geschrieben. Aus dieser Liste möchtest du eine zufällige Information auslesen und Anzeigen.

Ist meine Interpretation deines Vorhabens richtig?

Gruss wuf :wink:
Take it easy Mates!
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

genau richtig ;) so gut hätte ich es nicht beschreiben können *g*
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo secretwz

Hier eine von vielen möglichen Varianten zum herumexperimentieren:

Code: Alles auswählen

import Tkinter as tk
from random import randint, choice

class MyObjects(object):
    """Hilfs-Klasse fuer globale Objekte"""

    #~~ Um die 'global'-Anweisung zu umgehen, haengt man dieser
    #   Klasse die global verwendeten Objekte als Attribute an.
    def __init__(self):
        pass

window = tk.Tk()
window.config(bg='steelblue3')

def error():
    """Rueckstellung der Anzahl-Eingabe Fehlereingabe"""

    entry_anzahl.delete(0,'end')
    entry_anzahl.config(fg='black')

def anzahl():
    """Uebernehme die Anzahl fuer Eingabefelder"""

    #~~ Eingabekontrolle
    try:
        anzahl_felder = int(entry_anzahl.get())
    except ValueError:
        entry_anzahl.delete(0,'end')
        entry_anzahl.config(fg='red')
        entry_anzahl.insert(0,"Ungueltig!")
        #~~ Einblenden der Fehlermeldung (1 Sekunde)
        window.after(1000, error)
        print "Anzahl-Eingae ist ungueltig!!!"
        return

    create_entry_fields(anzahl_felder)

def create_entry_fields(anzahl_felder):
    """Erzeuge die gewaehlte Anzahl Eingabefelder"""

    #~~ Zuerst entferne bestehende Entry-Objekte
    if my_objects.entry_obj_list != ():
        for entry_obj in my_objects.entry_obj_list:
            entry_obj.destroy()
        my_objects.entry_obj_list = list()

    #~~ Erzeuge die gewaehlte Anzahl Entry-Objekte
    for obj in xrange(anzahl_felder):
        entry_obj = tk.Entry(entry_frame, text='', width=10, bg='khaki1',
        highlightthickness=0)
        entry_obj.pack(side='top', pady=2)

        my_objects.entry_obj_list.append(entry_obj)

def go():
    """Auswertung der eingegebenen Daten"""

    #~~ Leere bestehende Eingabe-Datenliste
    my_objects.entry_data_list = list()
    #~~ Schreibe die Entry-Daten in die Eingabeliste
    for obj in my_objects.entry_obj_list:
        my_objects.entry_data_list.append(obj.get())

    print "Debug: Datenliste", my_objects.entry_data_list

    #~~ Gebe ein Zufaelliger Eintrag aus
    print "Zufall = ", choice(my_objects.entry_data_list)

my_objects = MyObjects()

#~~ Sammelliste fuer Entry-Objekte
my_objects.entry_obj_list = list()
#~~ Sammelliste fuer Entry-Daten
my_objects.entry_data_list = list()

#~~ Eingabefeld fuer die Anzahl
entry_anzahl = tk.Entry(window, bg='white', highlightthickness=0)
entry_anzahl.pack(padx=2, pady=2)

#~~ Rahmen fuer die Aufnahme der Schaltflaechen
button_frame = tk.Frame(window, bg=window['bg'])
button_frame.pack()

#~~ Rahmen fuer die Aufnahme der Entry-Widgets
entry_frame = tk.Frame(window, bg=window['bg'])
entry_frame.pack(side='top')

button1 = tk.Button(button_frame, text="Anzahl!", width=10, command=anzahl,
    highlightthickness=0)
button1.pack(padx=2, pady=2)

button2 = tk.Button(button_frame, text="Go!", width=10, command=go,
    highlightthickness=0)
button2.pack(padx=2, pady=2)

#~~ Setze den Fokus auf das Eingabefeld fuer die Anzahl
entry_anzahl.focus_set()

window.mainloop()
Den Sternchen-Import vom Tkinter-Modul habe ich ersetzt durch:

Code: Alles auswählen

import Tkinter as tk
Um die Anweisung 'global' zu umgehen habe ich eine Hilfsklasse 'MyObjects' angelegt

Viel Spass beim studieren von Python & Tkinter!

Gruss wuf :wink:
Take it easy Mates!
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Danke!! Dass du dir solche Mühe gibts (weiß ja nicht ob das als Profi wirklich anstrengend ist *g*) und das ganze Programm schreibst! Ich bin schoneinmal kurz drübergeflogen und habe auch schon eine Frage: Was bewirkt "my_objects = MyObjects()" in Zeile 69?
Ich werde mich später nochmal melden falls ich weitere Probleme habe *gg*
Was mich sehr erfreut hat ist dass ich beim lesen der Funktion "anzahl" dass erste mal so richtig die return-Anweisung verstanden habe. (Also in einem sinnvollen Zusammenhang)

EDIT: Ups, du hast das ja beschrieben mit dem MyObjects xD Sorry ;) Hab die Klasse ganz vergessen :P

EDIT2: Ich habe mich jetzt nochmal näher beschäftigt, und irgendwie habe ich da noch ein paar kleine Haken... Könnte mir vielleicht jemand diese Klasse am Anfang erklären?
Es wird ein Objekt mit dem __init__ dort erstellt richtig? Aber dann kommt ja eine pass-Anweisung, das heißt doch dass nichts passiert, also das Objekt keine "EIgenschaften" hat. Und danach kommen ja auch keine Anwesiungen für das Objekt. Was bringt dann diese Klasse und wie wird das bewirkt? Danke!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

secretwz hat geschrieben:EDIT2: Ich habe mich jetzt nochmal näher beschäftigt, und irgendwie habe ich da noch ein paar kleine Haken... Könnte mir vielleicht jemand diese Klasse am Anfang erklären?
Es wird ein Objekt mit dem __init__ dort erstellt richtig? Aber dann kommt ja eine pass-Anweisung, das heißt doch dass nichts passiert, also das Objekt keine "EIgenschaften" hat.
Dass ``__init__`` leer ist bedeutet nicht dass die Klasse keine Attribute hat - das bedeutet nur, dass der Konstruktor nichts tut. Im dem Fall ist er eigentlich völlig überflüssig. Die Klasse wird hier als Container verwendet um Daten abzuspeichern.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Achso, ok danke ;)
Ich hätte dann noch die Frage wie man Strings in Listen in Floats umwandeln kann.
Ich habe mal im Internet nachgeschaut fand aber nur folgenden Hinweis:

Code: Alles auswählen

map(float, liste)
[float(s) for s in liste]
In Idle gibts dann folgende Ausgabe:

Code: Alles auswählen

>>> los = ["1.4", "5"]
>>> map(float, los)
[1.3999999999999999, 5.0]
>>> [float(s) for s in los]
[1.3999999999999999, 5.0]
Das sieht ja eigentlich schn ganz gut aus, allerdings wenn ich die beiden Elemente addiere kommt was falsches raus:

Code: Alles auswählen

>>> los[0]+los[1]
'1.45'
>>> los[0]
'1.4'
>>> a = los[0]
>>> b = los[1]
>>> a+b
'1.45'
Auch wenn ich probiere sollch eine Liste zu sortieren mit sort(), ändert sich nichts. Woran liegt das? Danke!

EDIT: Es sieht so aus, als würde idle die Elemente noch als String betrachten, und fügt sie so zusammen... Lieg ich da richtig?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Du hast ja eine *neue* Liste mit Zahlen erstellt und diese an keinen Namen gebunden. Dadurch verfällt sie und du rechnest mit der alten Liste weiter.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

achsoo stimmt ja. Vielen Dank! IDLE wertet das ja immer gleich aus... Hat mich etwas verwirrt ;) Ich glaub das wars erstmal mit Fragen. Danke an alle, melde mich nochmal falls ich doch noch ein Problem habe!
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

So jetzt habe ich doch noch eine Frage... Ich habe noch ein Zufallprogramm gebaut wo man Zahlen zufällig ausgeben kann. Ist allerdings nicht so wichtig, denn ich habe alles gut hinbekommen dank dieser vielen Hilfen ;)
Jetzt wollte ich jedoch das Design noch ein wenig verändern um es übersichtlicher zu gestalten. Dafür wollte ich grid() benutzen. Wenn ich allerdings w.grid(row=y, column=x) statt w.pack() benutze, und das Programm starten will, startet zwar die Konsole, sie zeigt jedoch nichts an, nicht einmal ein Fehler, und das Programm erscheint auch nicht. Kann die Konsole dann nur noch schließen...

PS:
Und eine allgemeine Frage. Wie kann man .py Datein in .py Datein öffnen? Also wenn ich ein Programm habe wo eine Liste von verschiedenen Programmen angezeigt werden als Buttons. Und dann möchte ich wenn ich auf einen der Buttons klicke, dass das jeweilige Programm startet.
Ich habe os.startfile("datei.py") ausprobiert, allerdings zeigt er dann an dass "os" die methode "startfile" nicht besitzt... Und auch in meiner Python Doc stand nichts davon. Dann habe ich es noch mit execfile() versucht. Dadurch klappte es auch, allerdings kfunktionierte das geöffnete Programm dann nicht wirklich.. Hatte irgendwelche global-Fehler. Würde mich freuen wenn mir noch jemand helfen könnte!
Antworten