Neuling sucht Rat

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

So - es ist wohl mal wieder an der Zeit das ich gesteinigt werde^^
Nachdem man mir hier nicht sagen wollte wie ich an Rückgabewerte von Funktionen die per Button aufgerufen werde komme hab ich ein wenig rumprobiert.


http://pastebin.com/LGKUyUeM


So dann feuer frei und teil mir mit was alles falsch ist :)


Frage 1:
Als ich mehr oder weniger "fertig" war - viel mir auf - der Ablauf natürlich nicht zwangsläufig beeinhalten das man zuerst den Verbrauch abfrägt - diese Abfrage nahm ich anfänglich aber allein um Fehler mit der .txt abzufangen - also - musste auch beim direkten neuen Wert eingeben - mögliche Fehler abgefangen werden.
Nur:
Die anzeige["text"] funktionieren nicht da die ja quasi "instant" vom neuen Wert überschrieben wird.
Ich hab versucht da mit time.sleep eine kurze "Pause" dazwischen zu schieben um kurz die Info - das 0 verwendet wird gelesen werden kann - aber das Label wollte den Text einfach nicht zeigen - zusätzlich dazu ist time.seep - irgendwie "fürchterlich" . .... das sieht aus als würde sich das Programm gerade aufhängen.
Das erklärt auch noch den import time - der jetzt natürlich überflüssig ist weil er nirgends wirklich gebraucht wird - werde ich noch entfernen.

Frage 2:
Wenn ich direkt einen neuen Wert berechnen lasse und davor absichtlich - qweljaöclsjh - oder sonstigen Text in die .txt schreibe, gibt er beim ersten drücken "Falsche Eingabe. Bitte eine Zahl eingeben" an und beim 2ten Button drücken funktioniert es.
Warum kommt beim ersten mal die Anzeige das die Eingabe nicht stimmt? Obwohl ja der Inhalt der .txt nicht stimmt?

Frage 3:
Das ich in meinen Funktionen an sich "zuviel" mache und diese nicht übersichtlich sind liegt daran - das ich es irgendwie lauffähig bekommen musste - ohne zu wissen wie ich Rückgabewerte bekomm.

Frage 4:
Wenn ich das über das .py starte - öffnet sich zusätzlich die Konsole - lässt sich das verhindern?


Ich weiß - es ist wieder 99% mies und schlecht und falsch - aber sollte ich diesesmal irgendwas richtig - oder zumindest besser gemacht habe wäre diese Info auch mal "schön" ..und evtl. etwas aufmunternd .


Gruß
Tengel
JonnyDamnnox
User
Beiträge: 68
Registriert: Sonntag 10. März 2013, 21:14

http://www.amazon.de/Programmieren-lern ... ren+lernen

Dort wird auch Tkinter besprochen. Ist die deutsche Übersetzung von "How to think like a computer scientist". Da wird nicht großartig rumgeschwafelt sondern leicht verständlich alles erklärt, Übungsaufgaben sind auch dabei. Kannst dir ja noch die eine rezension durchlesen.

Gruß
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Also is mein Code doch so schlimm ja?^^
xeike
User
Beiträge: 83
Registriert: Donnerstag 28. Februar 2013, 09:58

Tengel hat geschrieben: Das ich in meinen Funktionen an sich "zuviel" mache und diese nicht übersichtlich sind liegt daran - das ich es irgendwie lauffähig bekommen musste - ohne zu wissen wie ich Rückgabewerte bekomm.
Sehr schön, dass du Funktionen schreibst und diese benutzt.

Ich persönlich würde abfragen, ob die Datei "testtraffic.txt" existiert, dann öffnen und den Wert lesen. Wenn an irgend einer Stelle etwas falsch laufen würde, so würde ich mit einem "Basiswert" weiterrechnen, ihn aber noch nicht wieder in die Datei schreiben. Der Teil, bei dem du Basiswerte in die Datei schreibst, kommt sehr oft vor. Er braucht aber nur genau ein Mal vorzukommen.

Tk kenne ich nicht gut genug, um dabei zu helfen, aber unter http://wiki.python.org/moin/TkInter findest du bestimmt das Eine oder Andere Tutorial.


