Outils pour utilisateurs

Outils du site


stu:python_gui:pygame_tk

Comment utiliser simultanément Pygame et Tkinter

Pygame possède sa propre boucle de gestion des événements, ainsi que Tkinter. Pour avoir à la fois une fenêtre Pygame et Tkinter, voici trois solutions.

  1. ouvrir la fenêtre pygame. Puis, si besoin ouvrir la fenêtre tk qui bloque la fenêtre pygame jusqu'à sa fermeture.
  2. appeler le gestionnaire d'événements (update) de tk dans la boucle de pygame. On pourrai taussi faire l'inverse, mais je ne le présente pas ici
  3. lancer l'interface tk dans un thread à part. Le résultat est très simple, bien que la solution soit très technique.

La meilleur solution, si on veut que les deux fenêtres répondent est celle avec les threads (dans la seconde solution le flash su bouton ralentit l'animation de la fenêtr pygame).

Si en outre, on veut, dans pygame, déclencher l'apparition d'une fenêtre contenant du texte (mode d'emploi par exemple), alors, la première solution est sans doute la meilleure.

Solution 1

prog1.py
# Utiliser PyGame et Tk ensemble
# ===============================
# PROGRAMME 1
# -----------
# Dans cette version, la fenêtre Tk est ouverte lorsqu'on appuie sur la barre
# d'espace dans la fenêtre PyGame. L'exécution de la fenêtre Tk bloque l'exécution
# de la fenêtre PyGame, qui reprendra lorsqu'on refermera la fenêtre Tk
 
import pygame
import tkinter as tk
 
# Variable globale pour stocker la position de la bille animée
pos_vit=[100,100,0.3,-0.5]
# Variable contenant les coordonnées des points cliqués
liste_points=[]
 
# Animation dans la fenêtre PyGame
def animation(screen) :
    pos_vit[0]+=pos_vit[2]
    pos_vit[1]+=pos_vit[3]
    if pos_vit[0]<0 or pos_vit[0]>=screen.get_width() :
        pos_vit[2]*=-1
    if pos_vit[1]<0 or pos_vit[1]>=screen.get_height() :
        pos_vit[3]*=-1
    screen.fill([0,0,0])
    pygame.draw.rect(screen,[255,0,0],[pos_vit[0]-4,pos_vit[1]-4,8,8],0)
    for p in liste_points :
        pygame.draw.rect(screen,[255,255,0],[p[0]-10,p[1]-10,20,20],0)    
    pygame.display.flip()
 
# Fenetre TK (code de l'ouvrage de Mark Lutz) contenant un bouton qui flashe
class Alarm(tk.Frame):
    def __init__(self, msecs=1000):
        tk.Frame.__init__(self)
        self.msecs = msecs
        self.pack()
        stopper = tk.Button(self, text='Je suis un vrai bouton!')
        stopper.pack()
        stopper.config(bg='navy', fg='white', bd=8)
        self.stopper = stopper
        self.repeater()
 
    def repeater(self):
        self.bell()
        self.stopper.flash()
        self.after(self.msecs, self.repeater)
 
def main() :
    pygame.init()
    size=[256,256]
    screen=pygame.display.set_mode(size)
    while True :
        event = pygame.event.poll()  
        if event.type == pygame.QUIT: break 
        if event.type == pygame.MOUSEBUTTONDOWN:
            print(event.dict["button"])
            if event.dict["button"] == 1 : # clic gauche
                liste_points.append(event.dict["pos"])
            if event.dict["button"] == 3 : # clic droit
                Alarm().mainloop() # Bloque les évén. pygame
        animation(screen)
    pygame.quit()
 
main()

Solution 2

prog2.py
# Ne fonctionne pas correctement pour le moment

Solution 3

prog3.py
# Utiliser PyGame et Tk ensemble
# ===============================
# PROGRAMME 3
# -----------
# Dans cette version, les deux fenetre sont ouvertes dès le début et 
# sont exécutées dans des threads séparés. Elles ne se bloquent pas 
# l'une l'autre.
 
import pygame
import tkinter as tk
import threading
 
# Variable globale pour stocker la position de la bille animée
pos_vit=[100,100,0.3,-0.5]
# Variable contenant les coordonnées des points cliqués
liste_points=[]
 
 
# Animation dans la fenêtre PyGame
def animation(screen) :
    pos_vit[0]+=pos_vit[2]
    pos_vit[1]+=pos_vit[3]
    if pos_vit[0]<0 or pos_vit[0]>=screen.get_width() :
        pos_vit[2]*=-1
    if pos_vit[1]<0 or pos_vit[1]>=screen.get_height() :
        pos_vit[3]*=-1
    screen.fill([0,0,0])
    pygame.draw.rect(screen,[255,0,0],[pos_vit[0]-4,pos_vit[1]-4,8,8],0)
    for p in liste_points :
        pygame.draw.rect(screen,[255,255,0],[p[0]-10,p[1]-10,20,20],0)    
    pygame.display.flip()
 
# Fenetre TK (code de l'ouvrage de Mark Lutz) contenant un bouton qui flashe
class Alarm(tk.Frame):
    def __init__(self, msecs=1000):
        tk.Frame.__init__(self)
        self.msecs = msecs
        self.pack()
        stopper = tk.Button(self, text='Je suis un vrai bouton!')
        stopper.pack()
        stopper.config(bg='navy', fg='white', bd=8)
        self.stopper = stopper
        self.repeater()
    def repeater(self):
        self.bell()
        self.stopper.flash()
        self.after(self.msecs, self.repeater)
 
 
def main() :
    # Cette fonction constituera le Thread de Tk
    def tkthread() :
        alarm=Alarm()
        alarm.mainloop()
 
    pygame.init()
    size=[256,256]
    screen=pygame.display.set_mode(size)
    # Démarrage du thread tk
    threading.Thread(target=tkthread).start()
 
    while True :
        event = pygame.event.poll()  
        if event.type == pygame.QUIT: break 
        if event.type == pygame.MOUSEBUTTONDOWN:
            print(event.dict["button"])
            if event.dict["button"] == 1 :
                liste_points.append(event.dict["pos"])
        animation(screen)
    pygame.quit()
 
main()
stu/python_gui/pygame_tk.txt · Dernière modification: 2014/03/31 16:45 (modification externe)