Problem bei Objekten und Methoden

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.
Antworten
StarFox88
User
Beiträge: 3
Registriert: Sonntag 28. Dezember 2014, 15:56

Eines gleich vorweg, ich arbeite an einer Studienarbeit in einer Gruppe, wo wir ein Bauzeitenplan als Netzplan programmieren wollen. Da aber gerade meine Teamkollegen nicht erreichbar sind, ich aber an einem Fehler verzweifle, möchte ich mich mal an dieses Forum wenden. Ich möchte aber lediglich wissen, woher der Fehler kommt, dann komm ich vll selber auf die Lösung.

Das ganze spielt sich der Canvas ab, wo man über einen Klick auf einen Butten ein Eingabefeld erzeugen kann, den man dann per drag&drop organisieren kann.
Dazu hab ich folgendes Objekt mit den Methoden geschrieben:
(Ich hab die Canvas hier Fenster genannt.)

Code: Alles auswählen

from tkinter import *


##Grafik Oberfläche
MainWindow=Tk()
Fenster=Canvas(width=1000, height=600, bg="lightgray")
Fenster.pack(expand=YES, fill=BOTH)

##Hinzufügen-Fenster##
class HinzufügenFenster:
    def start(self,x,y):
        self.x=x
        self.y=y
        self.ID=GrafikHinzufügen=Fenster.create_rectangle(0,0,40,20,fill="blue")

##Verbindungen-Hinzufügen##
class HinzufügenVerbindung:
    def start(self,x,y):
        self.x=x
        self.y=y
        self.ID=GrafikVerbindung=Fenster.create_rectangle(40,0,80,20,fill="lightblue")

##Positionen##
class Position:
    def neu(self,x,y): ##Eingabefeld erzeugen##
        self.x=x
        self.y=y
        GrafikFeld=Fenster.create_rectangle(x,y,x+60,y+20,fill="white", width=2)
        self.markiert=False
        Fenster.update()
        return GrafikFeld ##zum späteren abspeichern in einer Liste##
    def schieben(self,x,y): ##verschieben##
        self.x=x
        self.y=y
        Fenster.coords(self.ID,x,y,x+60,y+20)
        Fenster.update()
    def prüfe(self,x,y): ##Rahmen bei Cursorkontakt hervorheben##
        if 0<=x-self.x<=60 and 0<=y-self.y<=20: 
            Fenster.itemconfig(self.ID, outline="red")
            self.markiert=True
        else:
            Fenster.itemconfig(self.ID, outline="black")
            self.markiert=False
        Fenster.update()
        
##Erzeugen der ersten Position##
Feld=Position()
GrafikFeld=Feld.neu(100,100)
Abschnitt=1
Name="Name"
Dauer="Dauer"
Einheit="Einheit"
Feld=[GrafikFeld, Abschnitt, Name, Dauer, Einheit] ##zum Abspeichern der Eigenschaften einer Position##
Felder=[Feld] ##Alle Positionen gemeinsam abgespeichert##

##Funktionen für Keybindings##
def Ziehe(event):
    for Feld in Felder:
         if Position.markiert:
             Position.schieben(event.x, event.y)
             
def Bewege(event):
    for Feld in Felder:
        Position.prüfe(event.x,event.y) 
        xPosition=event.x
        yPosition=event.y

def LinksKlick(event):
    if 0<=event.x<=40 and 0<=event.y<20: ##Hinzufügen von Feldern##
        Position.neu(100,100) 
        Felder.append(Feld) ##Objekt Feld and Liste Felder anhängen##
        Felder[len(Felder)]="Feld"
        print(len(Felder)) ##test auf Listenlänge##
        print(Felder) ##test auf Listeninhalt##
        Fenster.update()
    elif 40<=event.x<=80 and 0<=event.y<20: ##Hinzufügen von Verbindungen##
        Fenster.update()

##Button zum Hinzufügen##
HinzufügenFenster=HinzufügenFenster()
HinzufügenFenster.start(0,0)
HinzufügenVerbindung=HinzufügenVerbindung()
HinzufügenVerbindung.start(0,40)

##Keybindings##
Fenster.bind("<B1-Motion>", Ziehe)
Fenster.bind("<Motion>", Bewege)
Fenster.bind("<Button-1>",LinksKlick) 

MainWindow.update()
MainWindow.mainloop()
Das ist eigentlich das ganze Objekt zur Zeit, und wenn ich es jetzt z.B. über Position.neu(100,100) aufrufen möchte und die beiden Zahlen die X/Y-Koordinaten sind, bekomme ich folgenden Fehler:

"Traceback (most recent call last):
File "C:/..., line 55, in <module>
GrafikFeld=Position.neu(100,100)
TypeError: neu() missing 1 required positional argument: 'y'"

und ich weiß nicht, wie dieser entsteht. Denn wenn ich bei Position.neu einen dritten eintrag mache erhalte ich entweder:"AttributeError: 'int' object has no attribute 'x'" bei Zahlen oder: "NameError: name 'self' is not defined" wenn ich (self,100,100) abfrage.

