Adressbuch - neues Projekt

Fragen zu Tkinter.
Antworten
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Also ich habe jetzt damit begonnen ein Adressbuch zu programmieren. Damit ich nicht für jedes Problem n extra Thema aufmachen muss will ich meine Fragen hier mit der zeit loswerden und hoffe dass ich viel davon lernen kann. Wäre sehr nett wenn ihr mich bei meinen Problemen unterstützen könntet! Danke!

Nun zu meinem ersten Problem:

Der Eintrag eines neuen Kontakts:

Code: Alles auswählen

def entry():
	vorname = entry2.get()
	nachname = entry3.get()
	telefon = entry4.get()
	dictionary = {"Vorname":vorname, "Nachname":nachname, "Telefon":telefon}
	daten = open("daten.pickle", "a")
	pickle.dump(dictionary, daten)
	daten.close()
Hier werden die Daten aus den Entrys ausgelesen und als Dictionary in einer pickle-Datei gespeichert.
Wenn ich mir die Datei allerdings nach dem Speichern anschaue sieht dies so aus:

Code: Alles auswählen

(dp0
S'Nachname'
p1
S'Zander'
p2
sS'Vorname'
p3
S'Peter'
p4
sS'Telefon'
p5
S'08575/348576'
p6
s.
Meine Frage dazu: Warum ist der Nachname auf einmal vor den Vornamen?!
Sie wurde doch anders herrum gespeichert.

Zu meiner zweiten Frage:
Wenn ich mehrere Personen speichere und diese wieder als Dictionary auslesen und anzeigen will, dann zeigt er nur den ersten gespeicherten Eintrag an. Wie bekommt man es hin dass alle in das selbe Dictionary gespeichert werden um damit wieder arbeiten zu können?

Der Code dazu:

Code: Alles auswählen

def search():
	daten2 = open("daten.pickle", "r")
	dictionary2 = pickle.load(daten2)
	daten2.close()
	print dictionary2
Hoffe ihr könnt mir helfen, schonmal vielen Dank ;)[/quote]
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ad 1: Dictionaries haben keine Reihenfolge.

Ad 2: Du willst eine Liste von Dictionaries bzw ein Dictionary von Dictionaries. (Allerdings macht es mehr Sinn eine Datenbank zu bemuehen als Pickle)

Und bitte mach einen Thread pro konkretem Problem auf, das hilft Leuten mit aehnlichen Problemen besser. Was mit dem Adressbuch Design zu tun hat, findet hier aber trotzdem Platz ;)

Namen zu nummerieren ist eine ganz schlechte Praxis, bennen deine Namen, nach ihrer Funktion.
(Ich weiss wovon ich rede, ich durfte mich mal durch ein Legacy-System kaempfen, dass Namen wie ``wrw``, ``wrt`` usw einthielt, nummeriert von 1 bis 35. Die Namen setzten sich vom Code aus in die Datenbank fort .. fuerchterlich.)
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Danke für deine schnelle Antwort ;)

Stimmt.. vor allem macht ein Dictionary mit mehreren Kontakten wenig Sinn wenn es dort keine Reihenfolge gibt. Da wäre die einzige Lösung Dicts bzw Listen in Dicts. Aber naja..
Ich werde mich einfach mal mit Datenbanken in diesem Fall beschäftigen :)

Ja das nummerieren ist wirklich nicht gut xD Habe bei den paar schon kein richtigen Durchblick mehr ;) Ich werde sie mal umbenennen.

Danke für deine Hinweise ich werde mich erstmal darum kümmern und mich wieder melden wenn weitere Probleme auftreten ;)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

secretwz hat geschrieben:Stimmt.. vor allem macht ein Dictionary mit mehreren Kontakten wenig Sinn wenn es dort keine Reihenfolge gibt.
Ein Dictionary ist schon vernünftig, du darfst nur nicht alle Daten aller Personen in ein Dictionary verschieben. Für jeden Kontakt ein Dictionary ist allerdings wunderbar.

