Ich habe eine Frage, die wahrscheinlich eher eine Software-Engineering-Frage ist als eine Tkinter-Frage.
Angenommen ich habe ein Programm mit einer GUI.
Das Programm hat als Variable eine lange Liste von Objekten gespeichert. Sagen wir diese Liste heißt liste.
In der GUI ist eine Listbox. Sagen wir die Listbox heißt listbox.
Jeder Eintrag in der Listbox ist eine Beschreibung von einem der gespeicherten Objekte.
Neben der Listbox ist ein Button. Wenn der Benutzer den Button anklickt, dann soll das Objekt, das gerade in der Listbox ausgewählt ist, irgendwie geändert werden.
Um das zu erreichen, knüpfe ich an den Button eine Funktion die irgendwie sowas macht wie:
liste[listbox.curselection()[0]] = geändertes_objekt
So weit, so einfach. Aber was, wenn die Listbox nicht ALLE Einträge der liste anzeigt, sondern nur die, die ein bestimmtes Kriterium erfüllen? Dann kann ich den Index den mir listbox.curselection()[0] gibt, nicht einfach verwenden.
- Versteht man, was ich meine?
Eine Kopie von liste zu machen in der nur die angezeigten Objekte drinstehen ist auch nicht sinnvoll, denn wenn ich die Einträge der Kopie ändere, ändern sich die Einträge der liste i.A. nicht - aber das sollten sie.
Also bleibt nur, den Index von curselection zu nehmen und dann rumzurechnen, welcher Eintrag von liste dazu wohl gehört hat. Aber dann habe ich gewisse Code-Dopplungen - einmal beim Befüllen der Listbox und dann nochmal beim Rekonstruieren welchen Eintrag der Benutzer wohl gemeint hatte.
Sicherlich bin ich nicht der Erste, der dieses Problem hat. Wie würde das jemand angehen, der Ahnung von der Materie hat? Gibt es dafür irgendwelche Patterns?
Freundliche Grüße
Y.
Listbox, die nicht alles anzeigt
Doch, werden sie. Hier ein Minimalbeispiel, was ich meine:
Jetzt stelle man sich noch vor, das "h" wäre nicht hartkodiert sondern würde vom Benutzer in einem Entry eingegeben werden. Und die Listbox müsste nach dem Klick auf den Button die geänderten Strings anzeigen.
Code: Alles auswählen
import tkinter as tk
w = tk.Tk()
liste = ["hallo", "quatsch", "mit", "soße", "hussnätter"]
gefilterteliste = [s for s in liste if not s.startswith("h")]
listbox = tk.Listbox()
for s in gefilterteliste:
listbox.insert(tk.END, s)
listbox.pack()
def helau():
if len(listbox.curselection()) != 1:
print("nichts oder zu viel ausgewählt")
return
gefilterteliste[listbox.curselection()[0]] += " HELAU"
print(gefilterteliste)
print(liste)
tk.Button(w, text="helau anhängen", command=helau).pack()
w.mainloop()
PS: Die angebotene Summe ist beachtlich.
Und wieso sehe ich dann in der Ausgabe dass liste sich nicht geändert hat?
PS: Die angebotene Summe ist beachtlich.
@Üpsilon: Ich sehe auch nicht, wo du ein Objekt in einer Liste veränderst. Ich sehe, dass du `gefilterteliste[listbox.curselection[0]]` etwas _neues_ zuweist.
Hier würdest du auch nicht erwarten, dass der Wert von b plötzlich "ham" wird, oder?
Hier würdest du auch nicht erwarten, dass der Wert von b plötzlich "ham" wird, oder?
Code: Alles auswählen
>>> a = "spam"
>>> b = a
>>> a = "ham"
>>> print(a)
ham
>>> print(b)
spam
Ich programmiere seit 10 Jahren in dieser Sprache und weiß sehr wohl wie = funktioniert. Ich hatte mich explizit bemüht, meine Ausgangsfrage klar zu formulieren und bedaure, dass mir das nicht hinreichend gelungen ist.
Nochmal: Meine Frage ist - bezogen auf das kleine Beispiel was ich gepostet habe - wie bekommt man es ohne Code-Dopplungen am besten hin, an den ausgewählten Eintrag "HELAU" anzuhängen?
Nochmal: Meine Frage ist - bezogen auf das kleine Beispiel was ich gepostet habe - wie bekommt man es ohne Code-Dopplungen am besten hin, an den ausgewählten Eintrag "HELAU" anzuhängen?
PS: Die angebotene Summe ist beachtlich.
Strings sind nicht deine Objekte. Sondern immutable, und natürlich hast du dann zwei unterschiedliche.
Steckst du hingegen ein dict statt einem String in deine Liste, und änderst das, dann reflektiert sich das auch in beiden Listen. Und das auch schon seit 10 Jahren. Oder mehr.
Steckst du hingegen ein dict statt einem String in deine Liste, und änderst das, dann reflektiert sich das auch in beiden Listen. Und das auch schon seit 10 Jahren. Oder mehr.
Für dem Fall, dass jemand über den Thread stolpert, der noch nicht so viel Erfahrung im Zuweisen hat folgende Session aus dem interaktiven Interpreter. Manchmal sagt das mehr aus als viele Erklärungen.
Code: Alles auswählen
>>> a = "ham"
>>> print(id(a))
2146183766640
>>> l = [a]
>>> x = [l]
>>> print(l)
['ham']
>>> print(x)
[['ham']]
>>> a = "spam"
>>> print(id(a))
2146184025200
>>> print(id(l[0]))
2146183766640
>>> print(l)
['ham']
>>> print(x)
[['ham']]
>>> l[0] = "lemmon"
>>> print(l)
['lemmon']
>>> print(x)
[['lemmon']]
Um das nochmal klar zu machen (ich war gestern auf dem Mobiltelefon hier unterwegs): dein Ausgangsproblem bezog sich auf die Veraenderung bestehender Objekte, die in zwei Listen - gefiltern und ungefiltert - gefuehrt werden koennen, was dir aber irgendwie nix war. Auf dieses Problem haben sich meine Antworten hier bezogen.
Doch dein Beispiel hier zeigt ein voellig anderes Problem, das *hinzufuegen* eines Objektes an eine eine Liste, mit der Erwartungshaltung, das waere dann auch bei der anderen so. Das ist ein komplett anderes Problem. Niemand hat behauptet, dass da Liste A durch anhaengen an eine andere Liste B implizit mitveraendert wird.
Doch dein Beispiel hier zeigt ein voellig anderes Problem, das *hinzufuegen* eines Objektes an eine eine Liste, mit der Erwartungshaltung, das waere dann auch bei der anderen so. Das ist ein komplett anderes Problem. Niemand hat behauptet, dass da Liste A durch anhaengen an eine andere Liste B implizit mitveraendert wird.
Ah, du hast recht. Er modifiziert das Element in-place. Damit ist mein Beitrag zwei hoeher natuerlich Unfug, das entspricht schon dem urspruenglichen Szenario. Aber mutable vs immutable ist natuelich immer noch das Thema.