Freundesliste

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
cheffe
User
Beiträge: 12
Registriert: Donnerstag 21. Mai 2015, 22:25

hallo,
ich möchte euch gerne mal mein kleines Projekt vorstellen. Bisher ist es nur ein kleines Programm zum Speichern von Kontaktdaten.
Ich möchte damit später einmal erreichen, dass ich am Geburtstag meiner Freunde eine Benachrichtigung erhalte.

Vielleicht könnt ihr aber erst einmal über meinen Code gucken und mir bitte, bitte, bitte Verbesserungsvorschläge und Korrekturen zu meinem Quellcode geben. Ich habe mir nämlich ales selbst hier zusammengesucht und mir hat niemand wirklich Python beigebracht ;)

meine MAIN.py:

Code: Alles auswählen

#!/usr/bin/python

#-------------------------------------------------------------------------------
# Name:        Hauptmodul
# Purpose:
#
# Author:      Basti
#
# Created:     15.05.2015
# Copyright:   (c) Basti 2015
# Licence:     <your licence>
#-------------------------------------------------------------------------------

def main():
    pass

if __name__ == '__main__':
    main()


from tkinter import *
from zusatzfenster import *
import pprint

root = Tk()
root.title("Kontaktdaten")
root.geometry("1000x500")

##Ueberschrift
Label(root, text="Meine ganz persoenlichen Kontakte! \n \n").grid(row=0, column=1)



## hier wird das  Uebersichtsfenster generiert/geaendert
def personenliste_erzeugen():
    import csv     # imports the csv module
    zeilen_counter = 3
    csvdatei = open("personalien.csv") # opens the csv file
    reader = csv.DictReader(csvdatei, fieldnames = ( "Vorname","Nachname","Geburtsdatum","Handynr","Festnetznr","Adresse"))  # creates the reader object
    liste = list(reader)

    ## SORTIERUNG der csv File Daten
    if sortierauswahl.get() != "Geburtsdatum": ## wenn nach vorname oder Nachname sortiert wird
        liste.sort(key=lambda x: x[sortierauswahl.get()])
    elif sortierauswahl.get() == "Geburtsdatum": ## wenn nach Geburtsdatum sortiert wird
        def sortier_helfer(item):
            # Geburtsdatum ist item[2] in der Liste
            t, m, y = item[sortierauswahl.get()].split('.')
            return (m, t, y)
        liste.sort(key=sortier_helfer)

    for datensatz in liste:
        Zeile = Text(root, height=1, width=100,)
        Zeile.grid(row=zeilen_counter, column=1, columnspan=10)
        Zeile.insert(END, "{0[Vorname]} {0[Nachname]}, {0[Geburtsdatum]}, {0[Handynr]}, {0[Festnetznr]}, {0[Adresse]}".format(datensatz))
        Zeile.configure(state="disabled")
        zeilen_counter += 1
##    LeerZeile = Text(root, height=5, width=100)
##    LeerZeile.grid(row=zeilen_counter, column=1, columnspan=10)
    csvdatei.close()

##Radiobutton oben
Label (root, text="sortiert nach:\n").grid(row=1, column=1)
sortierauswahl = StringVar()
sortierauswahl.set("Vorname") # Standart-auswahl
auswahl_kriterien = [
    ("Vorname", "Vorname", 2),
    ("Nachname", "Nachname", 3),
    ("Geburtsdatum", "Geburtsdatum", 4),
]
for txt, val, column in auswahl_kriterien:
    Radiobutton(root, text=txt, indicatoron = 0, width = 15 ,  variable=sortierauswahl, value=val, command=personenliste_erzeugen).grid(column=column, row=1)


##  die Buttons
Button(root, text="aktualisieren", command=personenliste_erzeugen, bg="green", width=15).grid(row=1, column=100, sticky=W, pady=4)
Button(root, text="Eingabemaske", command=personeneingaben, width=15).grid(row=100, column=2, sticky=W, pady=4)
Button(root, text="Liste (CSV-Datei)", command=personenlisteausgabe, width=15).grid(row=100, column=3, sticky=W, pady=4)
Button(root, text='Quit', command=root.destroy, bg="red", width=15).grid(row=100, column=100, sticky=W, pady=4)

## Ausfuehrung der Liste bei Systemstart
personenliste_erzeugen()

root.mainloop()

dazu liegt im selben Verzeichnis die zusatzfenster.py

Code: Alles auswählen

#!/usr/bin/python

#-------------------------------------------------------------------------------
# Name:        module1
# Purpose:
#
# Author:      Basti
#
# Created:     15.05.2015
# Copyright:   (c) Basti 2015
# Licence:     <your licence>
#-------------------------------------------------------------------------------

