Ein paar Anmerkungen zu dem Quelltext:
Vermeide Sternchenimporte. Damit ist irgendwann nur noch schwer nachvollziehbar wo welcher Wert herkommt. Und man müllt sich den Namensraum voll, insbesondere bei Modulen wie `tkinter` das um die 190 Namen enthält. Da riskiert man dann auch Namenskollisionen. Bei `tkinter` ist es üblich das unter dem Namen `tk` zu importieren: ``import tkinter as tk``. Dann muss man die Objekte darin über den Namen `tk` referenzieren.
Auf Modulebene sollten nur Konstanten, Funktionen, und Klassen definiert werden und nicht das Hauptprogramm stehen. Schon gar nicht sollte man Hauptprogramm und Funktionsdefinitionen abwechselnd auf Modulebene stehen haben. Das macht alles nur noch unübersichtlicher. Das Hauptprogramm wird üblicherweise in eine `main()`-Funktion gesteckt und mit folgendem Idiom aufgerufen:
Dann kann man das Modul sowohl als Programm direkt ausführen, als auch als Modul importieren ohne das die `main()` sofort ausgeführt wird, um zum Beispiel einzelne Funktionen zu testen, oder in anderen Modulen zu verwenden.
Bezüglich der Namensschreibweise gibt es gewisse Konventionen:
Style Guide for Python Code. In dem Dokument steht auch etwas über Leerzeichensetzung.
Darüber hinaus sollte man keine Abkürzungen in Namen verwenden die nicht allgemein bekannt sind. Namen sollen dem Leser verraten was die Werte dahinter im Programmkontext bedeuten, und nicht zum Rätselraten zwingen.
Man sollte sich auf *eine* natürliche Sprache bei der Namenswahl beschränken. Das ist normalerweise Englisch. Insbesondere wenn man ähnliche Werte in unterschiedlichen Sprachen benennt, zum Beispel mal irgend etwas mit `frame` und mal `rahmen` für `Frame`-Objekte, dann belastet man den Leser oder Programmierer zusätzlich mit der Frage wie vorhandene `Frame`-Objekte denn nun benannt sind, oder welche Sprache man für neue `Frame`-Objekte verwenden sollte.
Das durchnummerieren von Namen ist auch keine gute Idee. Das ist in der Regel ein Hinweis darauf, dass man eigentlich eine Datenstruktur statt einzelner Namen verwenden möchte. Oft eine Liste. Oder aber wie im Fall von `Rahmen1` bis `Rahmen3`, dass man einfach den selben Namen wiederverwenden kann, weil der jeweils nur einen eng begrenzten Abschnitt lang für jeweils ein Rahmenobjekt verwendet wird. Oder man lässt die komplett weg, denn in jedem dieser Rahmen steckt jeweils nur *ein* Widget. Da kann man die Widgets auch direkt verwenden.
Selbst der `HFrame` scheint überflüssig zu sein.
Statt der ganzen Indexzugriffe um die einzelnen Optionen für die Widgets zu setzen, könnte man die gleich beim Erstellen als Schlüsselwortargumente angeben. Das spart Quelltextzeilen mit Code-Wiederholungen.
Funktionsnamen sind in der Regel Tätigkeiten, weil sie etwas tun. `Rechteck` passt da nicht, das ist ein ”Ding” was eher zu einem Wert passt der ein Rechteck repräsentiert, oder in dieser Schreibweise, mit einem grossen Anfangsbuchstaben, zu einem Datentyp der ein Rechteck modelliert.
`Wert` wird in der `Rechteck()`-Funktion überhaupt nicht verwendet. Das sollte wohl in der `CBKnopf()`-Funktion stehen.
``global`` sollte in einem Programm nicht vorkommen. Das deutet in 99,9% der Fälle auf einen unsauberen Entwurf hin. Werte, ausser Konstanten, sollten eine Funktion als Argument betreten und als Rückgabewert verlassen, und nicht einfach so aus ”der Umgebung” kommen oder dort gesetzt werden. Das ist sehr unübersichtlich und schlecht zu testen.
Da man sich bei der ereignisorientierten GUI-Programmierung Zustände über Funktionsaufrufe hinweg merken muss, braucht man Closures oder objektorientierte Programmierung. In Python wird ganz klar OOP bevorzugt, weil Python eine von Grund auf objektorientierte Programmiersprache ist. Darum ist IMHO OOP eine Voraussetzung bevor man sich an GUI-Programmierung setzt.
Ich lande dann als Zwischenschritt bei so etwas:
Code: Alles auswählen
from __future__ import print_function
import random
try:
import Tkinter as tk
range = xrange
except ImportError:
import tkinter as tk
from functools import partial
def draw_rectangle(canvas):
canvas.create_rectangle((10, 10, 35, 25), fill='red')
def do_create_rectangles(rectangle_count_entry, canvas):
for i in range(int(rectangle_count_entry.get())):
print(i)
def main():
root = tk.Tk()
canvas = tk.Canvas(root, width=600, height=300, bg='yellow')
canvas.pack(side=tk.TOP)
rectangle_count_entry = tk.Entry(
root, width=26, font=('Courier', 10, 'bold')
)
rectangle_count_entry.insert(0, 'Anzahl Rechtecke eingeben.')
rectangle_count_entry.pack(side=tk.BOTTOM)
create_rectangles_button = tk.Button(
root,
text='Erzeugen',
command=partial(do_create_rectangles, rectangle_count_entry, canvas)
)
create_rectangles_button.pack(side=tk.BOTTOM)
root.mainloop()
if __name__ == '__main__':
main()