Canvas beerben analog zu Java JComponent???

Fragen zu Tkinter.
Antworten
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

Hallo, wenn ich in Java z. B. eine Klasse Rechteck schreiben möchte, ist es ja Standard, JComponent zu beerben und die paint-Methode zu überschreiben.
Ist ein analoges Vorgehen in Python mit tkinter auch möglich? Canvas scheint man ja nicht zu beerben, soweit meine Recherche richtig ist...
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fffg: Du kannst von `Canvas` erben wenn das für den einsatzzweck Sinn macht. Aber eine `paint()`-Methode macht keinen Sinn weil das `Canvas` schon selbst macht, das Neuzeichnen wenn es nötig ist. `Canvas` ist auch Vektorgrafik und keine Pixelgrafik.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

Vielen Dank!
1. Was wäre denn ein Kontext, in dem erben vin canvas sinnvoll wäre?
2. Gibt es andere grafikmodule, mut denen das eingangs beschriebene Vorgehen sinnvoll wäre?
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fffg: Ad 1. Wenn man irgendetwas mit einem `Canvas` implementieren möchte bei dem man den um Methoden erweitert. Das kann alles mögliche sein.

Ad 2. Was willst Du denn eigentlich machen? Python ist nicht Java und keines der GUI-Rahmenwerke ist Swing. Also ausser natürlich wenn Du Jython nimmst und da von JComponent ableitest natürlich. 😜

Die Frage klingt nach ich habe eine Lösung und suche ein Problem. Oder in diesem Fall nach ich habe eine Lösung und suche ein GUI-Rahmenwerk mit dem die auch funktioniert. Normalerweise hat man ja ein Problem und ein GUI-Rahmenwerk und sucht dann eine Lösung.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

Naja,
wie mache ich es denn z. B. wenn ich eine geometrische Figur zeichnen will, die ich zur Laufzeit modifizieren will?
In Java beerbe ich JComponent und überschreibe die Paint-Methode. Dort kann ich festlegen, wie das Ding prinzipiell aussehen soll.
Dann kann ich von einer anderen Klasse (später) aus auf das referezierte Kreisobjekt zugreifen und mit den vorhandenen Methoden von JComponent zB die Position verändern.
Wie mache ich so etwas in tkinter?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei tkinter brauchst du keine Vererbung. Du zeichnest in ein Canvas die geometrischen Objekte und kannst sie auch nachträglich über ihre ID verändern.
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

Kann ich dann nicht - wie im obigen Beispiel - den Code in z. B. eine Klasse Rechteck auslagern und dann in der "Hauptklasse" nur sowas schreiben wie rechteck.PositionSetzen...?
In Java könnte ich ja zB separate Klassen für Rechteck, Kreis, Dreieck, ... erstellen und dann in der Hauptklasse Objekte erzeugen und verwalten und diese dann modifizieren.
Muss ich das in Python (tkinter) alles in derselben Klasse machen?
Objektorientiert "schöner" wären doch die eigenen Klassen..
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@fffg: Du kannst machen was Du willst. Und natürlich auch die ID und das Canvas-Objekt in Objekten kapseln die geometrische Formen repräsentieren. Dafür muss man nicht von `Canvas` ableiten. `rechteck.setze_position(…)` kannst Du in einer Methode in einer von `Canvas` abgeleiteten Klasse aufrufen, oder in irgendeiner anderen Methode oder Funktion. Kommt halt darauf an wie *Du* das gestalten möchtest. Was wiederum ein bisschen von den Anforderungen abhängt.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

vielen Dank aber ich komme leider immer noch nicht zurecht.
Ziel: Eine Spielfläche entwickeln, auf der ich zwei Bälle (Kreise) erstellen und dann positionieren kann (mit tkinter)

Ich habe hier einen Versuch gemacht, der aber Quatsch ist, weil ich wohl beide Bälle in ein Canvas packen muss (damit sie sich auch überlappen können)
also muss ich das canvas wohl in Spiel erstellen.
Außerdem ist es auch Quatsch, von Canvas zu erben, weil ja nicht Canvas eine PositionSetzen Methode hat sondern das Oval.

Code: Alles auswählen

from tkinter import *

class Ball(Canvas):
    
    def __init__(self, master, x, y, r):
        super().__init__(master, width = 2*r, height = 2*r)
        
        self.create_oval(x-r, y-r, x+r, y+r, width=1)
        


class Spiel:
    def __init__(self):
        master = Tk()

        ball1 = Ball(master, 50, 50, 50)
        ball2 = Ball(master, 25, 25, 25)
        #...
        ball1.pack()
        ball2.pack()
        mainloop()


k = Spiel()
ich müsste es so hinbekommen, dass ich beim Erstellen eines Kreisobjekts eine id zurückbekommen, so wie ich sie beim Aufruf von create_oval zurückbekomme.
das ginge über Methoden in der Klasse Spiel, wie aber mit eigenen Klassen?
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Man benutzt keine *-Importe weil man damit verschleiert, woher welcher Name stammt. __init__ ist dazu da, ein Objekt zu initialisieren, nicht das es ewig läuft. Das mainloop gehört da nicht rein
Und warum willst du unbedingt etwas vererben?
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sirius3: Javaprogrammierer wollen immer was vererben, und alles in Klassen stopfen. Da können die aber nichts für, die sind so sozialisiert worden. 😉

@fffg: Dein Ball muss Zugriff auf das `Canvas`-Objekt haben und die ID die beim erstellen des Kreises zurückgegeben wird. Also etwas in dieser Richtung:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk


class Ball:
    def __init__(self, canvas, x, y, radius):
        self.canvas = canvas
        self.item_id = self.canvas.create_oval(
            x - radius, y - radius, x + radius, y + radius, width=1
        )


def main():
    root = tk.Tk()
    canvas = tk.Canvas(root)
    canvas.pack()

    ball_a = Ball(canvas, 50, 50, 50)
    ball_b = Ball(canvas, 25, 25, 25)
    ...

    root.mainloop()


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

ok, danke, aber wie greife ich dann auf den jeweiligen Ball zu?
Statt in der Main-Methode hätte ich ja z. b. die Bälle in einer Klasse Spiel erstellt, die vllt. eine Methode
positioniereAlleBälleZufällig hat.
Ich hätte angenommen, dass ich dafür dann die item_id brauche.
Aber wie soll ich das machen? Ich könnte zwar als öffentliches Attribut darauf zugreifen, aber das ist doch nicht sinnvoll?
Außerdem klappt es bei mir selbst dann nicht, ich kann keine Methoden aufrufen.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Ob du jetzt das was in main steht wieder in einer Klasse Spiel packst, ist doch nebensächlich, __blackjack__ hast die Klasse nur weggelassen, weil sie für das Beispiel keinen Mehrwert bietet.
Und niemand hindert dich daran, der Klasse Ball auch noch eine Methode `positioniere` zu geben.
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

Dem Ball kann ich eine solche Methode schon geben, aber genau mein Ziel ist es doch, vorhandene Methoden nutzen zu können und nicht alles nochmal implementieren zu können.
Daher wollte ich das ja ursprünglich analog zu Java machen, wo ich JComponent beerbe und meine Klasse Ball dann automatisch alle Methodne wie Positionieren() und setColor und was weiß ich alles hat.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

Diese Methoden gibt es halt bei tkinter nicht direkt, von daher macht es Sinn, solche Methoden zu definieren.
fffg
User
Beiträge: 11
Registriert: Montag 21. Dezember 2020, 15:29

ok, dann muss man das wirklich grundlegend anders strukturieren.
Oder bietet ein anderes GUI-Modul hier mehr Analogie?
Antworten