from tkinter import *

def main():
    pass

if __name__ == '__main__':
    main()

## Dieses Fenster wird angeziegt wenn man auf "Eingabemaske" klickt
def personeneingaben():
    fenster_eingabe = Tk()
    fenster_eingabe.title("Eingabemaske")
    Label(fenster_eingabe, text="hier werden neue Freunde eingegeben: ").grid(row=0)

    labels = ["Vorname" , "Nachname", "Geburtsdatum", "Handy-Nr", "Festnetz-Nr", "Anschrift"]
    Eingabefelder = []

    position = 2
    for each in labels:
        ##Labels erstellen
        Label(fenster_eingabe, text=each).grid(row=position)
        ##einzelne Eingabefelder erstellen
        Eingabefeld = Entry(fenster_eingabe)
        Eingabefeld.grid(row=position, column=1)
        Eingabefelder.append(Eingabefeld)
        position += 1


    ##Speichert die Daten in den Eingabefeldern
    def datensatz_speichern():
        datensatz=str("")
        for each in Eingabefelder:
            datensatz += each.get()+","
        fobj = open("personalien.csv", "a")
        fobj.write(datensatz+ "\n" )
        fobj.close()
        print(datensatz, "gespeichert!")

    ##Leert alle vorhandenen Felder
    def felder_leeren():
        for jedes_feld in Eingabefelder:
            jedes_feld.delete(0, 'end')

    ##Buttons
    Button(fenster_eingabe, text="Speichern", command=datensatz_speichern, bg="green", width=15).grid(row=20, column=1,  sticky=W, pady=4)
    Button(fenster_eingabe, text="Felder leeren", command=felder_leeren, width=15).grid(row=20, column=2, sticky=W, pady=4)
    Button(fenster_eingabe, text='Quit', command=fenster_eingabe.destroy, bg="red", width=15).grid(row=20, column=3, sticky=W, pady=4)

    mainloop( )


## Dieses Fenster wird angezeigt, wenn man auf "CSV-Datei" klickt
def personenlisteausgabe():
    fenster_ausgabeliste = Tk()
    fenster_ausgabeliste.title("CSV-DATEI")

    ## Automatisches Erstellen der vorhandenen Liste
    personenliste = ""
    fobj = open("personalien.csv", "r")
    for zeile in fobj:
        personenliste += zeile
    fobj.close()
    Liste = Text(fenster_ausgabeliste, width=100, height=15)
    Liste.grid(row=1, rowspan=15)
    Liste.insert(END, personenliste)

    ## Aenderung der original .txt Datei
    def personenliste_aendern():
        alle_datensaetze = Liste.get("0.0", END)
        print (alle_datensaetze)
        fobj = open("personalien.csv", "w")
        fobj.write(alle_datensaetze)
        fobj.close()
    Button(fenster_ausgabeliste, text="Aendern", command=personenliste_aendern).grid(row=99)

    ## Schliessen-Button
    Button(fenster_ausgabeliste, text='Quit', command=fenster_ausgabeliste.destroy, bg="red", width=15).grid(row=100, column=3, sticky=W, pady=4)

    mainloop( )
als nächstes habe ich weiterhin vor, dass ich irgendwie die eingegebenen daten besser editieren kann. Z.B. indem ich die Daten eines Datensatzes aus der csv datei in die "eingabemaske" einlese um dann dort die daten ändern zu können.
Wie lässt sich sowas lösen?
BlackJack

@cheffe: Als erstes mal ein Programmfehler: Von `Tk` darf es nur ein Exemplar in einem Programm geben. Das ist *das* Hauptfenster. Wenn man davon mehr als ein Objekt zur gleichen Zeit hat, dann ist das Programmverhalten nicht mehr definiert. Das kann gut gehen, es kann aber auch komische Effekte bis hin zu harten Programmabstürzen haben.

Für zusätzliche Fenster neben dem Hauptfenster gibt es die `Toplevel`-Klasse.

Dann solltest Du die Sternchen-Importe sein lassen. Wenn man am Ende sowieso alles in einem Namensraum vermischt, bräuchte man keine Module schreiben. Ohne die Aufteilung auf Module wird es aber schwierig den Überblick zu behalten und es besteht die Gefahr von Namenskollisionen.

Importe gehören an den Anfang des Moduls und nicht in Funktionen versteckt. Man sollte die Abhängigkeiten eines Moduls einfacher erfassen können als den gesamten Quelltext nach ``import``-Anweisungen absuchen zu müssen.