Xe
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@Tengel: Idealer weise sollte nur an einer Stelle im Programm testtraffic.txt gelesen und an einer geschrieben werden.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Dessen bin ich mir bewusst - nur hab ich immer noch nichts dazu gefunden wie ich Rückgabewerte von Funktionen die per Button aufgerufen werde bekomme - somit könnte ich höchstens versuchen mit globalen Variablen zu arbeiten - aber ich meine irgendwo gelesen zu haben das man etwas falsch macht wenn man auf globale Variablen angewiesen ist.
BlackJack

@Tengel: Den Rückgabewert von Funktionen die durch Schaltflächen aufgerufen werden bekommst Du *gar nicht*, denn die Tk-Hauptschleife ruft die ja auf, und die schert sich nicht um die Rückgabewerte. Ich bin nach wie vor der Meinung das man objektorientierte Programmierung drauf haben sollte, bevor man sich mit GUI-Programmierung auseinander setzt, denn dann hätte man ja einen Weg Zustand über „Funktionsaufrufe” hinweg zu speichern, ohne das global machen zu müssen.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Das zeug zur OOP hab ich verstanden - zumindest das was es im Buch gab.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Tengel: Verstanden hast du es erst dann, wenn du es sinnvoll anwenden kannst. Diese Fähigkeit traue ich dir aufgrund deiner bisherigen Beiträge eher nicht zu. Du wärst IMHO aber auch ein ziemliches Wunderkind, wenn du nach der kurzen Zeit tatsächlich schon OOP in "ernstzunehmendem" Ausmaß drauf hättest...
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Tengel:
Sorry, nein hast Du nicht ;)
Du magst die Beispiele dort nachvollziehen können, aber der Sinn dahinter ist Dir noch verschlossen.

BlackJacks Aussagen zur Objektorientierung würde ich hier noch um den Punkt ereignisgesteuerte Programmierung verschärfen. Während Du im "klassischen" Ansatz den Hauptprogrammablauf selber steuerst, bringen GUI-Toolkits wie Tkinter den Ablauf per Ereignisschleife mit (bei Tkinter dieser mainloop-Aufruf). Um das entsprechend umzusetzen, muss man das Programm anders denken. Dafür ist objektorientierte Programmierung gut geeignet - ohne ein basales Verständnis von eben dieser objektorientierten Programmierung führt es nur zu "Hä?" und "keine Ahnung, was da passiert".

Betrachte Deinen Code doch mal aus 1m Abstand. Was fällt Dir auf? Dateioperationen auf derselben Datei noch und nöcher. Da würde ich anfangen zu optimieren :)
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Hat zufällig jemand ein paar sinnvolle Übungsaufgaben für OOP parat?
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@Tengel: Schreib eine Klasse »Traffic« ;)
BlackJack

Eine Klasse `Logbook` oder `DriversLogbook` wäre wahrscheinlich näher am Problem. :-)
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Code: Alles auswählen

import sys
import tkinter

class Traffic():

    def startWert(self): 
        d = open("testtraffic.txt")
        self.startWert = d.readline()
        d.close()
        try:
            self.startWert = int(self.startWert)  
        except ValueError:
            self.startWert = 0
        except EnvironmentError:
            self.startWert = 0
        except FileNotFoundError:
            self.startWert = 0

    def standAnzeigen(self):
        anzeige["text"] = "Der momentane Verbrauch liegt bei "+str(self.startWert)+" mb"
      
    def neuerVerbrauch(self):
        neuerVerbrauch = eingabe.get()
        try:
            neuerVerbrauch = int(neuerVerbrauch)
            self.startWert += neuerVerbrauch
            anzeige["text"] = "Der momentane Verbrauch liegt bei"+ str(self.startWert) +" mb."
        except ValueError:
            anzeige["text"] = "Falsche Eingabe, bitte eine Zahl eingeben."

    def Resetten(self):
        anzeige["text"] = "Aktuellen Stand zurückgesetzt"
        startWert = 0

    def verbrauchSchreiben(self):
        d = open("testtraffic.txt","w")
        d.write(str(self.startWert))
        d.close()
    


