Ein Adressbuch mit Tkinter

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Ein Adressbuch mit Tkinter

Beitragvon kaytec » Freitag 27. Juli 2007, 20:04

Hallo !
Habe mein Adressbuch mal mit Tkinter - Oberfläche gemacht. Ich speichere die Label, Entry etc. in einer Liste, damit ich im Programmablauf auf diese zugreifen kann - geht es auch anders ?

http://www.ubuntuusers.de/paste/13200/

Textdatei anlegen:

Muster
Max
Maxstrasse 1
Maxhausen 1000
01234/12345
0123/12345
01234/23456
max@muster.de
Arbeit


gruss und dank frank
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 27. Juli 2007, 22:09

Ohje, Tkinter schon wieder per Stern-Import ins Modul gezogen, von PEP 8 konfimität gar nicht erst zu sprechen.

Ich würde Buttons die die Daten nicht anzeigen nicht mit Inzizes abspeichern sondern eher in einem Dict mit namen. Oder noch besser an die Instanz der Klasse binden (mir wollte grade das böse Wort Instanzvariablen entrutschen).

``Adressbuch.vor()`` und ``Adressbuch.zurueck()`` finde ich etwas seltsam. Was passiert wenn ein ``Adressbuch`` vor oder zurückgeht? Das scheint mir sinnloses Klassendesign zu sein, vor allem weil die Klasse auch stark mit der Anzeigelogik verdrahtet ist.

Ebenso finde ich ``self.zeahler`` deplaziert. Wozu soll der gut sein (ohne jetzt die genaue Funktionsweise des Programms entziffern zu wollen)? Kann man den Zählen wert nicht aus einer sinnvollen Datenstruktur in die die Einträge gespeichert sind heruasbekommen? Wenn man die Datenstruktur und den Zähler einzeln behandelt kommt es einfacher dazu, dass der Zähler und der Wahre wert untereinander nicht stimmen - man muss somit aufpassen dass wenn man an der Datenstruktur etwas ändert, dass dann auch der Zähler aktualisiert wird. Unnötig, wie ich finde.

Überhaupt hätte ich das ganz anders Implementiert. Der Parameter ``datei`` gehört wenn, dann schon eher an ``laden()`` und ``ende()`` (speichern?). Die Klassenstruktur wirkt so gezwungen - ein reales Objekt würde im richtigen Leben ganz sicher nicht so aussehen. Noch dazu fliegt das Programm auf die Nase, wenns kein Adressbuch gibt - dann sollte ein leeres erstellt werden, statt an einer Exception zu scheitern. ``os.path.exists()`` existiert ja, open() im Read-Mode wirft ja auch eine Exception auf die man reagieren kann. ``laden()`` gibt wiederrum Adressen zurück - als Methode einer Klasse würde man eher erwarten, dass die Aderssen direkt in die Klasse geladen werden.

Ich würde es eher so machen: EIn Adressbuch-Objekt, dass eine Anzahl von Kontakt-Objekten beinhalten kann. Die Kontaktobjekte beinhalten die Daten über die Kontakte, die Adressbuch-Klasse kümmert sich um das Speichern und Laden, ebenso wie um das Suchen.
Dazu noch eine Klasse die sich um die GUI-Dinge kümmert.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Dienstag 31. Juli 2007, 08:32

Danke Leonidas !

Ich würde mal sagen, dass ich von objektorientierter Programmierung keine Ahnung habe und alles vermischt habe. Ich habe mal versucht es zu verstehen und habe jetzt einige Fragen.

Ein Objekt wäre eine Adresse in Form einer (bei mir) Liste mit den Adressdaten.
Attributname -> self.adresse
Attributwert -> ein Adressdatensatz

Klassenattribute (für alle Objekte gültig) -> feldnamen = ('Name', 'Vorname'. etc....

Ich erstelle eine Klasse für die GUI. Diese Klasse ist nun meine 'Oberklasse', da doch diese dem Objekt auferlegt, dass es verschiedene Zustände/Verhaltensweisen annehmen soll ?!. Das Objekt soll sich mit einem neuen Datensatz befüllen oder soll ein noch nicht vorhandener Datensatz werden etc.

Die Klasse für laden(), speichern() und suche() ist eine Klasse der Klasse für die GUI ?

gruss und dank frank
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Donnerstag 2. August 2007, 08:58

Hallo !

Würde so die Adressbuch-Klasse aussehen ?

Code: Alles auswählen

class Adressbuch(object):
   
    def __init__(self):
        self.zaehler = 0
        self.adressen = self.laden()
       
    def laden(self):
        adressen = (('Max', 'Muster', 'Maxstr. 12', '1 Maxhausen', '012345678'),
                    ('Tuxi', 'Tux', 'Tuxstr. 21','2 Tuxhausen', '023456734'))
        return adressen

   
    def speichern(self):
        pass

   
    def getAdresse(self):
        adresse = self.adressen[self.zaehler]
        if self.zaehler == len(self.adressen) - 1:
            self.zaehler = 0
        else:
            self.zaehler += 1
        return adresse


    def sucheAdresse(self, such_begriff):
        suche = list()
        for adresse in self.adressen:
            for eintrag in adresse:
                if such_begriff.upper() in eintrag.upper():
                    suche.append(adresse)
                    break
        return suche

So kommt man an die Adressen :

Code: Alles auswählen

adresse = Adressbuch()

adresse.getAdresse()
('Max', 'Muster', 'Maxstr. 12', '1 Maxhausen', '012345678')

adresse.getAdresse()
('Tuxi', 'Tux', 'Tuxstr. 21', '2 Tuxhausen', '023456734')

adresse.sucheAdresse('Tux')
[('Tuxi', 'Tux', 'Tuxstr. 21', '2 Tuxhausen', '023456734')]


gruss und dank frank
BlackJack

Beitragvon BlackJack » Donnerstag 2. August 2007, 11:09

Es hat einen kleinen Augenblick gedauert, bis ich `getAdresse()` verstanden hatte. Recht ungewöhnlich und falls man auch Adressen entfernen kann, dann ist die Überprüfung auf "Anzahl der Adressen - 1" fehlerhaft. Und bei einem leeren Adressbuch funktioniert die Methode auch nicht.

Um durch die Adressen zu gehen würde man eher `__iter__()` entsprechend implementieren, dann kann man so ein Adressbuch einfach in einer ``for``-Schleife verwenden. Oder um so eine Art Rolodex™ zu simulieren kann man dann `itertools.cycle()` benutzen.

Code: Alles auswählen

class Adressbuch(object):
    def __init__(self):
        self.adressen = self.laden()
   
    def __len__(self):
        return len(self.adressen)
   
    def __iter__(self):
        return iter(self.adressen)
   
    def laden(self):
        adressen = (('Max', 'Muster', 'Maxstr. 12', '1 Maxhausen', '012345678'),
                    ('Tuxi', 'Tux', 'Tuxstr. 21','2 Tuxhausen', '023456734'))
        return adressen


So kann man es dann verwenden:

Code: Alles auswählen

In [8]: adressen = Adressbuch()

In [9]: len(adressen)
Out[9]: 2

In [10]: for adresse in adressen:
   ....:     print adresse
   ....:
('Max', 'Muster', 'Maxstr. 12', '1 Maxhausen', '012345678')
('Tuxi', 'Tux', 'Tuxstr. 21', '2 Tuxhausen', '023456734')

In [11]: import itertools

In [12]: rolodex = itertools.cycle(adressen)

In [13]: rolodex.next()
Out[13]: ('Max', 'Muster', 'Maxstr. 12', '1 Maxhausen', '012345678')

In [14]: rolodex.next()
Out[14]: ('Tuxi', 'Tux', 'Tuxstr. 21', '2 Tuxhausen', '023456734')

In [15]: rolodex.next()
Out[15]: ('Max', 'Muster', 'Maxstr. 12', '1 Maxhausen', '012345678')

In [16]: rolodex.next()
Out[16]: ('Tuxi', 'Tux', 'Tuxstr. 21', '2 Tuxhausen', '023456734')
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Donnerstag 2. August 2007, 21:29

Danke BlackJack !

Mein Ansatz war ja es nach dem Tip von Leonidas zu machen. Eine Klasse für laden, speichern und suchen. Da ich ja schon unbewusst das ganze Adressbuch übergeben habe, ist das 'Nachladen' der einzelnen Adressen ja unötig - oder ?. Das Suchen in der Adressbuch - Klasse eigentich auch !?. Das mit itertools löst meine self.zaehler Probleme - was es so alles schönes gibt. Dafür muss aber die Methode 'def __iter__(self) ' vorhanden sein ?

gruss und dank frank
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Freitag 3. August 2007, 09:30

Habe mich mal eine ein Version mit dem realen Laden und Speichern der Adressen gemacht.

Code: Alles auswählen

#! /usr/bin/env python
# -*- coding: utf-8
import pickle

class Adressbuch(object):
    feldnamen = ('Name:','Vorname:', 'Strasse:', 'Ort:',
                 'Festnetz:', 'Handy:','Arbeit:', 'email:',
                 'Bemerkung:')
   
    def __init__(self, adressbuch):
        self.adressen = self.laden(adressbuch)


    def __iter__(self):
        return iter(self.adressen)
   
       
    def laden(self, adressbuch):
        try:
            datei = file('adressbuch.dmp', 'r')
        except IOError:
            adressen = list()
            adresse = list()
            for name in self.feldnamen:
                adresse.append('')
            adressen.append(adresse)
            return adressen   
        adressen = pickle.load(datei)
        datei.close()
        return adressen
   
   
    def speichern(self, adressen):
        datei = file('adressbuch.dmp', 'w')
        pickle.dump(adressen, datei)
        datei.close()


gruss und dank frank
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Mittwoch 8. August 2007, 08:00

Habe das Adressbuch mal umgebaut , doch die Funktion zurückblättern geht jetzt nicht mehr - oder gibt es das Gegenteil von next() (z.B.: back()) ?

http://www.ubuntuusers.de/paste/13524/

gruss frank
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Donnerstag 9. August 2007, 11:22

Also ich würde ja bei ``Adressbuch.laden()`` nicht die Adressen zurückgeben, sondern den internen Zustand der Klasse ändern, so dass die Klasse nun die Liste der Adressen enthält. Dann kann man der Funktion auch noch einen Parameter ``filename`` mitgeben, der Definiert aus welcher Datei überhaupt geladen wird.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Donnerstag 9. August 2007, 22:33

Danke Leonidas !!

Das würde man mit einer Methode übergeben ( z.B. wie die Methode zum itterieren --> def ___iter___(self)) Habe in meinen Buch und hier auf dem Board sowas nicht gefunden ( z. B.:" def___list___(self)"). Könntest du mir da helfen ?

gruss frank
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Donnerstag 9. August 2007, 22:56

Ich hätts etwa so gemacht wie in Paste #2334. Man könnte auch ``Adressbuch.__init__`` einen Dateinamen-Parameter mitgeben, so dass es dort ``Adressbuch.laden()`` aufruft, aber an sich ist die Idee gar nicht mal so gut, denn man könnte ja verschiendene Laden-Funktionen machen und dann wäre das wohl nicht optimal. Solche Funktionen könnten sein ``laden_aus_pickle(self, dateiname)``, ``laden_aus_datenbank(self, tabellenname)`` etc.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Freitag 10. August 2007, 09:35

Danke Leonidas !

Das was Du gepostet hast sieht schon schön aus - aber was es so macht ?

Ich habe einen kleine Fehler gefunden. Es fehlt ein Unterstrich in self.custom_attrs.append(key).

So wie ich OOP verstanden habe, wir dem Objekt Eigenschaften mit den definierten Methoden übergeben. Diese Eigenschaften sind doch in meinem Beispiel nur ein einziges mal relevant, da ich die self.adressen ja mit Adressbuch_Gui ständigen verändere und somit ich die Verhaltensweisen des Objektes immer wieder neu definieren muß oder ? Die Anzahl der Adressen ändert sich doch beim Einfügen einer Adresse und es ist kein .append oder len möglich. Deswegen habe ich in meinem Beispiel die self.ladressen (für .append etc.) und die self.iadressen (für .next()). Das man sie gleich als eine Liste übergibt, finde ich auch ok, doch das habe ich ja nicht hinbekommen und mache es über den Umweg mit Aufruf: self.ladressen = self.adress_buch.laden(). Das ganze Übergeben von Eigenschaften macht für mich irgendwie keinen Sinn ?!

Dein Beispiel macht dies evt. möglich doch wie o.b. muß ich es erst mal verstehen lernen - habe dieses Wochenende frei und viel Zeit :-).