Die `main()`-Funktion und das Idiom zum Aufruf sind nicht dazu da um sie leer und damit funktionslos im Modul stehen zu haben, sondern um in der Funktion das Hauptprogramm unterzubringen. Auf Modulebene gehören dann auch keine Variablen sondern nur definitionen von Konstanten, Funktionen, und Klassen.

Da dann die Funktionen nicht mehr einfach so auf irgendwelche Werte aus der ”Umgebung” zugreifen können, braucht man bei GUI-Programmierung dann objektorientierte Programmierung (OOP). Prophylaktische Warnung: Kein ``globall`` verwenden!

Geschäftslogik und GUI sollten besser getrennt sein. Am besten fängt man mit der Geschäftslogik an und setzt darauf dann am Ende ein GUI auf. Auch sollte nicht jede Funktion direkt auf der Datendatei operieren, und deren Name sollte nur *einmal* im Quelltext stehen und nicht in jeder Funktion. Das ist schwieriger zu warten und fehleranfällig. Wenn man den Namen mal ändert, muss man das an mehreren Stellen tun und darf dabei keine vergessen und darf bei keiner der Änderungen einen Tippfehler machen.
cheffe
User
Beiträge: 12
Registriert: Donnerstag 21. Mai 2015, 22:25

1) also TK habe ich in der zweiten DAtei durch Toplevel ersetzt, funktioniert auch wunderbar. Check!
2) mit den *-importen muss ich mal gucken. habe noch von

Code: Alles auswählen

from tkinter import *
stehen, da ich sonst da so viel eingeben muss... muss das wirklich?
3) import steht jetzt nur noch am anfang. Check !
4)
Die `main()`-Funktion und das Idiom zum Aufruf sind nicht dazu da um sie leer und damit funktionslos im Modul stehen zu haben, sondern um in der Funktion das Hauptprogramm unterzubringen. Auf Modulebene gehören dann auch keine Variablen sondern nur definitionen von Konstanten, Funktionen, und Klassen.
hiermit kann ich leider so garnix anfangen... könntest du mir das erklären bzw passend eine erklärung zeigen, was ich da tun soll??
5) auch alles was du danach geschrieben hast, lässt nur eine menge fragezeichen über meinem kopf erscheinen... sorry :(
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

*-Importe sollte man (fast) immer vermeiden. Natürlich ist es ein wenig Tipparbeit eingespart. Aber mit einem richtig guten Editor hat man soagr den gegenteiligen Effekt!

Dein Namensraum wird halt zugemüllt und man weiß nicht mehr wo was herkommt.

Leider sind viele Tk Beispiel im Netz mit *-Import. Die einfach meiden!

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Kebap
User
Beiträge: 686
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

cheffe hat geschrieben:
Die `main()`-Funktion und das Idiom zum Aufruf sind nicht dazu da um sie leer und damit funktionslos im Modul stehen zu haben, sondern um in der Funktion das Hauptprogramm unterzubringen. Auf Modulebene gehören dann auch keine Variablen sondern nur definitionen von Konstanten, Funktionen, und Klassen.
hiermit kann ich leider so garnix anfangen... könntest du mir das erklären bzw passend eine erklärung zeigen, was ich da tun soll??
Könntest du mal kurz erklären, was dieser Teil bewirken soll?

Code: Alles auswählen

def main():
    pass
 
if __name__ == '__main__':
    main()
 
Code zusammen suchen und kopieren, ohne das Ganze zu verstehen, kann kurz mal gut gehen, scheint aber langfristig nicht sinnvoll.

Jedenfalls willkommen bei Python und hier im Forum. Welche Anleitung benutzt du zum Lernen?
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
cheffe
User
Beiträge: 12
Registriert: Donnerstag 21. Mai 2015, 22:25

diese zeilen hat mein pyscripter portable da von anfang an automatisch rein geschrieben... und ich nutze biser python-kurs.eu
aber leider hab ich da von dieser main funktion noch nix gelesen. würde es mir jemand kurz erklären bzw sagen wo eine gute erklärung dazu steht?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cheffe hat geschrieben:und ich nutze biser python-kurs.eu
aber leider hab ich da von dieser main funktion noch nix gelesen. würde es mir jemand kurz erklären bzw sagen wo eine gute erklärung dazu steht?
Das ist ein ziemlich gängiges und ziemlich triviales Konzept - mittels der Suche findest Du z.B. diesen Thread von vor wenigen Tagen ;-)

Wenn Du einen Tutorial nutzt, welches das bisher nicht erwähnt hat (obwohl es schon weit fortgeschritten ist!), was sagt Dir das dann über die Qualität des Tutorials? ;-)

Such einfach mal hier im Forum nach Empfehlungen - es gibt da einige wirklich gute und einige ziemlich schlechte. Wieso also die schlechten nutzen?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten