Es gibt mehr als einen Weg, sich als Einsteiger mit einer Programmiersprache vertraut
zu machen. Ohne Suchen und sehr viel Lesen wird es nie abgehen, ein Unterschied besteht jedoch in der Vorgehensweise.
Am schnellsten lernt es sich bei einer konkreten Aufgabenstellung und der Umsetzung eines ersten eigenen Projektes,
nur zu groß sollte es nicht sein. Fehler werden sich dabei mit Sicherheit einstellen, doch Fehler sind bekanntlich
dafür da, dass ein jeder Mensch aus seinen gemachten Fehlern lernt und diese Aussage trifft auf Programmierer nicht
weniger zu, als auf alle anderen menschlichen Lebensformen.
Nachfolgend ein Beispiel für ein kleines Notizbuch, welches im prozeduralen Programmierstil umgesetzt wurde. Der
prozedurale Stil hat den Vorteil, dass ein Einsteiger noch nicht unbedingt dem objektorientierten Programmierstil
(OOP) vertraut sein muss, um eine erste Anwendung zu realisieren. Dem objektorientierten Programmierstil
kann sich der Einzelne später zuwenden, sozusagen in einem zweiten Schritt, nachdem er bereits bestens mit der
Syntax, mit Variablen, Statements, Schleifen, Tupeln, Dictionaries und Funktionen vertraut ist.
Es sei angemerkt, prozedurale Programmierung sollte in diesem Zusammenhang nicht mit dem Begriff Prozeduren in
einem Topf geworfen werden. Eine Funktion ohne eine Return-Anweisung wird als Prozedur bezeichnet, wenn sie z.B.
dazu beiträgt, einen Wert in ein Textfeld zu schreiben, statt diesen Wert nach einer Bearbeitung per return-Anweisung
zurückzugeben.
Bei der prozedurale Programmierung wird hingegen nur ein Schritt nach dem anderen im Programmablauf umgesetzt,
ohne diese Schritte bereits in Klassen zu gruppieren. Doch ganz so eindeutig und abgrenzend sind die einzelnen
Bezeichnungen oftmals nicht. Betrachten wir deshalb die nachfolgende Anwendung etwas näher.
Ansicht des Notizbuches bei 520 x 360 Pixel mit einem 'Lorem ipsum'-Platzhaltertext.
Zu dem Funktionsumfang der Anwendung gehören zwei wesentliche Programme. Das erste von
den beiden Programmen ist ein einfaches Schreibprogramm zum Schreiben, Erfassen und Speichern von neuen Einträgen.
Beim zweiten Programm handelt es sich praktisch um einen kleinen Editor, der das Öffnen, Editieren und Speichern
von geänderten Notizen oder Beiträgen ermöglicht. Beide Programme werden in einer Anwendung vereint, die so zu
einer voll funktionsfähigen Software wird.
Wer sich bereits mit dem Öffnen, Einlesen und Speichern von Dateien auskennt, wird erkennen, dass beim Speichern
von neuen Notizen für "open" der Modus "a" gewählt wurde. Bei einem Klick auf dem Button wird
nun am Anfang eines jeden Monats eine Datei mit dem Namen
"notizen-im-[aktueller Monat]-[aktuelle Jahreszahl].txt"
angelegt und der neue Eintrag gespeichert. Besteht die Datei bereits, so wird der interne Dateizeiger am Ende
der Datei platziert und die Datei um den neuen Eintrag erweitert.
Erwähnenswert ist nebenher die Schreibweise von ("1.0", END), da deren erster Teil je nach Quelle einmal mit
und ein anderes Mal ohne Anführungszeichen notiert wird. Dazu sollte ein angehender Programmierer wissen, dass
es sich um keine Gleitkommazahl handelt. Eher verhält es sich ähnlich wie in der Welt der Hühner, wo eine Angabe
von 1.7 einer Hühnerschar von genau 8 Hühnern entsprechen würde, bestehend aus einem Hahn und sieben Hennen. Nur
ist bei Python die Zeile 1 mit dem Zeichen 0 (Beginn) gemeint. Bei "2.3" würde Python z.B. ab der zweiten
Zeile und dem dritten Zeichen mit dem Lesen oder Löschen beginnen. Ob die Notierung mit oder ohne Anführungszeichen
erfolgt, Python und Tkinter werten beide Schreibweisen korrekt aus.
Im zweiten Teil, dem Bereich zum Editieren bestehender Einträge, wird eine ausgewählte Datei mit mode "r" geöffnet,
in das Textfeld geladen und mit mode "w" wieder gespeichert. Eigentlich ist "r" nur zum Lesen von Dateien gedacht
und nicht zum Schreiben oder zum Editieren. Doch nach dem der Inhalt aus der Datei ins Textfeld geschrieben wurde,
wird die Datei ohnehin sofort wieder geschlossen. Wenn der Editor mit seiner Arbeit fertig und zufrieden ist,
wird mit "w" der Dateizeiger beim Speichern auf den Anfang der Datei gesetzt und somit der Inhalt der Datei gegen
den bearbeiteten Content vom Textfeld ausgetauscht.
Als letzter Schritt wird der Wert der Variablen "dname" auf None gesetzt, wodurch verhindert wird, dass bei einem
versehentlichen zweiten Klick auf Speichern die Datei nicht mit dem Inhalt vom nunmehr leeren Textfeld erneut
überschrieben wird. Ohne diese letzte Zeile könnte hingegen der komplette Inhalt einer Datei unbeabsichtigt gelöscht
werden.
Weiterhin sei erwähnt, das Textfenster wächst ab einer gewissen Fenstergröße nicht mehr analog mit dem Fenster
mit. Es ließe sich jedoch entsprechend formatieren, wenn dabei berücksichtigt wird, dass die Berechnung nicht
in Pixel, sondern in Zeilenhöhe und in Zeichenbreite entsprechend der verwendeten Schriftgröße erfolgen müsste.
Siehe weitere Hinweise und Möglichkeiten.
Bei den Bezeichnern von selbstdefinierten Funktionen sind zwei Schreibweisen verbreitet, wobei von den Entwicklern von Python die zweite favorisiert wird und die erste eigentlich nicht mehr benutzt werden sollte. Dem steht die Großschreibung von Substantiven gegenüber, die im deutschen Sprachraum mehr an die natürliche Schreibweise angelehnt ist und somit leichter lesbar.
def camelCase():
def camel_case():
Wer ein Script einreichen oder in einem Forum vorstellen möchte, sollte sich hingegen
an die zweite Schreibweise halten sowie Variablen immer klein und Konstanten durchgehend mit Großbuchstaben schreiben.
Weiterhin sollten Variablen nur in Ausnahmefällen "global" gemacht werden. Spätestens ab der dritten globalen
Variable sollte ein Einsteiger sich mit OOP und Klassen beschäftigen, da in einer Klasse Variablen als Instanzattribute
initialisiert werden können, so dass diese in einer Klasse allgemein zur Verfügung stehen.
Weiterhin sollte ein Einsteiger bedenken, nicht nur bei den beiden in den Funktionen global gemachten Variablen
handelt es sich um globale Variablen, sondern strenggenommen alle außerhalb einer Funktion definierten Variablen
stehen im Script global zur Verfügung. Wird nun der Wert einer globalen Variable verändert, beginnt beim Auftreten
von Fehlern die Suche, wo diese Veränderung welchen Effekt bewirkte, was bei umfangreicheren Anwendungen mindestens
eine Fehlersuche erschweren könnte.
Somit gesehen ist das Script auf dieser Seite zwar durchaus funktionsfähig, doch wer sich mit der Absicht trägt,
es noch weiter auszubauen, sollte sich in OOP einarbeiten und der zweiten Version von diesem Notizbuch zuwenden
bzw. lieber diese zweite Version benutzen.
Verbesserte Version: Notizbuch mit Python 3 und Tkinter (Version 2.0)
In Version 2.0 sind noch weitere Änderungen enthalten, die im vorausgehenden Text nicht erwähnt wurden. So haben wir uns in der neueren Version mehr an den Leitfaden für Python-Code (PEP 8) gehalten, von dem im Listing auf dieser Seite noch nicht übermäßig viel zu sehen ist.
Code – Version 1.0:
# --------------------------------------------------------------------- # Description: Ein universelles Notizbuch # Autor: Horst Müller # Version: 1.0 Release Candidate # Datum: 08. Mai 2017 # --------------------------------------------------------------------- from tkinter import Tk, Frame, Button, Label, Text, PhotoImage, Scrollbar, END from tkinter.filedialog import askopenfilename, asksaveasfile import time import os # -------------------------------------------------------------------- # Globale Variable und Konstanten vor dem Deklarieren und Definieren # auf Vorhandensein prüfen, z.B. mit print(globals()) an dieser Stelle. # --------------------------------------------------------------------- FONT = "cambria" dname = None # --------------------------------------------------------------------- # Deutsche Monatsnamen für Datum und monatliche Dateinamen benutzen. # Beispiel Datum: 06. Mai 2017 # Beispiel Verzeichnis plus Dateiname: reminder\notizen-im-mai-2017.txt # --------------------------------------------------------------------- deutsche = { "01" : "Januar", "02" : "Februar", "03" : "Maerz", "04" : "April", "05" : "Mai", "06" : "Juni", "07" : "Juli", "08" : "August", "09" : "September", "10" : "Oktober", "11" : "November", "12" : "Dezember" } wotag = time.strftime("%d") # Wochentage 01 bis 31 monat = time.strftime("%m") # Monate 01 bis 12 jahre = time.strftime("%Y") # Jahre allgemein sidebar = "{0:s}. {1:s} {2:s}".format(wotag, deutsche[monat], jahre) ablage = "reminder" # Verzeichnis fuer die Speicherung der Notizen datname = "notizen-im-{0:s}-{1:s}.txt".format(deutsche[monat].lower(), jahre) abspfad = os.path.abspath(".") pfadnam = os.path.join(abspfad, ablage, datname) # --------------------------------------------------------------------- # Ein Fenster erzeugen, einen Fenstertitel plus Icon hinzufuegen, sowie # die Größe und Aufteilung festlegen. # --------------------------------------------------------------------- fenster = Tk() fenster.title("Mein Notizbuch") fenster.wm_iconbitmap("logo.ico") fenster.geometry("640x420") # Für Screenshots wurden 520x360 benutzt. # Aufteilung in linken und rechten Frame frame_l = Frame(fenster) frame_r = Frame(fenster) # --- Alle Funktionen ------------------------------------------------- # Datei anlegen, falls noch nicht vorhanden und neue Notizen speichern. def speicherNeue(): with open(pfadnam, "a") as datei: datei.write(textfld.get("1.0", END)) textfld.delete("1.0", END) textfld.insert(END, "Eintrag erfolgreich!") # Funktion für das Einfügen eines Datums als Option. def setzeDatum(): textfld.insert(END, "Notizen vom " + sidebar + "\n\n") # Bestehende Datei zum Lesen oder zum Editieren öffnen. def oeffneNotizen(): global dname dname = askopenfilename(filetypes=[("Text Datei", "*.txt")]) if dname is not None and dname != "": with open(dname, "r") as datei: textfld.delete("1.0", END) textfld.insert(END, datei.read()) # Die alte Datei wird nach dem Editieren überschrieben. def speicherNotizen(): global dname if dname is not None: with open(dname, "w") as datei: datei.write(textfld.get("1.0", END)) textfld.delete("1.0", END) textfld.insert(END, "Änderung erfolgreich!") dname = None # Manuelle Wahl des Speicherortes und des Dateinamens. def waehlePfadName(): datei = asksaveasfile(mode = "a", filetypes = [("Text Datei", "*.txt")]) if datei: datei.write(textfld.get("1.0", END)) datei.close() textfld.delete("1.0", END) textfld.insert(END, "Gespeichert!") # --- Labels für die linke Sidebar ------------------------------------ # Label für linke Seite oben (lob gleich links oben) sidelob = Label(frame_l, text = "Notizen", fg = "#c7a621", font = (FONT, 12, "bold"), pady = 8) # Label für linke Seite mittig (lmi gleich links mittig) sidelmi = Label(frame_l, text = "Ältere Notizen", fg = "#c7a621", font = (FONT, 9, "bold"), pady = 8) # Label für linke Seite unten (lun gleich links unten) fraktal = PhotoImage(file = "neuronen.gif") sidelun = Label(frame_l, image = fraktal) # --- Alle Buttons ---------------------------------------------------- # Datei anlegen, falls noch nicht vorhanden und neue Notizen speichern. anlegen = Button(frame_l, text = "Neue speichern", font = (FONT, 10), command = speicherNeue) # Button für das Einfügen eines Datums als Option. aktuell = Button(frame_l, text = "Datum einfügen", font = (FONT, 10), command = setzeDatum) # Bestehende Datei zum Lesen oder zum Editieren öffnen. oeffnen = Button(frame_l, text = "Öffnen", font = (FONT, 10), command = oeffneNotizen) # Speichern normal sp_norm = Button(frame_l, text = "Speichern", font = (FONT, 10), command = speicherNotizen) # Speichern unter ... als mögliche Auswahl anbieten. sp_ausw = Button(frame_l, text = "Speichern unter ...", font = (FONT, 10), command = waehlePfadName) # --- Textfeld mit Scrollbar ------------------------------------------ # Ein Textfeld mit Scrollbar erstellen und formatieren. textfld = Text(frame_r, pady = 10, padx = 10, wrap = "word") scrollb = Scrollbar(frame_r) scrollb.config(command = textfld.yview) textfld.config(yscrollcommand = scrollb.set) # --- Der Aufbau des Fensters ----------------------------------------- # Linke Seite packen frame_l.pack(side = "left") sidelob.pack() anlegen.pack(fill = "x", padx = 8) aktuell.pack(fill = "x", padx = 8) sidelmi.pack(fill = "x", padx = 8) oeffnen.pack(fill = "x", padx = 8) sp_norm.pack(fill = "x", padx = 8) sp_ausw.pack(fill = "x", padx = 8) sidelun.pack(pady = 24) # Rechte Seite packen frame_r.pack(side = "left") scrollb.pack(side = "right", fill = "y") textfld.pack(pady = 4, padx = 4) # Die Hauptschleife fenster.mainloop()
Das Script auf dieser Seite wurde mit Python 3.6 und Windows 10 getestet. Falls Sie es
selbst unter Windows testen oder benutzen möchten, muss eine neuere Python Version auf Ihrem Computer installiert
werden, falls noch nicht vorhanden. Weiterhin muss in dem Verzeichnis, in dem sie dieses Script ablegen, ein
Ordner mit der Bezeichnung "reminder" abgelegt werden oder Sie müssen den bei der Variablen "datname " angegebenen
Pfad entsprechend anpassen.
Abschließend sei noch erwähnt, dass wir keine Gewähr für die Fehlerfreiheit des Scripts übernehmen
können.
Einstieg in Python
OOP mit Python
Codes & Tutorials
Kleines Projekt