sich überlappende elemente

Fragen zu Tkinter.
Antworten
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

Hallo,

ich habe jetzt schon viel zeit in ein Problem gesteckt und komme mit google und SuFu nicht weiter.

Ich möchte in einem fenster (480x320) verschiedene Elemte anzeigen lassen die unabhängig voneinander verändert werden sollen (rotation)

um es verständlicher zu machen:

Code: Alles auswählen

import tkinter
import time

ares = tkinter.Tk() #hauptfenster
ares.geometry("480x320")

#-Funktionen
def uiPack(cc):
    button_menu.config(fg=color(cc))
    
def dayNight_switch():
    global day

    if day == True:
        uiPack("txt-night")
        day = False
    elif day == False:
        uiPack("txt-day")
        day = True

ares = tkinter.Tk()
ares.geometry("480x320")

frame_nav = tkinter.Frame(ares)
frame_menu = tkinter.Frame(ares)

button_menu = tkinter.Button(frame_nav, text="+ + +", bg=red, fg=white, border="0")
button_menu.pack()
test = tkinter.Label(frame_menu, text="Hallo welt!", bg=red, fg=white)

frame_nav.place(relx=0.5, rely=0.5)
frame_menu.place(relx=0.5, rely=0.5)

ares.mainloop()
Ist zwar nicht 100% der original Code aber spiegelt es 1a wieder.

Anstatt des label "test" soll später eine bilddatei stehen die in der in der Mitte durchsichtig ist (png) dieser soll sich anhand eines bestimmten wertes noch drehen (live) und immer wieder updaten

Meine Frage(n):
  • Wie bekomme es gelöst dass sich die (aktuell) Frames überlappen (sind frames überhaupt der richtige Ansatz?)?
  • Wie kann ich das bild beim erstellen skalieren?
  • Wie kann ich das bild rotieren lassen (nicht dauerhaft sondern nur wenn sich wert x ändert (soll von einem sensor kommen))

Geht nicht zu hart mit mir ins gericht XD, bin neu!

Aber trotzdem schonmal jetzt vielen dank. :D

Mit freundlichen grüßen
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich denke mal das hier hilft: https://stackoverflow.com/questions/157 ... -animation

Sowohl fuer die Frage nach Ueberlagerung (einfach nacheinander malen) als auch Rotation). Wobei du wenn du nicht rotieren willst trotzdem rotierst, aber eben so viel/weit wie vorher.
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

WOW.
Das ging schnell.

Ich werde es mir in ruhe zu gemühte führen und den überarbeiteten code reinstellen =)
ggfs mit weiteren fragen

auf jedenfall schonmal dickes danke
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

Also ich habe mir jetzt den Code die letzten Tage angesehen und viel herumprobiert damit.
Was die rotation angeht ist das teil genial =) vielen dank schonmal dafür!

Das was ich jetzt nicht gelöst bekomme ist, dass ich zwar zwei grafiken übereinander habe aber diese nicht sehe da die eine grafik die andere in gänze "überlagert".
Hab es jetzt mit transparenz probiert was leider nicht funktioniert da ja nur das Hauptfenster dann transparent ist und ich dann die darunter liegende grafik trotzdem wieder nicht sehe.

Code: Alles auswählen

import time
import tkinter
from PIL import Image, ImageTk

class SimpleApp(object):
    def __init__(self, master, filename, **kwargs):
        self.master = master
        self.filename = filename
        self.canvas = tkinter.Canvas(master, width=500, height=500, bg="green")
        #self.canvas.pack()
        #self.canvas.configure(bg="green")
        self.canvas.place(relx=0.5, rely=0.5, anchor="center")
        

        self.process_next_frame = self.draw().__next__  # Using "next(self.draw())" doesn't work
        master.after(1, self.process_next_frame)

    def draw(self):
        image = Image.open(self.filename)
        angle = 0
        print(self.process_next_frame)
        while True:
            tkimage = ImageTk.PhotoImage(image.rotate(angle))
            canvas_obj = self.canvas.create_image(250, 250, image=tkimage)
            self.master.after_idle(self.process_next_frame)
            yield
            self.canvas.delete(canvas_obj)
            angle += -0.5
            angle %= 360
            time.sleep(0.002)


class main():
    def __init__(self):
        root = tkinter.Tk()
        root.configure(bg="black")
        root.geometry("750x750")
        f1 = tkinter.Frame(root, bg="green")
        f1.place(relx=0.5, rely=0.5, anchor="center")
        SimpleApp(root, '../images/es.png')
        SimpleApp(root, '../images/kreis.png')
        root.mainloop()
        
        
main()
Welchen anstaz kann ich mal probieren?
(Ich bin äuserst lernwillig und nehme auch sehr dankbar antworten wie "Schau dir mal das Thema xxx an" an)

nochmals danke
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dragback: Du hast da ja nicht zwei Grafiken die sich überlagern sondern zwei `Canvas`-Widgets die sich überlagern. Du darfst da nur *einen* `Canvas` haben.

Und `place()` ist eine schlechte Idee. Verwende `pack()` und/oder `grid()` (nicht im gleichen Container-Widget!) und lass auch das `geometry()` beim Hauptfenster weg.

Ich finde das mit der Generatormethode die auf eine Referenz von einem Ergebnis von sich selbst zugreift um den Code voran zu treiben ja ziemlich verwirrend. Und ein `time.sleep()` hat da grundsätzlich nichts verloren. Arbeite mit `after()` und gibt da eine entsprechende Verzögerung an statt mit `time.sleep()` die GUI zu blockieren.