Auch wenn du hier besser eine Datenbank benutzten solltest, noch die Lösung zu deinem pickle-Problem beim Laden: Für jedes Element das du mit "dump" gespeichert hast musst du auch einmal "load" aufrufen. Es wird nicht implizit die ganze Datei gelesen sondern immer nur ein neues Objekt.
Das Leben ist wie ein Tennisball.
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Danke auch für deine Antwort ;) Ich habe mich inzwischen allerdings schon an Datenbanken ran gemacht..

Möchte erstmal mein kompletten Code posten: (Vielleicht könnt ihr mich ja auch noch auf andere Dinge hinweisen die nicht passen etc. ;))

Code: Alles auswählen

#imports
from Tkinter import *
import anydbm

#Fenstererstellung
window = Tk()
window.config(bg="#cde66a")
window.geometry("800x600")

db = anydbm.open("db", "c")

#Funktionen
def search():
	daten2 = open("daten.pickle", "r")
	dictionary2 = pickle.load(daten2)
	daten2.close()
	print dictionary2

def newentry():
	label_vorname.place(x=370, y=250, anchor="e")
	entry_vorname.place(x=370, y=250, anchor="w")
	label_nachname.place(x=370, y=300, anchor="e")
	entry_nachname.place(x=370, y=300, anchor="w")
	label_telefon.place(x=370, y=350, anchor="e")
	entry_telefon.place(x=370, y=350, anchor="w")
	button_entry.place(x=400, y=410, anchor="center")

def entry():
	vorname = entry_vorname.get()
	nachname = entry_nachname.get()
	telefon = entry_telefon.get()
	
	zeilen = len(open("db").readlines())
	print zeilen
      	zeilen += 1
   	db[str(zeilen)] = ("%s;%s;%s") % (vorname, nachname, telefon)
	for i in db.keys():
		tupel = db[i].split(";")
		vorname, nachname, telefon = tupel
		print ('Name:', vorname, nachname, 'Tel:', telefon)
	
	global zeilen
	
#Erstellung von Labels
label_welcome = Label(window, text="Willkommen bei AddyBs dem Adressbuch!", font=("Arial",18,"bold"), bg="#cde66a")
label_suche = Label(window, text="Suche", font=("Arial", "12", "underline"), bg="#cde66a")
label_vorname = Label(window, text="Vorname: ", bg="#cde66a")
label_nachname = Label(window, text="Nachname: ", bg="#cde66a")
label_telefon = Label(window, text="Telefon: ", bg="#cde66a")

#Erstellung von Buttons
button_suche = Button(window, text="Suche starten", command=search)
button_newentry = Button(window, text="Neuer Eintrag", command=newentry)
button_entry = Button(window, text="Eintragen", command=entry)

#Erstellung von Entrys
entry_suche = Entry(window)
entry_vorname = Entry(window)
entry_nachname = Entry(window)
entry_telefon = Entry(window)

#Aufbau des Fensters
label_welcome.place(x=400, y=30, anchor="center")
label_suche.place(x=400, y=100, anchor="center")
entry_suche.place(x=395, y=130, anchor="e")
button_suche.place(x=405, y=130, anchor="w")
button_newentry.place(x=400, y=180, anchor="center")

#Fensterschleife
window.mainloop()
Das mit den Zeilen zählen in der Datenbank klappt nicht wirklich da das anscheint alles in eine Zeile geschrieben wird und die zeile jedesmal wieder bei 1 beginnt...
Wie kann man sonst die Anzahl der EInträge in Datenbanken zählen?

Also mein hauptsächliches Problem ist eigentlich dass ich nicht weiß wie und was ich für ein Datenbank Modul nutzen sollte... Ich finde auch nirgends so richtig was, vielleicht könntet ihr mir Quellen hierfür geben damit ich mich erstmal richtig mit beschäftigen kann.
Weil ich werde wohl auch beim auslesen der Datenbank einige Probleme bekommen ohne richtige Anleitungen!
BlackJack