Lasst mich raten - alles falsch -.-"

Hm - wenn ich mich nicht irre ist def startWert eigentlich eine Eigenschaft und keine Methode?
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Code: Alles auswählen

import sys
import tkinter

class Traffic():

    def startWert(self):
        d = open("testtraffic.txt")
        self.startWert = d.readline()
        d.close()
        try:
            self.startWert = int(self.startWert)  
        except ValueError:
            self.startWert = 0
        except EnvironmentError:
            self.startWert = 0
        except FileNotFoundError:
            self.startWert = 0

    def standAnzeigen(self):
        anzeige["text"] = "Der momentane Verbrauch liegt bei "+str(self.startWert)+" mb."
     
    def neuerVerbrauch(self):
        neuerVerbrauch = eingabe.get()
        try:
            neuerVerbrauch = int(neuerVerbrauch)
            self.startWert += neuerVerbrauch
            anzeige["text"] = "Der momentane Verbrauch liegt bei "+ str(self.startWert) +" mb."
        except ValueError:
            anzeige["text"] = "Falsche Eingabe, bitte eine Zahl eingeben."

    def Resetten(self):
        anzeige["text"] = "Aktuellen Stand zurückgesetzt"
        self.startWert = 0

    def verbrauchSchreiben(self):
        d = open("testtraffic.txt","w")
        d.write(str(self.startWert))
        d.close()

        main.destroy()


traffic=Traffic()
traffic.startWert()

main = tkinter.Tk()
main.title("Traffic")





kopf=tkinter.Label(main, text="Herzlich willkommen",width=20,bg="yellow", relief="ridge",height = 2,font="Arial 20 bold")
kopf.pack()

anzeige=tkinter.Label(main, text="Anzeigefeld", font="bold", relief="ridge", bg="white")
anzeige.pack(fill="x")

aktuell=tkinter.Button(main, text="Wert anzeigen", command=traffic.standAnzeigen)
aktuell.pack(fill="x")

neuerVerbrauch=tkinter.Button(main, text="Neuer Verbrauch",command=traffic.neuerVerbrauch)
neuerVerbrauch.pack(fill="x")

eingabe=tkinter.Entry(main)
eingabe.pack(fill="x")

resetten=tkinter.Button(main, text="Trafficstand resetten",command=traffic.Resetten)
resetten.pack(fill="x")

ende=tkinter.Button(main,text="Ende",command=traffic.verbrauchSchreiben)
ende.pack(fill="x")

main.mainloop()



