Dorian.D
10 months ago
5 changed files with 371 additions and 0 deletions
@ -0,0 +1,266 @@
|
||||
|
||||
# IMPORTATIONS |
||||
|
||||
import tkinter as tk |
||||
from PIL import Image as Img |
||||
from PIL import ImageTk |
||||
|
||||
|
||||
# CONSTANTES |
||||
|
||||
TAILLE_IMG = 350 |
||||
FOND_IMAGE = "#222222" |
||||
|
||||
VISUEL = { |
||||
'nb caractères':80, |
||||
'nb lignes':9, |
||||
'fond':"#EE7722", |
||||
'écriture':"black", |
||||
'police': ("Courier", 16) |
||||
} |
||||
|
||||
# DECLARATION DES CLASSES PUBLIQUES |
||||
|
||||
class IHM(): |
||||
'''IHM basique permettant de gérer le projet Manoir Hanté |
||||
|
||||
Idée générale |
||||
------------- |
||||
Interface graphique interactive permettant d'afficher : |
||||
-> Trois zones de texte : description, actions possibles et caractéristiques ? |
||||
-> Deux images : une pour le lieu et une pour un monstre ou autre ? |
||||
|
||||
Classe IHM |
||||
---------- |
||||
La Classe générant l'interface graphique (GUI en anglais) |
||||
L'interaction avec le programme gérant les données se fait |
||||
via la méthode signaler_evenement() |
||||
|
||||
Méthodes disponibles |
||||
-------------------- |
||||
signaler_evenement(self, f) |
||||
afficher_txt_1(self, texte:str) |
||||
afficher_txt_2(self, texte:str) |
||||
afficher_txt_3(self, texte:str) |
||||
afficher_img_1(self, fichier_image:str) |
||||
afficher_img_2(self, fichier_image:str) |
||||
''' |
||||
|
||||
def __init__(self): |
||||
self.interne = IHM_interne() |
||||
|
||||
def signaler_evenement(self, f): |
||||
self.interne.signaler_evenement(f) |
||||
|
||||
def afficher_txt_1(self, texte:str): |
||||
self.interne.afficher_txt_1(texte) |
||||
|
||||
def afficher_txt_2(self, texte:str): |
||||
self.interne.afficher_txt_2(texte) |
||||
|
||||
def afficher_txt_3(self, texte:str): |
||||
self.interne.afficher_txt_3(texte) |
||||
|
||||
def afficher_img_1(self, fichier_image:str): |
||||
self.interne.afficher_img_1(fichier_image) |
||||
|
||||
def afficher_img_2(self, fichier_image:str): |
||||
self.interne.afficher_img_2(fichier_image) |
||||
|
||||
|
||||
# DECLARATION DES CLASSES PRIVEES (mais que je n'ai pas caché plus que cela) |
||||
# Vous pouvez d'ailleurs interagir direction avec elle en notant directement |
||||
# ihm =IHM_interne() plutôt que ihm = IHM() si vous voulez. |
||||
|
||||
class IHM_interne(tk.Tk): |
||||
|
||||
def __init__(self): |
||||
|
||||
# Création de l'application en elle-même |
||||
tk.Tk.__init__(self) |
||||
xmax, ymax = self.obtenir_taille_ecran() |
||||
self.geometry(f"{xmax}x{ymax}") |
||||
self.title("MON SUPER JEU") |
||||
self.configure(bg=FOND_IMAGE) |
||||
|
||||
|
||||
self.frame_g = self.creer_frame_g(FOND_IMAGE) |
||||
self.frame_d = self.creer_frame_d(FOND_IMAGE) |
||||
|
||||
# Création des widgets-labels |
||||
self.IMAGE_VIDE = ImageTk.PhotoImage(Img.new("RGB", (TAILLE_IMG, TAILLE_IMG), (50, 50, 50))) |
||||
self.image_1 = self.IMAGE_VIDE |
||||
self.image_2 = self.IMAGE_VIDE |
||||
self.label_img_1 = self.creer_label_img_1(self.frame_g, None) |
||||
self.label_img_2 = self.creer_label_img_2(self.frame_g, None) |
||||
self.label_txt_1 = self.creer_label_txt_1(self.frame_d, "-", VISUEL) |
||||
self.label_txt_3 = self.creer_label_txt_3(self.frame_d, "valeurs", VISUEL) |
||||
self.label_txt_2 = self.creer_label_txt_2(self.frame_d, "-", VISUEL) |
||||
|
||||
# Configuration intiale des widgets (à commenter si vous ne voulez pas d'images au départ |
||||
config_depart = ("Ici, on décrit la scène\nSur plusieurs lignes si nécessaire.", "Ici, on donne les choix possibles", None, None, "Caractéristiques aventurier et monstre") |
||||
self.configuration_scene(config_depart) |
||||
|
||||
# Gestion des événements |
||||
self.fonction = None |
||||
self.bind('<Any-KeyPress>', self.gestion_actions) |
||||
|
||||
# DECLARATION DES METHODES INTERNES : ne pas utiliser depuis l'extérieur du module |
||||
|
||||
def obtenir_taille_ecran(self) -> tuple: |
||||
xmax = self.winfo_screenwidth() |
||||
ymax = self.winfo_screenheight() |
||||
return xmax, ymax |
||||
|
||||
def creer_frame_g(self, fond): |
||||
zone = tk.Frame(self, bg=fond) |
||||
zone.pack(side=tk.LEFT, fill=tk.Y, padx=0, pady=0) |
||||
return zone |
||||
|
||||
def creer_frame_d(self, fond): |
||||
zone = tk.Frame(self, bg=fond) |
||||
zone.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH, padx=0, pady=0) |
||||
return zone |
||||
|
||||
def creer_label_txt_1(self:tk.Tk, conteneur, texte:str, visuel:dict) -> tk.Label: |
||||
auDessus = tk.Label(conteneur, text="DESCRIPTION", fg="#CCCCCC", bg="black", height=3) |
||||
auDessus.configure(font=visuel['police']) |
||||
auDessus.pack(side=tk.TOP, fill=tk.X, padx=10, pady=10) |
||||
|
||||
monLabel = tk.Label(conteneur, text=texte) |
||||
monLabel.configure(fg=visuel['écriture']) |
||||
monLabel.configure(bg=visuel['fond']) |
||||
monLabel.configure(font=visuel['police']) |
||||
monLabel.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=10, pady=10) |
||||
|
||||
return monLabel |
||||
|
||||
def creer_label_txt_2(self:tk.Tk, conteneur, texte:str, visuel:dict) -> tk.Label: |
||||
|
||||
monLabel = tk.Label(conteneur, text=texte) |
||||
monLabel.configure(fg=visuel['écriture']) |
||||
monLabel.configure(bg=visuel['fond']) |
||||
monLabel.configure(width=visuel['nb caractères']) |
||||
monLabel.configure(height=visuel['nb lignes']) |
||||
monLabel.configure(font=visuel['police']) |
||||
monLabel.pack(side=tk.BOTTOM,fill=tk.BOTH, expand=True, padx=10, pady=10) |
||||
|
||||
auDessus = tk.Label(conteneur, text="ACTIONS POSSIBLES", fg="#CCCCCC", bg="black", height=3) |
||||
auDessus.configure(font=visuel['police']) |
||||
auDessus.pack(side=tk.BOTTOM,fill=tk.X, padx=10, pady=10) |
||||
|
||||
return monLabel |
||||
|
||||
def creer_label_txt_3(self:tk.Tk, conteneur, texte:str, visuel:dict) -> tk.Label: |
||||
monLabel = tk.Label(conteneur, text=texte) |
||||
monLabel.configure(fg=visuel['écriture']) |
||||
monLabel.configure(bg=visuel['fond']) |
||||
monLabel.configure(width=visuel['nb caractères']) |
||||
monLabel.configure(height=2) |
||||
monLabel.configure(font=visuel['police']) |
||||
monLabel.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10) |
||||
|
||||
auDessus = tk.Label(conteneur, text="Caractéristiques", fg="#CCCCCC", bg="black", height=3) |
||||
auDessus.configure(font=visuel['police']) |
||||
auDessus.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10) |
||||
|
||||
return monLabel |
||||
|
||||
def creer_label_img_1(self:tk.Tk, conteneur, fichier_image:str) -> tk.Label: |
||||
|
||||
if fichier_image: |
||||
objet_image_PIL = Img.open(fichier_image) |
||||
objet_image_PIL = objet_image_PIL.resize( (TAILLE_IMG, TAILLE_IMG) ) |
||||
objet_image_tk = ImageTk.PhotoImage(objet_image_PIL) |
||||
self.image_1 = objet_image_tk |
||||
else: |
||||
self.image_1 = self.IMAGE_VIDE |
||||
|
||||
zone_image = tk.Label(conteneur, image=self.image_1) |
||||
zone_image.configure(bg=FOND_IMAGE) |
||||
zone_image.pack(side=tk.TOP, ipadx=10, ipady=10) |
||||
|
||||
return zone_image |
||||
|
||||
def creer_label_img_2(self:tk.Tk, conteneur, fichier_image:str) -> tk.Label: |
||||
|
||||
if fichier_image: |
||||
objet_image_PIL = Img.open(fichier_image) |
||||
objet_image_PIL = objet_image_PIL.resize( (TAILLE_IMG, TAILLE_IMG) ) |
||||
objet_image_tk = ImageTk.PhotoImage(objet_image_PIL) |
||||
self.image_2 = objet_image_tk |
||||
else: |
||||
self.image_2 = self.IMAGE_VIDE |
||||
|
||||
zone_image = tk.Label(conteneur, image=self.image_2) |
||||
zone_image.configure(bg=FOND_IMAGE) |
||||
zone_image.pack(side=tk.BOTTOM, ipadx=10, ipady=10) |
||||
|
||||
return zone_image |
||||
|
||||
def gestion_actions(self, event): |
||||
if self.fonction: |
||||
self.fonction(event) |
||||
|
||||
# DECLARATION DES METHODES D'INTERFACE |
||||
|
||||
def signaler_evenement(self, f): |
||||
'''Lance un appel à la fonction f transmise lors de l'appui sur une touche''' |
||||
self.fonction = f |
||||
|
||||
def configuration_scene(self, configuration_voulue:list): |
||||
'''Modifie l'affichage sur le GUI''' |
||||
self.afficher_txt_1(configuration_voulue[0]) |
||||
self.afficher_txt_2(configuration_voulue[1]) |
||||
self.afficher_img_1(configuration_voulue[2]) |
||||
self.afficher_img_2(configuration_voulue[3]) |
||||
self.afficher_txt_3(configuration_voulue[4]) |
||||
|
||||
def afficher_txt_1(self, texte:str): |
||||
'''Modifie le texte visible dans la zone de texte en haut à gauche''' |
||||
#largeur_max_ligne = max(map(len, texte.split('\n'))) |
||||
#zone_texte.configure(width=largeur_max_ligne) |
||||
self.label_txt_1.configure(text=texte) |
||||
|
||||
def afficher_txt_2(self, texte:str): |
||||
'''Modifie le texte visible dans la zone de texte en haut à gauche''' |
||||
#largeur_max_ligne = max(map(len, texte.split('\n'))) |
||||
#zone_texte.configure(width=largeur_max_ligne) |
||||
self.label_txt_2.configure(text=texte) |
||||
|
||||
def afficher_txt_3(self, texte:str): |
||||
'''Modifie le texte visible dans la zone de texte en haut à gauche''' |
||||
#largeur_max_ligne = max(map(len, texte.split('\n'))) |
||||
#zone_texte.configure(width=largeur_max_ligne) |
||||
self.label_txt_3.configure(text=texte) |
||||
|
||||
def afficher_img_1(self, fichier_image:str): |
||||
'''Modifie le texte visible dans la zone de texte en haut à gauche''' |
||||
if fichier_image: |
||||
objet_image_PIL = Img.open(fichier_image) |
||||
objet_image_PIL = objet_image_PIL.resize( (TAILLE_IMG, TAILLE_IMG) ) |
||||
objet_image_tk = ImageTk.PhotoImage(objet_image_PIL) |
||||
self.image_1 = objet_image_tk |
||||
else: |
||||
self.image_1 = self.IMAGE_VIDE |
||||
|
||||
self.label_img_1.configure(image=self.image_1) |
||||
|
||||
def afficher_img_2(self, fichier_image:str): |
||||
'''Modifie le texte visible dans la zone de texte en haut à gauche''' |
||||
if fichier_image: |
||||
objet_image_PIL = Img.open(fichier_image) |
||||
objet_image_PIL = objet_image_PIL.resize( (TAILLE_IMG, TAILLE_IMG) ) |
||||
objet_image_tk = ImageTk.PhotoImage(objet_image_PIL) |
||||
self.image_2 = objet_image_tk |
||||
else: |
||||
self.image_2 = self.IMAGE_VIDE |
||||
|
||||
self.label_img_2.configure(image=self.image_2) |
||||
|
||||
|
||||
|
||||
# PROGRAMME PRINCIPAL |
||||
|
||||
if __name__ == '__main__': |
||||
application = IHM() |
@ -0,0 +1,105 @@
|
||||
# Importations |
||||
|
||||
import interface # Dépendances : PIL(Pillow) et tkinter |
||||
import donnees |
||||
import sys |
||||
import pickle |
||||
|
||||
# Déclaration des fonctions pour la sauvegarde |
||||
|
||||
def sauvegarder_jeu(manoir, fichier): |
||||
with open(fichier, 'wb') as f: |
||||
pickle.dump(manoir, f) |
||||
|
||||
def charger_jeu(fichier): |
||||
with open(fichier, 'rb') as f: |
||||
return pickle.load(f) |
||||
|
||||
# Déclaration des fonctions pour le fichier texte |
||||
|
||||
def rediriger_sortie_vers_fichier(fichier_sortie: str): |
||||
"""Redirige la sortie de la console vers un fichier texte.""" |
||||
sys.stdout = open(fichier_sortie, "a") |
||||
sys.stderr = sys.stdout |
||||
|
||||
def restaurer_sortie_console(): |
||||
"""Restaure la sortie de la console après la redirection vers un fichier.""" |
||||
sys.stdout.close() |
||||
sys.stdout = sys.__stdout__ |
||||
sys.stderr = sys.__stderr__ |
||||
|
||||
# Déclaration des fonctions |
||||
|
||||
def ihm_signale_evenement(evenement:'tkinter.Event', manoir:'Manoir', ihm:'IHM') -> None: |
||||
"""Fonction où on récupère des informations sur l'événément reçu via l'IHM""" |
||||
|
||||
# On récupère la touche sur laquelle on vient d'appuyer |
||||
touche = evenement.char |
||||
print(f"\nEVENEMENT RECU : {evenement}") # Permet de voir le vrai événement |
||||
print(f"CODE PERSO : {touche}") # L'IHM permet de connaitre la touche utilisée |
||||
|
||||
# Il faut maintenant gérer l'événement : modifier les données et redemander une affichage à l'IHM |
||||
|
||||
h = manoir.heros |
||||
|
||||
if touche == 'X' or touche == 'x': |
||||
sauvegarder_jeu(manoir, "sauvegarde_jeu.pkl") |
||||
print("Jeu sauvegardé.") |
||||
|
||||
elif touche == 'V' or touche == 'v': |
||||
try: |
||||
manoir = charger_jeu("sauvegarde_jeu.pkl") |
||||
modifier_affichage(manoir, ihm) |
||||
print("Jeu chargé.") |
||||
except FileNotFoundError: |
||||
print("Aucune sauvegarde trouvée.") |
||||
|
||||
h = manoir.heros |
||||
|
||||
if touche == 'N' or touche == 'n': |
||||
if h.aller_nord(): # Si aller au nord est possible et c'est bien passé |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'S' or touche == 's': |
||||
if h.aller_sud(): # Si aller au sud est possible et c'est bien passé |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'Q' or touche == 'q': |
||||
if h.aller_ouest(): # Si aller a l'ouest est possible et c'est bien passé |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'D' or touche == 'd': |
||||
if h.aller_est(): # Si aller a l'est est possible et c'est bien passé |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'C' or touche == 'c': |
||||
if h.combattre_monstre_actuel(): # Si combattre est possible et c'est bien passé |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'F' or touche == 'f': |
||||
if h.fuire(): # Si fuire est possible |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'U' or touche == 'u': |
||||
if h.ouvrir(manoir): # Si l'utilisation de la cle fonctionne |
||||
modifier_affichage(manoir, ihm) |
||||
if touche == 'R' or touche == 'r': |
||||
modifier_affichage(manoir, ihm) |
||||
|
||||
def modifier_affichage(manoir:'Manoir', ihm:'IHM') -> None: |
||||
"""Modifie les 5 champs de l'interface graphique""" |
||||
h = manoir.heros |
||||
ihm.afficher_txt_1( h.observer() ) # affiche le texte descriptif |
||||
ihm.afficher_txt_2( h.reflechir() ) # affiche les actions possibles |
||||
ihm.afficher_txt_3( h.get_carac() ) # affiche les caractéristiques du héros |
||||
ihm.afficher_img_1( h.lieu.img ) # affiche l'image éventuelle du lieu |
||||
if h.lieu.occupant: |
||||
ihm.afficher_img_2( h.lieu.occupant.img) # affiche l'image éventuelle du monstre |
||||
|
||||
|
||||
# PROGRAMME PRINCIPAL |
||||
|
||||
#rediriger_sortie_vers_fichier("sortie_console.txt") |
||||
|
||||
# Création des données et de l'interface graphique |
||||
m = donnees.peupler_manoir() # Création des données du manoir |
||||
ihm = interface.IHM() # Création de l'interface graphique |
||||
|
||||
# ihm_signale_evenement va récupérer les événements sur l'ihm |
||||
ihm.signaler_evenement(lambda event: ihm_signale_evenement(event, m, ihm)) |
||||
|
||||
modifier_affichage(m, ihm) |
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 80 KiB |
Loading…
Reference in new issue