Probleme mit der richtigen Vererbung

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
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hi,

ich möchte mir gerne für tkinter eine Klasse erzeugen, mit der ich einen Schieberegler erstellen kann. Leider habe ich so meine Probleme mit der Vererbung von Elternklassen.

Meine Klasse heisst Balkenanzeige, und weil ich einige Elemente von tkinter brauche - z.B. die .pack-Methode, habe ich tkinter mit in die Klammern bei class ... (tkinter) eingefügt, weil ich so dachte, dass dann die Funktionen von tkinter mit vererbt werden und verfügbar sind.

Leider klappt das nicht - ich bekomme die Fehlermeldung für Zeile 5 - die Init-Prozedur meiner Klasse:
module.__init__() takes at most 2 arguments (3 given)
Ich weis grad gar nicht, was ich falsch mache. Ich möchte aus der Hauptfunktion heraus mir mittels der Klasse ein tkinter-Canvas-rectangle erzeugen. Kann mir vielleicht jemand von Euch einen Tipp geben, was ich bei der Vererbung falsch verstanden haben könnte?


Code: Alles auswählen

import tkinter
from tkinter import Canvas as canvas

class Balkenanzeige (tkinter):
    def __init__(self,
                 parent,
                 x_1=0, x_2=100,
                 y_1=0, y_2=50,
                 linewidth=3,
                 linecolor="black",
                 color_left="green",
                 color_right="blue",
                 fillstate=30):
        self.parent = parent
        self.x_1 = x_1
        self.x_2 = x_2
        self.y_1 = y_1
        self.y_2 = y_2
        self.linewidth   = linewidth
        self.linecolor   = linecolor
        self.color_left  = color_left
        self.color_right = color_right
        self.fillstate   = fillstate

    def __del__(self):
        pass

    def zyli_show (self):
        print("in show")
        self.parent.Canvas.create_rectangle (self.x_1, self.y_1,
                                             self.x_2, self.y_2,
                                             fill = self.linecolor,
                                             outline= self.linecolor)

def myfunc ():
    master = tkinter.Tk()
    my_zyli = Balkenanzeige(master)
    my_zyli.zyli_show()
    my_zyli.pack()
    master.mainloop()

if __name__ == "__main__":
    myfunc()
BlackJack

@Papp Nase: Vererbung funktioniert nur mit Klassen und `tkinter` ist ein Modul und keine Klasse.

Von der `__del__()`-Methode sollte man übrigens die Finger lassen. Alleine das was Du da geschrieben hast ist schon potentiell ”gefährlich” weil durch das vorhandensein einer eigenen Implementierung schon Speicherlecks entstehen können.

Edit: Einen Schieberegler würde man wohl am besten mit einem `Tkinter.Scrollbar`-Widget basteln.

Edit2: Oder man nimmt einfach ein `Tkinter.Scale`. ;-)
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Papp Nase hat geschrieben:Von der `__del__()`-Methode sollte man übrigens die Finger lassen
ok, ich merks mir für die Zukunft - danke :-)
Papp Nase hat geschrieben:Edit: Einen Schieberegler würde man wohl am besten mit einem `Tkinter.Scrollbar`-Widget basteln.Edit2: Oder man nimmt einfach ein `Tkinter.Scale`.
Das mag sein, ich möchte aber selber lernen und will mir selber eine Schiebeanzeige programmieren.

Ich habe mir jetzt eine Klasse Balkenanzeige gebaut, die einige Funktionen hat und wie ich denke - recht gut funktioniert. Ich habe an die Klasse zwei Funktionen angefügt, mit denen ein Wert addiert oder subtrahiert werden kann, wenn man in dem Fenster die entsprechenden Buttons aufruft. Ich hatte zunächst das Problem, dass der Wert nicht aktualisiert wurde. Ich rufe jetzt einfach in der jeweiligen def die Funktion self.create() auf, die dann das Bild nochmal neu zeichnet.

Meine Frage - ist diese Art der Aktualisierung des Balkenelements so gut oder gibt es eine andere - bessere Möglichkeit?

Hinweis - der grüne Balken, der sich verschiebt - verschiebt sich noch nicht optimal, da er bei 100 Prozent nicht exakt am rechten Rand ist und bei 0 Prozent etwas zu weit nach links geht - das ist mir jetzt erstmal egal - falls jemand das als Problem sieht - mir geht es jetzt hier erstmal um die Aktualisierung.

Falls ihr mir wertvolle Tipps geben könntet, würde ich mich sehr darüber freuen.

Code: Alles auswählen


import tkinter
from functools import partial

class Balkenanzeige ():   #   (tkinter):
    def __init__(self,
                 parent=tkinter.Canvas,
                 x_1=0, x_2=100,
                 y_1=0, y_2=50,
                 linewidth=3,
                 linecolor="black",
                 color_left="green",
                 color_right="blue",
                 fillstate=30,
                 inkrement=1):

        self.parent = parent
        self.x_1 = x_1
        self.x_2 = x_2
        self.y_1 = y_1
        self.y_2 = y_2
        self.linewidth   = linewidth
        self.linecolor   = linecolor
        self.color_left  = color_left
        self.color_right = color_right
        self.fillstate   = fillstate
        self.inkrement   = inkrement
        self.create()

    def create (self):
        self.parent.create_rectangle(self.x_1, self.y_1,
                                     self.x_2, self.y_2,
                                     fill    = self.linecolor,
                                     outline = self.linecolor)
        self.parent.create_rectangle(self.x_1+self.linewidth, self.y_1+self.linewidth,
                                     self.x_2-self.linewidth, self.y_2-self.linewidth,
                                     fill = self.color_right,
                                     outline = "white")
        # linke Seite:
        x_left = (int ((self.x_2-self.x_1-(2*self.linewidth)+2)*self.fillstate/100))+self.x_1
        self.parent.create_rectangle(self.x_1+self.linewidth, self.y_1+self.linewidth,
                                     x_left, self.y_2-self.linewidth,
                                     fill = self.color_left,
                                     outline = "yellow")
    def set_fillstate(self, fillstate):
        self.fillstate = fillstate
        self.create()

    def get_selfstate(self):
        return self.fillstate

    def addiere1(self):
        if self.fillstate >=100-self.inkrement:
            self.fillstate = 100
        else:
            self.fillstate += self.inkrement
        print (self.fillstate)
        self.create()

    def subtrahiere1(self):
        if self.fillstate <= self.inkrement:
            self.fillstate = 1
        else:
            self.fillstate -= self.inkrement
        print (self.fillstate)
        self.create()

    def set_inkrement(self, inkrement):
        self.inkrement = inkrement
    def get_inkrement (self):
        return self.inkrement

def myfunc ():

    master = tkinter.Tk()
    master.title ("myTitle")

    myslider = tkinter.Canvas(master)
    myslider2 = Balkenanzeige (myslider, x_1=50, y_1=50, x_2=201, y_2=100)
    myslider2.set_fillstate(10)
    myslider2.set_inkrement(10)
    # myslider2.create()
    myslider.pack()

    myButton1 = tkinter.Button (master, text=" +1", command=myslider2.addiere1)
    myButton2 = tkinter.Button (master, text=" -1", command=myslider2.subtrahiere1)
    myButton1.pack()
    myButton2.pack()

    inkrement_entry = tkinter.Entry (master)

    # Hilfsfunktion:
    def change_inkrement(event):
        myslider2.set_inkrement(int (event.widget.get()))
        # myButton1.setvar (text=event.widget.get())


    inkrement_entry.insert(0, myslider2.get_inkrement())
    inkrement_entry.bind ('<Return>', change_inkrement)
    inkrement_entry.pack()



    master.mainloop()

if __name__ == "__main__":
    myfunc()
BlackJack

@Papp Nase: Immer neue Rechtecke zu erzeugen ist kein gute Idee. `Canvas` ist Vektorgrafik und keine Pixelgrafik, die ganzen Rechtecke werden immer mehr und verbrauchen Speicherplatz und Rechenzeit beim immer wieder alle bisherigen Rechtecke übereinanderzeichnen, obwohl man eigentlich nur drei sieht. Die `create_*()`-Methoden geben eine ID zurück über die man die Grafikobjekte mit der `itemconfigure()`-Methode verändern kann.

Der Default-Wert vom `parent`-Argument macht keinen Sinn. Mit der Klasse kann man dort gar nichts anfangen. Selbst ein `Canvas`-Exemplar würde dort keinen Sinn machen, weil das dann ja das selbe für alle `Balkenanzeige`-Exemplare wäre.

Der Name ist nicht so gut. In der Hierarchie der Widget-Exemplare heisst das übergeordnete Objekt bei Tk zwar konventionell `master`, aber ich finde `parent` trotzdem verwirrend. Ich würde das einfach `canvas` nennen.

Die Argumente für die Position und Aussmasse finde ich unpraktisch. Eine Koordinate und Höhe und Breite wären für den Benutzer mit weniger Rechnerei verbunden. Beziehungsweise würde ich die Koordinate ganz weglassen und das `Canvas`-Exemplar nicht von aussen übergeben sondern in der `__init__()` mit der angegebenen Grösse erstellen. Und vielleicht auch von `Canvas` erben. Oder von `Frame`.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Papp Nase: und dann noch die ganzen formalen Dinge: vor öffnende Klammern gehören keine Leerzeichen, und am Anfang einer Funktion auch keine Leerzeile. 'get_fillstate', 'get_inkrement' und 'set_inkrement' sind überflüssig, weil auch direkt auf fillstate und inkrement zugegriffen werden kann, statt 'set_fillstate' könnte man 'fillstate' in ein Property umwandeln. 'addiere1' und 'subtrahiere1' haben falsche Namen, da ja ein Inkrement und nicht 1 addiert, bzw. subtrahiert wird. Sobald inkrement negativ ist, funktionierten auch die Tests nicht mehr. Einfacher wäre es, die Prüfung gleich in 'set_fillstate' einzubauen, und 'addiere' bzw. 'subtrahiere' nur noch 'set_fillstate' aufrufen zu lassen. Damit vereinfacht sich auch, wo überall 'create' aufgerufen wird.

Code: Alles auswählen

...
    def set_fillstate(self, fillstate):
        self.fillstate = max(0, min(100, fillstate))
        self.create()

    def addiere(self, amount=1):
        self.set_fillstate(self.fillstate + amount * self.inkrement)

    def subtrahiere(self, amount=1):
        self.set_fillstate(self.fillstate - amount * self.inkrement)
...
Antworten