So - im "Feldversuch" funktioniert es
Im vergleich zu den Vorgänger muss nun nicht überall aus der Datei gelesen - bzw. in die Datei geschrieben werden.
Ebenso hab ich Abstand davon genommen 50 verschiedene Variablen zu benennen - was damals alterWert - neuerWert - aktuellerWert etc. war beschränkt
sich nun auf startWert und neuerVerbrauch, mir ist klar das startWert ein wohl etwas ungünstiger Name ist aber da fehlts mal wieder an Kreativität :(

der startWert wird jetzt einmalig vor(!) der main aufgerufen - das bedeutet man muss den Wert nicht überall abspeichern(wäre er in der main - würde er ohne ein speichern immer wieder den "altenWert" laden richtig?

Der neue Wert wird in die Datei geschrieben - wenn man das Programm beendet.

Das einzige "Problem" das ich momentan sehe ist - der X Button, aber nun gut - ihr werdet mich schon auf meine 100 Fehler aufmerksam machen :)


Btw - ich hab Traffic genommen - weil ich mit Logbook irgendwie nich so vorwärts kam:(
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Das erste was mir sauer aufstößt; Du greifst aus Deiner Klasse auf Namen zu, welche weiter unten im Quelltext global gebunden werden. Das lässt sich nur sehr schwer nachvollziehen.

Traffic ist kein guter Name. Er beschreibt nicht das, was die Klasse darstellen soll. Traffic hat zu viele Aufgaben: Persistenz und (wirre) GUI-Anbindung.

Grüße ... bwbg
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo Tengel,
Dein neuer Code wirkt schon viel aufgeräumter, und dazu sind ja Klassen unter anderem auch da.
Trotzdem haben sich noch ein paar Fehler und auch Unschönheiten eingeschlichen.

Schau mal nach, welche Exception von welcher Zeile in »startWert« geworfen werden kann. Du schreibst selbst, dass »startWert« vor jeder anderen Funktion aufgerufen werden muss, und genau das erledigt die »__init__«-Methode. Du überschreibst im übrigen die Methode »startWert« mit der Instanzvariable »startWert«. Das sollte nicht sein. Der Dateiname ist ein guter Kandidat dafür in der __init__-Methode als Argument übergeben zu werden.

Wenn Du das geschafft hast, solltest Du alles, was mit GUI zu tun hat in eine zweite Klasse schreiben, so dass Dein __main__-Teil nur noch aus dem erzeugen dieser Klasse und dem Aufruf von mainloop besteht.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Traffic ist kein guter Name
wäre TrafficVerwaltung besser?

wie kann eine Klasse zu viele Aufgaben haben?

Code: Alles auswählen

Dein neuer Code wirkt schon viel aufgeräumte
Juhu :) endlich mal was positives - nach 100 Jahren ich kanns nicht fassen
Du überschreibst im übrigen die Methode »startWert« mit der Instanzvariable »startWert
?!?!
Der Dateiname ist ein guter Kandidat dafür in der __init__-Methode als Argument übergeben zu werden
mit dem Konstruktor in der Klasse?

Der wurde im Buch nur sehr "oberflächlich" genutzt
z. B.

Code: Alles auswählen

class Fahrzeug:
    def __init__(self,bez,ge):     #Konstruktormethode
        self.bezeichnung = bez
        self.geschwindigkeit = ge
    def beschleunigen(self, wert):
        self.geschwindigkeit += wert
        self.ausgabe()
    def ausgabe(self):
        print(self.bezeichnung,self.geschwindigkeit,"km/h")

BlackJack

@Tengel: Ich würde die `__init__`-Methode nicht Konstruktor nennen. Die konstruiert kein neues Objekt, sondern initialisiert eines, welches es schon gibt und das ihr als erstes Argument übergeben wird. In anderen Sprachen könnte man das als semantische Haarspalterei bezeichnen, in Python gibt es allerdings auch eine `__new__()`-Methode, die *tatsächlich* ein Konstruktor ist.

Die `__init__()`-Methode ist wichtig. In der sollte ein Objekt vollständig initialisiert werden. Nachdem die abgelaufen ist, sollten alle Attribute existieren und sich das Objekt in einem konsistenten, benutzbaren Zustand befinden. Im Grunde der einzige Grund *keine* `__init__()` zu haben wäre eine Basisklasse deren `__init__()`-Methode genau das schon leistet, oder wenn man eine „mix in”-Klasse schreibt, die nicht eigenständig für sich existieren kann, sondern immer als zusätzliche Basisklasse von anderen Klassen verwendet werden muss.

Ad `startWert()`: Du hast auf dem Objekt eine Methode `startWert()` und in dieser Methode bindest Du einen Zahlenwert an das Attribut `startWert`. Damit hast Du die Methode überschrieben. Die kannst Du nur einmal aufrufen, danach hat das Objekt unter diesem Namen nicht mehr die Methode sondern den Zahlenwert gespeichert. Man kann nicht zwei verschiedene Sachen gleichzeitig an den selben Namen beziehungsweise das selbe Attribut binden.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Interessant
__init__ wirds als Konstruktor
__del__ als Desktruktor im Buch beschrieben
naja - das Buch wird wohl einen guten Türstopper/Briefbeschwerer abgeben - heute ist mein neues Buch gekommen - das werde ich nochmal von vorne durch arbeiten - da ich einiges ja schon "kenne" sollte es schneller gehen und evtl. kann ich so einge "Missstände" ausmerzen mal sehen

stimmt - da hab ich wieder nicht aufgepasst :( ich werde die Methode mal umbenennen
Antworten