Wie am Anfang erwähnt, reicht mir vermutlich schon zu wissen wie dieser Fehler entsteht bzw ich erkenne ihn vermutlich einfach nicht, weil ich den Wald vor lauter Bäumen nicht sehe.
Zuletzt geändert von StarFox88 am Sonntag 28. Dezember 2014, 19:08, insgesamt 2-mal geändert.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Weil Position der Name der Klasse und keine Instanz ist und die Methode "neu" nur in einer Instanz sinnvoll ist, deshalb besitzt sie doch 2 Parameter und die Referenz(self) auf die Instanz.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@StarFox88
``self`` ist nicht einfach nur so da. Wenn Du eine Methode (eine Klassenfunktion) aufrufst, übergibt Python dieser Methode als erstes Argument die Instanz, über die diese Methode aufgerufen wird. Und der Name dieses ersten Arguments ist ``self``. Danach kommen erst potentiell weitere Argumente.

Wenn Du also, wie Du schreibst, ``Position.neu(100, 100)`` aufrufst, erhältst Du

Code: Alles auswählen

>>> class Position:
...     def neu(self, x, y):
...         self.x = x
...         self.y = y
... 
>>> Position.neu(100, 100)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method neu() must be called with Position instance as first argument (got int instance instead)
weil Du eine Methode aufrufst, die an keine Instanz gebunden ist. Also:

Code: Alles auswählen

>>> p = Position()
>>> p.neu(100,100)
>>> p.x
100
>>> p.y
100
Es ist also immer hilfreich, uns erstens den tatsächlich verwendeten Code und zweitens die tatsächlich erscheinende Fehlermeldung zu posten... ;-)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
StarFox88
User
Beiträge: 3
Registriert: Sonntag 28. Dezember 2014, 15:56

Ach so, wollte den Thread nicht zu unübersichtlich machen, daher hatte ich nur den Teil kopiert, welcher den Fehler hervorruft. Habe aber nun den Startpost entsprechend bearbeitet.
Kurzer Nachtrag, grad einen Fehler gefunden in Zeile 48 und korrigiert, doch nun bekomme ich andere Fehler an denen ich erstmal weiter arbeiten möchte.
Zuletzt geändert von StarFox88 am Sonntag 28. Dezember 2014, 19:17, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@mutetella: das ist Python3 und da ist die Fehlermeldung tatsächlich

Code: Alles auswählen

TypeError: neu() missing 1 required positional argument: 'y'
@StarFox88: Klassen haben nicht umsonst die __init__-Methode um ein Objekt zu initialisieren. Sich selbst etwas mit "neu" auszudenken ist nicht nur unsinnig, sondern macht, wie Du siehst auch noch Probleme. Die Instanz an den selben Namen (HinzufügenFenster) wie die Klasse zu binden ist auch nicht gerade hilfreich, weil Du dann nicht mehr auf die Klasse zugreifen kannst.
Wenn Du nachträglich einen Beitrag änderst, versteht jemand, der das später liest nicht mehr, worauf sich die Antwort bezieht, weil die Frage plötzlich ganz anders aussieht.

Weiter sollte kein Code auf Modulebene ausgeführt werden. Das verführt nur dazu, globale Variablen zu verwenden, anstatt Objekte sauber als Parameter zu übergeben. Die Klassen sehen auch nicht wie Klassen aus, mehr wie Funktionen. Das merkt man auch daran, dass Du ständig direkt auf die Klassen zugreifst, anstatt über erstellte Instanzen. Die Liste `Feld` ist auch seltsam und die for-Schleifen über diese Liste umsomehr, zumal Feld darin gar nicht verwendet wird.
Als gut gemeinter Tipp: lösche alles nochmal, lerne erstmal Objektorientierte Programmierung und fang dann frisch von vorne an.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Sirius3
Ok, das wusste ich noch nicht...

@StarFox88
Was bezweckst Du mit den ``HinzufügenFenster``, ``HinzufügenVerbindung`` und ``Postition`` Klassen? Wenn der Name einer Klasse ausdrückt, dass da etwas getan wird, dann ist das oft ein Zeichen dafür, dass eine Klasse dafür nicht das Richtige ist. Und wenn dann in den Klassen noch nicht einmal das geschieht, worauf sich der Name bezieht, dann ist der Wurm drin!

Wie auch immer: Der Code, den Du zeigst, ist so nicht ansatzweise zu gebrauchen. Ich empfehle Dir, Dich einmal mit dem Python Tutorial zu beschäftigen und dort einmal unter anderem nachzuschlagen, wofür Klassen und Funktionen jeweils verwendet werden und was es mit der Einrückung in Python auf sich hat. Das ist zwar anfangs etwas unbefriedigend, weil man ja an seinem Programm arbeiten möchte, aber anderst wirst Du nicht weiterkommen.

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
StarFox88
User
Beiträge: 3
Registriert: Sonntag 28. Dezember 2014, 15:56

@Sirius3
danke, ich werde mich darüber mal informieren und vom Ansatz an anders vorgehen.
Antworten