gruss und dank frank
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Freitag 10. August 2007, 10:00

Habe da mal etwa gefunden In A Byte of Python:

http://abop-german.berlios.de/read/repr-function.html

Code: Alles auswählen

>>> liste = []
>>> liste.append('element')
>>> `liste`
"['element']"
>>> repr(liste)
"['element']"


gruss frank
BlackJack

Beitragvon BlackJack » Freitag 10. August 2007, 10:49

Aus Deiner Beschreibung was Du denkst was OOP ist, werde ich nicht wirklich schlau.

Und hier: http://www.ubuntuusers.de/paste/13524/ ist `Adressbuch` kein wirkliches Objekt. Also formal ist es schon eines, aber im OOP Sinn nicht. Wo sind denn da die Adressen? Von einem Adressbuch erwartet man, das es die Adressen und die notwendigen Methoden zum Umgang mit ihnen enthält. Stattdessen sind bei Dir die Adressen in der GUI gespeichert und dass dann auch noch zweimal unabhängig voneinander.

Und Dir fehlt es anscheinend auch immer noch an ganz grundlegendem Verständnis was Programmabläufe und Sichtbarkeitsbereiche von Namen angeht. Anders kann ich mir zum Beispiel `Adressbuch_GUI.vor()` nicht erklären.
Benutzeravatar
kaytec
User
Beiträge: 541
Registriert: Dienstag 13. Februar 2007, 21:57

Beitragvon kaytec » Freitag 10. August 2007, 12:19

Danke BlackJack !

Die Adressen bleiben im Adressbuch und mit Adressbuch_gui rufe ich immer nur eine ab. Diese hat über die definierten Methoden die richtige Form. Ich lade nicht alle Adressen in das Adressbuch_Gui, sondern nur immer die benötigte Adresse.

Adressbuch_Gui.vor() bedeutet nächste Adresse anzeigen !

gruss frank

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder