Moin, ich habe hier einen tkinter-Frame mit mehreren Bedien- und Anzeigeelementen. Den würde ich gerne per Schleife vervielfältigen und in einem anderen Frame verteilen. Das geht auch soweit. Leider kann ich aber immer nur auf den zuletzt erstellten zugreifen. In anderen (klammerorintierten) Programmiersprachen erstellt man ja neue Instanzen per "new" und hat dann auch eindeutige "Ansprechpartner". Wie geht man mit sowas in python um? Es kommt weder ein Wechsel auf eine andere Programmiersprache, noch auf ein andere GUI-Framework infrage. Vielen Dank schon mal
Rahul D. schrieb: > In anderen (klammerorintierten) Programmiersprachen erstellt man ja neue > Instanzen per "new" und hat dann auch eindeutige "Ansprechpartner". > Wie geht man mit sowas in python um? Klasse erstellen. Instanziieren, bis der Speicher ausgeht.
1 | #!/usr/bin/python3
|
2 | # -*- coding: UTF-8 -*-
|
3 | # vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
|
4 | |
5 | class MyClass(): |
6 | |
7 | def __init__(self, num): |
8 | self._num = num**2 |
9 | |
10 | def show(self): |
11 | return self._num |
12 | |
13 | cls = [ MyClass(i) for i in range(10) ] |
14 | |
15 | for i in range(10): |
16 | print(cls[i].show()) |
:
Bearbeitet durch User
Norbert schrieb: > Klasse erstellen. Instanziieren, bis der Speicher ausgeht. Danke, geht so (bis auf die Button-Aktionen, die jetzt auch umziehen). Da stand ich wie der Ochs' vorm Berg.
import tkinter as tk
class BedienFrame(tk.Frame):
def __init__(self, parent, nummer):
super().__init__(parent, borderwidth=2, relief="groove")
self.label = tk.Label(self, text=f"Frame {nummer}")
self.label.pack()
self.button = tk.Button(self, text="Klick mich",
command=self.aktion)
self.button.pack()
def aktion(self):
print(f"Button in Frame {self.label.cget('text')} gedrückt")
root = tk.Tk()
hauptframe = tk.Frame(root)
hauptframe.pack()
# Hier erzeugen wir mehrere Instanzen und merken sie uns in einer Liste:
frames = []
for i in range(5):
f = BedienFrame(hauptframe, i)
f.grid(row=i, column=0, padx=5, pady=5)
frames.append(f) # WICHTIG: Referenz speichern!
# Zugriff auf eine bestimmte Instanz:
frames[2].label.config(text="Geändert!")
root.mainloop()
In Python erzeugst du Objekte einfach durch Funktions- oder
Klassenaufruf (f = BedienFrame(...)).
• Du musst die Referenzen (z. B. f) in einer Liste oder einem
Dictionary speichern, wenn du später wieder darauf zugreifen willst.
• Überschreibst du die Variable in der Schleife (f = ... ohne
Speicherung), bleibt am Ende nur die letzte Instanz übrig.
• Zugriff erfolgt später über frames[index] oder frames_dict[name].
Wenn du lieber sprechende Namen hast, kannst du z. B. ein Dictionary
verwenden:
frames = {}
for i in range(5):
frames[f"frame_{i}"] = BedienFrame(hauptframe, i)
frames[f"frame_{i}"].grid(row=i, column=0)
Dann kannst du später schreiben:
frames["frame_3"].button.config(text="Aktiviert")
In Python ersetzt du das Konzept von new durch einfaches Instanziieren
und das Speichern der Referenzen (z. B. in einer Liste oder einem
Dictionary).
So hast du „eindeutige Ansprechpartner“ für jede erstellte GUI-Einheit.
Ralf L. schrieb: >
1 | > class BedienFrame(tk.Frame): |
2 | > def __init__(self, parent, nummer): |
3 | > # ... |
4 | > |
5 | > root = tk.Tk() |
6 | > hauptframe = tk.Frame(root) |
7 | > hauptframe.pack() |
8 | > |
Das verstehe ich nicht. Du weißt offensichtlich, wie Objektorientierung
mit Tkinter geht. Warum erzeugst Du Dein Hauptfenster trotzdem
prozedural? Das ärgert mich schon bei den 10000 Tutorials, die im Netz
herumschwirren, dort schreibt offenbar immer wieder ein neuer Tünnes von
den anderen ab. Meinen Beispielcode habe ich hier angehängt.
Das Einzige, was man dabei beachten muß, wird zunehmend unwichtiger:
Tkinter ist schon recht alt und unter Python2 waren das old-style
classes, die also nicht von object geerbt haben. Darum hat dort super()
nicht so funktioniert, wie wir das heute kennen (und oft als
selbstverständlich annehmen), weil die von object geerbte Infrastruktur
nicht vorhanden war. Mit dem Ausschleichen von Python2 wird das zwar
zunehmend unwichtig, denn seit Python3 gibt es ja nurmehr new-style
classes, die automatisch von object erben und deshalb die notwendige
Infrastruktur haben. Aber wenn man mal alten Code pflegen müsste und den
aus irgendeinem Grund nicht auf Python3 portieren könnte oder wollte,
ist es sinnvoll, das im Hinterkopf zu behalten.
>1 | > frames = [] |
2 | > for i in range(5): |
3 | > f = BedienFrame(hauptframe, i) |
4 | > f.grid(row=i, column=0, padx=5, pady=5) |
5 | > frames.append(f) # WICHTIG: Referenz speichern! |
6 | > |
Da würde ich eine List Comprehension eleganter finden:
1 | #!/usr/bin/env python # for proper syntax highlighting
|
2 | |
3 | frames = [BedienFrame(hauptframe, i) for i in range(5)] |
4 | for i, frame in enumerate(frames): |
5 | frame.grid(row=i, column=0, padx=5, pady=5) |
>1 | > frames = {}
|
2 | > for i in range(5): |
3 | > frames[f"frame_{i}"] = BedienFrame(hauptframe, i)
|
4 | > frames[f"frame_{i}"].grid(row=i, column=0)
|
5 | > |
Hier gefiele mir eine Dictionary Comprehension besser:
1 | #!/usr/bin/env python # for proper syntax highlighting
|
2 | |
3 | frames = {f'frame_{i}': BedienFrame(hauptframe, i) for i in range(5)} |
4 | for i, frame in enumerate(frames.values()): |
5 | frame.grid(row=i, column=0) |
Ein T. schrieb: > Das ärgert mich schon bei den 10000 Tutorials, die im Netz > herumschwirren, dort schreibt offenbar immer wieder ein neuer Tünnes von > den anderen ab Dann schreib doch endlich mal eins, das dem mmodernen Standard entspricht und laber nicht immer in irgendwelchen Threads rum, wie du es machen würdest (Sätze, die mit "Ich würde.." beginnen, stellen mir die Nackenhaare auf, weil die implizieren, dass alle Welt das selbe weiß wie du). Du könntest ja beispielsweise mal einen Artikel hier in der Artikelsammlung deses Forums erstellen, wenn du schon so eine Korypäe bist. Dann brauchst du nur auf deinen Artikel verweisen. Ralf L. schrieb: > In Python erzeugst du Objekte einfach durch Funktions- oder > Klassenaufruf (f = BedienFrame(...)). > • Du musst die Referenzen (z. B. f) in einer Liste oder einem > Dictionary speichern, wenn du später wieder darauf zugreifen willst. > • Überschreibst du die Variable in der Schleife (f = ... ohne > Speicherung), bleibt am Ende nur die letzte Instanz übrig. > • Zugriff erfolgt später über frames[index] oder frames_dict[name]. > > Wenn du lieber sprechende Namen hast, kannst du z. B. ein Dictionary > verwenden: Danke, mein Programm läuft inzwischen.
Rahul D. schrieb: > Dann schreib doch endlich mal eins, das dem mmodernen Standard > entspricht und laber nicht immer in irgendwelchen Threads rum, wie du es > machen würdest (Sätze, die mit "Ich würde.." beginnen, stellen mir die > Nackenhaare auf, weil die implizieren, dass alle Welt das selbe weiß wie > du). Schau doch einfach in den Anhang meines Beitrages, den Du wieder einmal in Deiner Dir ganz eigenen Höflichkeit beantwortet hast. Da ist sogar ein Link "Codeansicht", den Du bemühen kannst. Du schaffst das, ich glaube an Dich! Ich wünsche Dir viel Glück und allen einen schönen Sonntag.
Ein T. schrieb: > Schau doch einfach in den Anhang meines Beitrages, den Du wieder einmal > in Deiner Dir ganz eigenen Höflichkeit beantwortet hast. Da ist sogar > ein Link "Codeansicht", den Du bemühen kannst. Du schaffst das, ich > glaube an Dich! Arrogant bist du gar nicht, oder? Ich hatte dir einen Vorschlag gemacht, weil du ja immer von allem so genervt bist, dich alle anderen immer aufregen und dauernd mit deinem Wissen prahlen musst, es dann aber auch jedes Mal wieder hinbschreiben musst. Wü+rdest du das in einem Artikel in der Artikelsammlung veröffentlich, bräuchtest du höchstens den Link dazu verteilen (das könnten dann überigens auch andere machen, die den Artikel vielleicht gut finden). Warum ich deine Art nicht mag, habe ich dir geschrieben. Wenn dich meinne "höfliche Art" stört: Bleib weg (von Threads, die ich eingestellt habe). Mich interessiert deine Meinung kein Stück, und helfen konntest du ja auch bisher nicht. Edit: Dein Quellcode ist ja super kommentiert. Da kann man richtig was lernen. NOT
:
Bearbeitet durch User
Rahul D. schrieb: > Arrogant bist du gar nicht, oder? Das ist eine außerordentlich witzige Frage von jemandem, der hier erst um Hilfe bittet und dann die Helfer verspottet. :-) > Edit: Dein Quellcode ist ja super kommentiert. Da kann man richtig was > lernen. NOT Mein Vorposter hatte schon gezeigt, daß er das Thema grundsätzlich verstanden und nur eine kleine Anregung gebraucht hat. Er wird meinen Anhang sicher auch ohne Kommentare verstehen, und alles Übrige steht in meinem Beitrag. Schau, ich habe verstanden, daß Du Python nicht leiden kannst und Du trotzdem von irgendwem dazu gezwungen wirst, etwas damit zu machen. Aber auch wenn mir das leid tut, bin ich der Falsche, um Deinen Frust darüber auszulassen.
Ein T. schrieb: > Schau, ich habe verstanden, daß Du Python nicht leiden kannst und Du > trotzdem von irgendwem dazu gezwungen wirst, etwas damit zu machen. Aber > auch wenn mir das leid tut, bin ich der Falsche, um Deinen Frust darüber > auszulassen. Das hast du falsch verstanden. Ich mag Sätze, die mit "Ich würde..." beginnen, einfach nicht. Soll ich deiner Meinung nach das Projekt noch mal von vorne beginnen, um mir vorher noch dein Wissen anzueignen? Wie wärw denn eine Formulierung wie "Vorschlag fürs nächste Mal...". Vielleicht übernehme ich beim nächsten Projekt ja deinen Vorschlag. Aber jetzt ist es dafür zu spät ("Never change a running system!"). Deine "Hilfe" mit ".after" in anderen Python-Thread war auch nicht wirklich hilfreich. Dafür hatte ich aber in meiner "typisch freundlichen Art" ("höflich" ist mMn unpassend, da durch Höflichkeitsbremser noch negativer belegt) schon bedankt.
Rahul D. schrieb: > Ein T. schrieb: >> Schau, ich habe verstanden, daß Du Python nicht leiden kannst und Du >> trotzdem von irgendwem dazu gezwungen wirst, etwas damit zu machen. Aber >> auch wenn mir das leid tut, bin ich der Falsche, um Deinen Frust darüber >> auszulassen. > > Das hast du falsch verstanden. Okay. > Ich mag Sätze, die mit "Ich würde..." beginnen, einfach nicht. > Wie wärw denn eine Formulierung wie "Vorschlag fürs nächste Mal...". Naja, "ich würde" sagt und zeigt ja, wie ich das machen würde, also implizit mit meinem Wissen, und meiner Erfahrung. Die Formulierung, die Du vorschlägst, empfinde ich hingegen, als würde mein alter Meister zum Lehrling sprechen. > Soll ich deiner Meinung nach das Projekt noch mal von vorne beginnen, um > mir vorher noch dein Wissen anzueignen? Das kommt darauf an, ehrlich gesagt. Das Ziel der Übung sollte IMHO bleiben, am Ende eine Codebasis zu erhalten, die natürlich erstens tun muß, was sie tun soll, und zweitens möglichst les- und wartbar ist. Dabei stehen drittens auch immer die Fragen nach Ökonomie und Priorisierung im Raum. > Vielleicht übernehme ich beim nächsten Projekt ja deinen Vorschlag. Aber > jetzt ist es dafür zu spät ("Never change a running system!"). Puh... "never change a running system" ist für einen DevOpsler schwer zu verknusen, denn changing running systems ist ja quasi mein Beruf. > Deine "Hilfe" mit ".after" in anderen Python-Thread war auch nicht > wirklich hilfreich. Dafür hatte ich aber in meiner "typisch freundlichen > Art" ("höflich" ist mMn unpassend, da durch Höflichkeitsbremser noch > negativer belegt) schon bedankt. Das stimmt, allerdings... wenn Du häufiger mit Tkinter arbeitest, wirst Du Dich garantiert noch an diesen Rat erinnern. Spätestens dann, wenn Du eine Anzeige aktualisieren möchtest und sich nichts tut, obwohl Du genau weißt, alles richtig zu machen. ;-)
[Offtopic] Ein T. schrieb: > quasi mein Beruf. Meiner nicht. Nicht mal quasi ;) Ein T. schrieb: > Naja, "ich würde" sagt und zeigt ja, wie ich das machen würde, also > implizit mit meinem Wissen, und meiner Erfahrung. Genau so verstehe ich diese Formulierung auch. Ein kleines Beispiel (jetzt klinge ich wie mein Vater), warum ich diese Aussage nicht so pralle finde: Ich hatte mir einen Hochdachkombi in der Lieferwagen-Version gekauft, da ich zu dem Zeit öfter mal Gerätschaften transportiert habe. Eine Bekannte meinte dann "Ich würde mir den ja zum Wohnmobil umbauen." - "Du würdest dir den nicht mal kaufen." Oder jemand sagt "Ich würde das ja so und so machen!" - "Dann mach das doch selber!" > Die Formulierung, die > Du vorschlägst, empfinde ich hingegen, als würde mein alter Meister zum > Lehrling sprechen. Und? Was spricht dagegen? Solange man nicht auf dem selben Stand ist (dass ich keine Ahnung von python habe, hatte ich schon geschrieben), aber jemanden frage, der mehr Ahnung hat, ist das ein Meister-/Geselle-Lehrlingsverhältnis bzw. Lehrer-Schüler-Verhältnis. [/Offtopi]
Rahul D. schrieb: > Ein T. schrieb: >> Die Formulierung, die >> Du vorschlägst, empfinde ich hingegen, als würde mein alter Meister zum >> Lehrling sprechen. > > Und? Was spricht dagegen? Solange man nicht auf dem selben Stand ist > (dass ich keine Ahnung von python habe, hatte ich schon geschrieben), > aber jemanden frage, der mehr Ahnung hat, ist das ein > Meister-/Geselle-Lehrlingsverhältnis bzw. Lehrer-Schüler-Verhältnis. > [/Offtopi] Ich bin hier (soweit ich weiß) niemandes Chef und will das auch nicht sein, und ich möchte so etwas auch nicht einmal andeuten. Deine Formulierung gibt mir das Gefühl, ich spräche als Chef zu meinem Mitarbeiter, als mein "schau bitte mal auf mein Beispiel, ob Dir das nicht auch besser gefällt".
Hallo T. Ich bin zwar nicht Ralf, aber die Frage könnte auf mich auch passen. Ein T. schrieb: > Warum erzeugst Du Dein Hauptfenster trotzdem > prozedural? Das ärgert mich schon bei den 10000 Tutorials, die im Netz > herumschwirren, dort schreibt offenbar immer wieder ein neuer Tünnes von > den anderen ab. Weil es in solchen Situationen oft dazu kommt, dass man zwar ähnliche Inhalte, aber nicht die gleichen verwendet. Objektorientierung erzeugt gleiche Objekte, die aber mit einer Parametrisierung angepasst werden können. Theoretisch könnte man die Objekte jetzt so gestalten, das die Parametrisierung diese Unterschiede mit abdeckt. Leider ist es aber oft so, dass man erst beim Erstellen eines Programmes die vielen kleinen Nickeligkeiten erkennt, die die Unterschiede verlangen. Jetzt nachträglich immer wieder das Objekt anpassen, kann kompliziert und vor allem langwierig werden. Irgendwann ist dann der Punkt gekommen, wo es schneller geht, statt ein Objekt anzupassen, per copy und paste eine Kopie zu machen und separat in das Programm einzufügen. Wenn Du hauptberuflich Python schreibst, mag das anders aussehen, aber gerade Python ist eine Sprache, die wegen ihrer Einfachheit von vielen Programmierern verwendet wird, die eher selten oder sogar nur als Hobby gelegentlich etwas programmieren. Als solcher muss ich mich nach einem halben oder ganzen Jahr, wenn ich alles vergessen habe, wieder neu in die Details der Sprache bzw. meines eigenen Programmes einarbeiten, und da ist dann Objektorientierung auf einmal etwas umständlich. Copy and paste ist dann durchaus die einfachere Alternative und führt zu dem prozeduralen Stil. Wenn Du bessere Alternativen kennst, die auch meine eigenen diesbezüglichen Unzulänglichkeiten abdecken, so bin ich auf Deine Vorschläge gespannt. Nachtrag: Sehr viele der Eigenschaften, die Python so "einfach" machen, betreffen Fälle, wo durch Schleifen und Vereinbahrung vieles "automatisiert" werden kann. Diese Fälle sind aber nur hilfreich, wenn ich ständig damit arbeite. Als Gelegenheitsprogrammierer verstolpere ich dort nur. Mit freundlichem Gruß: Bernd Wiebus alias dl1eic http://www.l02.de
:
Bearbeitet durch User
Hallo Bernd, Bernd W. schrieb: > Ein T. schrieb: >> Warum erzeugst Du Dein Hauptfenster trotzdem >> prozedural? Das ärgert mich schon bei den 10000 Tutorials, die im Netz >> herumschwirren, dort schreibt offenbar immer wieder ein neuer Tünnes von >> den anderen ab. > > Weil es in solchen Situationen oft dazu kommt, dass man zwar ähnliche > Inhalte, aber nicht die gleichen verwendet. Objektorientierung erzeugt > gleiche Objekte, die aber mit einer Parametrisierung angepasst werden > können. Theoretisch könnte man die Objekte jetzt so gestalten, das die > Parametrisierung diese Unterschiede mit abdeckt. Ohne konkretes Beispiel ist es natürlich nicht ganz einfach, etwas in Code zu zeigen. Aber die Objektorientierung bietet doch neben der Parametrierung noch eine andere Möglichkeit zur Spezialisierung, nämlich die Vererbung. Vielleicht magst Du dazu einen eigenen Thread eröffnen und mit einem (oder gern mehreren) Codebeispielen zeigen, was genau Du meinst? > Irgendwann ist dann der Punkt gekommen, wo es schneller geht, statt ein > Objekt anzupassen, per copy und paste eine Kopie zu machen und separat > in das Programm einzufügen. Wenn ich so etwas klassisch prozedural schreibe, wie es zum Beispiel auf der (ansonsten sehr empfehlenswerten) Seite Realpython [1] gezeigt wird, muß ich beim Copy'n'Paste mehrere Zeilen kopieren, die Variablennamen in einer Reihe meiner kopierten Codezeilen anpassen, und wenn ich dabei eine Zeile vergesse oder einen Variablennamen nicht oder nicht richtig anpasse, kann ich enormes Glück haben und die Veranstaltung explodiert sofort. Mit ein wenig Pech habe ich einen sehr schwer zu findenden Fehler eingebaut. Schau Dir auf der verlinkten Seite [1] einfach mal unten den "Text Editor" an (letztes Beispiel vor "Conclusion"): fünf globale Variablen auf nur 37 Zeilen Code in einem winzigen Projekt. Ich hab' mir mal den Spaß gemacht, und dieses Beispiel in zwei OO-Versionen umgebaut: einmal in better.py so "halbwegs OO", wie ich das in einem kleinen Projekt wie diesem umgesetzt hätte. Zudem einmal in best.py, wo auch für den Frame mit den Buttons eine eigene Klasse benutzt wird -- was bei diesem Winzling natürlich Overkill ist, aber in einem großen Projekt würde das durch die bessere Organisation des Code den Überblick, und damit die Les- und Wartbarkeit deutlich verbessern. Den Originalcode von der verlinkten Seite habe ich der Einfachheit halber als main.py angehängt. [1] https://realpython.com/python-gui-tkinter/ Für jeden, der Interesse an der Entwicklung mit Tkinter hat, ist die Seite trotzdem ausgesprochen lesenswert, auch wenn ich mit dem prozeduralen Stil ihres Autors unglücklich bin. Dennoch ist die Seite großartig! > Wenn Du hauptberuflich Python schreibst, mag das anders aussehen, aber > gerade Python ist eine Sprache, die wegen ihrer Einfachheit von vielen > Programmierern verwendet wird, die eher selten oder sogar nur als Hobby > gelegentlich etwas programmieren. Naja, auch wenn man kein hauptberuflicher Entwickler ist -- was ich nicht bin und auch nie gewesen bin, ich komme aus dem Operationsbereich -- ist es immer sinnvoll, sauberen und sauber strukturierten Code zu schreiben, den man auch morgen noch lesen und viel leichter anpassen, warten und pflegen kann. Dabei hilft die Objektorientierung auch den Nichtprofis enorm. Wie gesagt, schau' Dir den angehängten Code an: findest Du denn nicht auch, daß meine Varianten viel strukturierter und übersichtlicher sind? Hinzu käme bei einem wirklich großen Projekt, daß ich meinen Code ganz leicht auf mehrere Dateien verteilen kann. Das ist mit dem prozeduralen Originalcode von Realpython leider nicht möglich.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.