@secretwz: Argh. Du "benutzt" hier `anydbm`, `pickle`, und die Datenbank-Datei als Textdatei interpretiert wild durcheinander. Sternchenimporte sollte man vermeiden. Die Namen haben teilweise immer noch willkürlich scheinende Nummern angehängt. Du verwendest den `place()`-Layout-Manager. Und ``global`` solltest Du am besten auch gleich wieder komplett vergessen.

Zeile 36 ist falsch eingerückt, so läuft das Programm gar nicht erst.
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Danke für die Antwort. Das mit dem einrücken ist beim kopiern passiert im Programm isses richtig ;)
Und des mit dem pickle ist noch von der Aktion davor, hab einfach noch nicht die search() Funktion rausgenommen bzw geändert, sorry ;) also die gehört da eigentlich garnicht mehr rein.
Ja ich verwende place() was ist daran falsch?
Warum sollte man Sternchenimporte vermeiden?
Mit dem global das war auch nur son kurzer Versuch hat ja auch nichts gebracht ;)
Danke für die Hinweise
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Mit "place" werden alle Elemente auf den Pixel genau positioniert. Das Ergebnis sieht auch gut aus, solange es nur auf deinem System betrachtet wird. Auf vielen anderen wird es Überlagerungen in der Schrift und den Buttons geben und gruselig aussehen, da viele verschiedene Betriebssysteme mit vielen verschiedenen Einstellungen auf vielen verschiedenen Rechnern existieren. Benutze besser "pack" oder "grid".

*-Importe sind schlecht, da sie dir den ganzen Namensraum zumüllen. Wenn du mehrere *-Importe hast ist nahezu garantiert, dass sich irgendwo Namen überschneiden. Am schlimmsten ist jedoch, dass du im Code nicht mehr sofort nachvollziehen kannst, wo die Namen her kommen. Wenn mal eine Name zu lang ist, dann nutze "import Tkinter as tk". Dann kannst du statt "Tkinter.Button" kurz schreiben als "tk.Button".

Die "gloabl"-Anweisungen ersetzt du durch am besten durch Parameter und Rückgabewerte.

Edit: Ganz vergessen: Code gehört nicht auf Modulebene sondern in Funktionen, andernfalls kannst du dein Modul nicht vernünftig importieren. Am Ende deines Moduls solltest du folgendes zum Aufrufen deines Programms schreiben:

Code: Alles auswählen

if __name__ == "__main__":
    main()
Das garantiert dir, dass die main-Funktion, welche du selber definieren musst, nur aufgerufen wird, wenn dein Programm direkt aufgerufen wird. Wenn du dein Modul importierst, dann wird die main-Funktion nicht aufgerufen.
Das Leben ist wie ein Tennisball.
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

Ich habe mich jetzt mal mit Datenbanken beschäftigt und das ist wirklich ziemlich praktisch, hatten DB SQL ja auch inna 11Klasse von daher wusst ich noch ein bisschen was^^

Ich habe jetzt das modul sqlite3 verwendet. Erstelln und so klappt alles super. Nur bei der Abfrage habe ich ein Problem:

Code: Alles auswählen

def search():
    input = entry_suche.get()
    werte = (input)
    sql = "SELECT * FROM adressen WHERE vorname = (?)"
    cursor.execute(sql, werte)
    print cursor.fetchall()
Beim Hinzufügen eines Eintrags klappt diese Art auch, hier jedoch zeigt er folgenden Fehler an:

Code: Alles auswählen

ProgrammingError: Incorrect number of bindings supplied. The current statement uses 1, and there are 0 supplied.
Die letzte Zahl gilt hierbei als die Anzahl der Zeichen die man in das Suche-Entry eingegeben hat. Hier habe ich es freigelassen daher die 0.
Aber was kann ich jetzt machen damit der Fehler nicht mehr auftritt?
BlackJack

@secretwz: Werte muss ein Tupel sein und keine Zeichenkette. Irgendwo Klammern drum zu setzen erzeugt kein Tupel. Kommata erzeugen Tupel.
secretwz
User
Beiträge: 40
Registriert: Mittwoch 14. Januar 2009, 22:01

@BlackJack: Danke! Daran habe ich gar nicht mehr gedacht.. vergisst immer so viel wieder^^
Antworten