Hallo Zusammen,
ich bin in Python eher klassisch unterwegs. Meine GUI-Anwendungen schreibe ich mittels Tkinter.
Allerdings benötige ich auch sehr häufig Grafik um div. Dinge im mneinen Programmen zu viusualisieren.
Dazu eignet sich Pygame ja bekanntlich bestens.
Meine Google-Suche hat ergeben, dass es wohl nicht möglich ist ein Pygame-Fenster in eine Tkinter-Anwendung einzubetten.
Scheinbar bauen sich andere ihre Buttons, Checkboxen, ... selbst in Pygame zusammen.
Nun zur eigentlichen Frage:
Wie kann ich die Vorteile von Pygame und einen GUI-Framework (z.Bsp. Tkinter) kombinieren?
Oder gibt es in Pygame auch fertige Klassen für Buttons, etc?
GUI-Elemente in Pygame nutzen (Button, Textfelder, ...)
Pygame hat zumindest nichts eingebautes, und was es so an Drittlösungen gibt, ist oft nicht gepflegt.
Auch wenn es natürlich Unterschiede zu pygame gibt, kann der Canvas von tkinter vieles erledigen. Hast du den mal probiert?
Auch wenn es natürlich Unterschiede zu pygame gibt, kann der Canvas von tkinter vieles erledigen. Hast du den mal probiert?
- __blackjack__
- User
- Beiträge: 13533
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@aitsch: Arbeite an Deiner Google-Suche oder Google ist schlechter geworden, dann nimm eine andere Suchmaschine. Man kann das Pygame-Fenster in Tk einbetten. Stichwort ist die Umgebungsvariable `SDL_WINDOWID`. Das findet man auch in der PyGame-Dokumentation bei der pygame.display.init()-Funktion.
Kleines Beispiel:
Einerseits muss man sich um die Ereignisse in Pygame kümmern, damit die Queue nicht voll läuft, andererseits werden viele Ereignisse schon von Tk behandelt, wie Maus- und Tastaturereignisse.
Kleines Beispiel:
Code: Alles auswählen
#!/usr/bin/env python3
import os
import tkinter as tk
from random import randrange
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
def update_pygame(widget, screen):
for event in pygame.event.get():
print(event)
screen.set_at(
(randrange(0, screen.get_width()), randrange(0, screen.get_height())),
WHITE,
)
pygame.display.update()
widget.after(100, update_pygame, widget, screen)
def main():
size = width, height = 320, 200
root = tk.Tk()
frame = tk.Frame(root, width=width, height=height)
frame.pack()
root.update_idletasks()
os.environ["SDL_WINDOWID"] = str(frame.winfo_id())
screen = pygame.display.set_mode(size)
tk.Button(root, text="Löschen", command=lambda: screen.fill(BLACK)).pack()
update_pygame(frame, screen)
root.mainloop()
if __name__ == "__main__":
main()
Code: Alles auswählen
- (void)countSheep {
unsigned int sheep = 0;
while ( ! [self isAsleep]) { ++sheep; }
}
Da werde ich wohl nochmal in der Google-Schule nachsitzen müssen.
Man findet leider soviel Trash in den Suchergebnissen, dass mir wohl die korrekte Methode als solche nicht aufgefallen ist.
Aber: Danke für die Lösung !!!
Sie läuft aber ich würde sie auch gerne besser verstehen.
Daher noch ein paar Fragen:
1. Das mit der überlaufenden Queue der Pygame Events verunsichert mich etwas.
Bisher (ohne Einbettung in Tkinter) ist da noch nie etwas übergelaufen.
Ich würde wahrscheinlich nur Maus-Clicks abfragen bzw. behandeln wollen.
Sollte ich danach ein pygamne.event.clear() einfügen oder reicht die Abfrage über die for-Schleife?
2. Läuft die Pygame-Funktion durch:
widget.after(100, update_pygame, widget, screen)
in einem eigenen Thread oder Task?
3. Was genau bewirkt:
...
root.update_idletasks()
os.environ["SDL_WINDOWID"] = str(frame.winfo_id())
...
Man findet leider soviel Trash in den Suchergebnissen, dass mir wohl die korrekte Methode als solche nicht aufgefallen ist.
Aber: Danke für die Lösung !!!
Sie läuft aber ich würde sie auch gerne besser verstehen.
Daher noch ein paar Fragen:
1. Das mit der überlaufenden Queue der Pygame Events verunsichert mich etwas.
Bisher (ohne Einbettung in Tkinter) ist da noch nie etwas übergelaufen.
Ich würde wahrscheinlich nur Maus-Clicks abfragen bzw. behandeln wollen.
Sollte ich danach ein pygamne.event.clear() einfügen oder reicht die Abfrage über die for-Schleife?
2. Läuft die Pygame-Funktion durch:
widget.after(100, update_pygame, widget, screen)
in einem eigenen Thread oder Task?
3. Was genau bewirkt:
...
root.update_idletasks()
os.environ["SDL_WINDOWID"] = str(frame.winfo_id())
...
- __blackjack__
- User
- Beiträge: 13533
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@aitsch:
Ad 1.: `pygame.event.clear()` sollte reichen. Ich hatte die Ereignisse nur ausgegeben, damit man sieht, dass da beispielsweise die Mausbewegungen *nicht* ausgegeben werden wenn man mit der Maus über den PyGame-Bereich geht. Andererseits gibt es Ereignisse die dort behandelt werden können wie das Anzeigen des ”Fensters”. Und man sollte da auch andere Sachen verarbeiten können, die nicht von Tk verarbeitet werden wie Joysticks.
Mausklicks müsste man auf dem `Frame` in Tk behandeln. Beispiel um das setzen von roten Kreisen an der Mausposition erweitert:
Ad 2.: Nein die läuft im Hauptthread und wird von der `mainloop()` aufgerufen.
Ad 3.: Das sorgt für das Einbetten in die Tk-GUI. Wenn die Umgebungsvariable `SDL_WINDOWID` mit der ID eines ”Fensters” existiert, dann erstellt `pygame.init()`/`pygame.set_mode()` kein eigenes Fenster, sondern benutzt den Bereich der durch die ID beschrieben wird. Das `update_idletasks()` braucht man um sicherzustellen, dass der `Frame` tatsächlich auf Systemebene erstellt wurde und dort eine ID bekommen hat, die man abfragen kann.
Ad 1.: `pygame.event.clear()` sollte reichen. Ich hatte die Ereignisse nur ausgegeben, damit man sieht, dass da beispielsweise die Mausbewegungen *nicht* ausgegeben werden wenn man mit der Maus über den PyGame-Bereich geht. Andererseits gibt es Ereignisse die dort behandelt werden können wie das Anzeigen des ”Fensters”. Und man sollte da auch andere Sachen verarbeiten können, die nicht von Tk verarbeitet werden wie Joysticks.
Mausklicks müsste man auf dem `Frame` in Tk behandeln. Beispiel um das setzen von roten Kreisen an der Mausposition erweitert:
Code: Alles auswählen
#!/usr/bin/env python3
import os
import tkinter as tk
from random import randrange
import pygame
BLACK = (0, 0, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
def update_pygame(widget, screen):
for event in pygame.event.get():
print(event)
screen.set_at(
(randrange(0, screen.get_width()), randrange(0, screen.get_height())),
WHITE,
)
pygame.display.update()
widget.after(100, update_pygame, widget, screen)
def main():
size = width, height = 320, 200
root = tk.Tk()
frame = tk.Frame(root, width=width, height=height)
frame.pack()
root.update_idletasks()
os.environ["SDL_WINDOWID"] = str(frame.winfo_id())
screen = pygame.display.set_mode(size)
frame.bind(
"<Button>",
lambda event: pygame.draw.circle(screen, RED, (event.x, event.y), 5),
)
tk.Button(root, text="Löschen", command=lambda: screen.fill(BLACK)).pack()
update_pygame(frame, screen)
root.mainloop()
if __name__ == "__main__":
main()
Ad 3.: Das sorgt für das Einbetten in die Tk-GUI. Wenn die Umgebungsvariable `SDL_WINDOWID` mit der ID eines ”Fensters” existiert, dann erstellt `pygame.init()`/`pygame.set_mode()` kein eigenes Fenster, sondern benutzt den Bereich der durch die ID beschrieben wird. Das `update_idletasks()` braucht man um sicherzustellen, dass der `Frame` tatsächlich auf Systemebene erstellt wurde und dort eine ID bekommen hat, die man abfragen kann.
Code: Alles auswählen
- (void)countSheep {
unsigned int sheep = 0;
while ( ! [self isAsleep]) { ++sheep; }
}