Insbesondere wenn es am Ende mehrere Objekte werden sollen die man mit selbstgebastelten Generator-Coroutinen antreiben will, sollte man das hinterlegen des nächsten Aufrufs per `after()` und das antreiben der Coroutine(n) trennen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

Danke für die Infos
Wie gesagt der Code soll erst einmal generell funktionieren und dann den feinschliff bekommen
Der Punkt mit "after" steht bei mir schon auf der todo

Mich würde wirklich interessieren wie ich die bilddatein übereinander gelagert bekomme ohne dass sie sich gegenseitig ausblenden / verdecken

Das "place" hatte ich eigentlich dafür genommen Umd später es dynamisch zu halten bzgl. der Auflösung.
Bekomme ich das auch ohne spätere Anpassung mit grid hin?

G
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

__blackjack__ hat doch schon gesagt, woran es liegt. Du darfst nicht mehrere Canvas nehmen. Hast du das schon probiert?
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dragback: Was hält denn `place()` bezüglich der Auflösung dynamisch? Du gibst momentan zwei Grössen fest vor: den `Canvas` und das Fenster. Normal wäre es `pack()` oder `grid()` zu benutzen dann ist das Fenster automatisch so gross, dass alles rein passt. `place()` macht hier einfach nur mehr Arbeit.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

🤔Klingt hier logisch
Ich danke für den input und melde mich dann die Tage mit hoffentlich meiner Lösung oder neuen Fragen 🙈

😤 👍 Ihr seid klasse
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

So ich habe mein Problem dann auch mal in den griff bekommen :lol:
Danke für eure Hilfestellung dabei!

Ich weis dass der Code "hässlich" ist und ich kann euch beruhigen SO wird er nie den weg in das Fertige Programm finden.
Er ist aber relativ ansehnlich sollte vll irgandwann anders mal genau so verstrahlt sein wie ich :P

Es fehlt lediglich noch die Ratation aber das ist ja mit die beispielen von euch kein Problem mehr =)

Code: Alles auswählen

import time
import tkinter as t
from PIL import Image, ImageTk

angle_1 = -0
angle_2 = -45
angle_3 = -0
c_width = 240
c_height = 160

master = t.Tk()
master.configure(width=480, height=320)

c_1 = t.Canvas(master, width=c_width*2, height=c_height*2)

img1_open = Image.open("../images/1.png")
img1_open = img1_open.resize((50,50), Image.ANTIALIAS)
img1 = ImageTk.PhotoImage(img1_open.rotate(angle_1))
img_obj_1 = c_1.create_image(c_width, c_height, image=img1)

img2_open = Image.open("../images/2.png")
img2_open = img2_open.resize((150,150), Image.ANTIALIAS)
img2 = ImageTk.PhotoImage(img2_open.rotate(angle_2))
img_obj_2 = c_1.create_image(c_width, c_height, image=img2)

img3_open = Image.open("../images/3.png")
img3_open = img3_open.resize((75,75), Image.ANTIALIAS)
img3 = ImageTk.PhotoImage(img3_open.rotate(angle_3))
img_obj_3 = c_1.create_image(c_width, c_height, image=img3)

c_1.place(relx=0.5, rely=0.5, anchor="center")

master.mainloop()

Danke nochmal für eure Hilfe
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum `c_1`? Die img_open sind Bilder und nicht in irgendeiner Form offen. tkinter wird als tk importiert nicht als t.
Bei c_width steht das c für (i)mage?
Da Du dreimal das selbe machst, sollte das in eine Funktion wandern.
Dragback
User
Beiträge: 7
Registriert: Montag 27. Januar 2020, 08:41

Sirius3 hat geschrieben: Montag 16. März 2020, 13:01 Warum `c_1`? Die img_open sind Bilder und nicht in irgendeiner Form offen. tkinter wird als tk importiert nicht als t.
Bei c_width steht das c für (i)mage?
Da Du dreimal das selbe machst, sollte das in eine Funktion wandern.
Du magst recht haben mit deinen Äuserungen, aber wie von mir gesagt ist der Code "Hässlich" und wird so nie in ein fertiges Programm kommen.
Aber um die Frage des Thread zu beantworten sollte er übersichtlich genug sein

mit freundlichen grüßen
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Dragback: Dass das so nicht in ein Programm kommt ist ein schwacher Trost, denn es steht so öffentlich in einem Forum wo es sich Leute als Vorbild nehmen könnten.

`time` wird importiert aber nirgends verwendet.

Überarbeitet und ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from pathlib import Path

from PIL import Image, ImageTk

IMAGE_WIDTH = 240
IMAGE_HEIGHT = 160


def main():
    root = tk.Tk()
    
    canvas = tk.Canvas(root, width=IMAGE_WIDTH * 2, height=IMAGE_HEIGHT * 2)
    canvas.pack()
    
    images = list()
    for i, (size, angle) in enumerate([(50, 0), (150, -45), (75, 0)], 1):
        image = ImageTk.PhotoImage(
            Image.open(Path.cwd().parent / "images" / f"{i}.png")
            .resize((size, size), Image.ANTIALIAS)
            .rotate(angle)
        )
        canvas.create_image(IMAGE_WIDTH, IMAGE_HEIGHT, image=image)
        images.append(image)

    root.mainloop()


if __name__ == "__main__":
    main()
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten