Je vais essayer de vous expliquer mon problème le plus clairement possible ! Le lien vous permettra de vous procurer tout les fichiers du projet: https://mega.nz/#F!1oBRza5L!fdVX47ZMiRDp5adocTiaJQ
Mon problème est le suivant:
Si l'on veut utiliser mon jeu normalement, il faut premièrement ouvrir WorldOfRandom.py et l’exécuter, cliquer sur "Jouer!" puis sur "valider". Le problème arrive ici. A cette étape, je voudrais destroy la fenêtre précédente et ouvrir le programme "damier_compl3.py" grâce a une ligne de code dans le programme WorldOfRandom, mais impossible d'y arriver avec une simple ligne comme " import damier_compl3.py", il ouvre la fenêtre avec la bonne geometry, mais il n'y a rien à l'intérieur. De plus, je ne comprends pas l'erreur qu'il m'affiche dans le fenêtre d'exécution et les deux professeurs qui nous encadrent ne trouvent pas de solution à notre problème, je me réfère donc à votre communauté !
J'ajoute que je suis assez novice dans ce milieu et que j'essaye de me débrouiller comme je le peux. En espérant trouver une solution grâce vous.
Malheureusement, j'avais déjà essayé cette technique (en beaucoup plus simplifié il faut le dire :D) qui ne fonctionne pas car avec la ligne "import damier_compl3" au tout début du fichier WorldOfRandom, il ouvre en premier le damier (sans aucune raison valable) et n'ouvrira pas la page main(c'est a dire la "page d’accueil du jeu"), sauf si l'on ferme volontairement le damier....
Après je me trompe peut-être mais avec l'exemple que vous m'avez donné, cela refait le même schéma
Par contre j'ai une petite question: je ne comprends pas pourquoi vous avez écrit dans le premier exemple "fenetre = tk.Tk()". Le terme tk ne renvoie à rien en particulier et une erreur apparait dans ma fenêtre ?
Si vous avez d'autres idées à me faire partager, n’hésitait pas !
Avant de commencer, le fenetre = tk.Tk(), est simplement l'importation du module.
Si vous obtenez une erreur, c'est parce que vous avez pas copier/coller le code, tel que je l'ai écris
Puisque voici pourquoi:
Exemple 1:
from tkinter import *
fenetre = Tk()
Lorsque vous faites ceci, vous importez tous les éléments du modules tkinter. Il suffit donc, de créer votre fenêtre par Tk()
C'est simplement plus facile. Sauf que, ce n'est pas la meilleur solution. Puisque, plusieurs modules pourraient contenir les mêmes noms, ce qui entraînerait un conflit, entre les modules importés.
Exemple 2:
import tkinter as tk
fenetre = tk.Tk()
Lorsque vous faites cela, vous importez tout le module tkinter, par la variable tk. Ce qui enlève les conflits.
C'est comme si vous faisiez un import normal.. sauf que vous avez créé un raccourci dans le nom...
Exemple:
import tkinter
import math
tkinter.Tk()
math.ceil()
Donc, il suffit d'ajouter tk.Tk(), pour instancier Tk().
De plus, cela permet de connaître quel est le module que vous instancier, lorsque vous en avez plusieurs et que les modules ont des noms long.
Exemple:
import tkinter as tk
tk.Tk()
tk.Label(...)
tk.Button(...)
import math as mt
mt.ceil()
mt.floor()
Tandis que, si vous faites cela:
from tkinter import *
from math import *
Tk()
ceil()
floor()
C'est pas facile, de savoir quel module, ceil() fait-il parti... (il fait parti du module math) ....
Pour votre problème, votre damier s'ouvre avant, puisque vous avez pas créé de fonction, comme le main(), dans mon exemple..
Si vous avez copier/coller mon exemple, il ne doit pas y avoir de problème.
Vous devez créer une fonction dans le fichier appelé par WorldOfRandom, ce qui empêche l'appel, pendant l'importation du module.
Donc, tout ce qui se trouve dans les fichiers secondaires, devrait être dans une fonction.
Si cela ne vous aide pas, je m'exprime peut-être mal. Si vous avez un petit exemple, ne ce qui ne fonctionne pas, essayez de le copier/coller ici.
Je vous assure que vous vous exprimez très bien, c'est juste moi qui doit mal faire les choses car je me perds un peu dans mon programme comme nous travaillons à trois dessus :/.
Merci pour la petite explication, c'est tout de suite plus claire !
Bref, j'avais recopié le programme à la main mais je viens de faire un pauvre copier collé et ça ne marche toujours pas, mais cela doit être de ma faute (c'est même plus que probable ^^')
Dans mon programme main, c'est à dire WorldOfRandom, ça se présente comme cela (TEST_DC3 est une copie de mon programme de base, je fais quelques bêtises et je n'ai pas envie de faire une mauvais manipulation et TEST_WOR est aussi une copie) :
from tkinter import *
import TEST_DC3
root=Tk()
#je passe quelques def inutiles
#le petite correction que vous m'avez donné:
def jouer():
toplevel.destroy()
TEST_DC3.main(fenetre)
fenetre = tk.Tk()
toplevel = tk.Toplevel(fenetre)
boutonJouer = tk.Button(toplevel, text='Jouer', command=jouer)
boutonJouer.pack()
#Le bouton ci-dessus se trouve normalement dans la def suivant, je dois donc la décaler vers l'autre def ?
fenetre.withdraw()
fenetre.mainloop()
#Je suppose qu'il y a des choses a changer et c'est là ou je suis perdu puisque nous avons assigné au début "root=Tk()", il y a des choses qui ne marcherons pas ?
La def suivante est l'endroit où doit se trouver le bouton jouer, permettant de réduire/destroy WorldOfRandom et ouvrir le damier. Je vous donne seulement les lignes qui nous intéresses:
BU=tk.Button(fenetre, text="Valider", command=jouer)
BU.pack()
BU.place(x=50,y=60)
#Faut-il donc que je remplace ces lignes par vos lignes ?:
toplevel = tk.Toplevel(fenetre)
boutonJouer = tk.Button(toplevel, text='Jouer', command=jouer)
boutonJouer.pack()
fenetre.withdraw()
#Ne risque-t-il pas d'avoir quelques problème ? J'ai déjà essayé de mettres ces lignes dans cette def et cela ne fonctionne pas, mais je suppose que le problème vient encore de ma part :/
Dans le fichier du damier il ne devrait pas avoir de problème je pense mais je vous insère ci-dessous mon début de programme:
from tkinter import *
def jouer():
global T,CarreVide,CarreB,CarreR,a,b,i,j,posx,posy
for i in range (8):
for j in range(8):
a=i*100+50
b=j*105
if T[i][j]=="0" or T[i][j]=="P":
Button(fen3,image=CarreVide,command=lambda x=i,y=j:action1(x,y)).place(x=a,y=b)
if T[i][j]=="base1":
Button(fen3,image=Base1,command=lambda x=i,y=j:action0(x,y)).place(x=a,y=b)
if T[i][j]=="base2":
Button(fen3,image=Base2,command=lambda x=i,y=j:action1(x,y)).place(x=a,y=b)
if T[i][j]=="rienB.png":
Button(fen3,image=CarreB,command=lambda x=i,y=j:action1(x,y)).place(x=a,y=b)
if T[i][j]=="rienR.png":
Button(fen3,image=CarreR,command=lambda x=i,y=j:action0(x,y)).place(x=a,y=b)
def main(fenetre):
toplevel = tk.Toplevel(fenetre)
label = tk.Label(toplevel, text='Voici le Damier..')
label.pack()
L'erreur qui persiste malgré tout est "fenetre=tk.Tk()"is not defined...
Quand on à une erreur de programmation, qu'est-ce-que c'est long de trouver le problème !!
Je vous remercie une fois de plus pour votre aide et votre temps consacré à m'expliquer mes petites erreurs de débutant
Dans ton premier extrait de code, c'est soit la ligne 4, soit la 14, pas les deux en même temps.
Ce qu'il explique dans son post, c'est que tk.Tk(), et Tk(), ça fait la même chose, tu choisis soit l'un soit l'autre selon ta manière d'importer le module.
Si vous nommez la variable root, alors ce sera root.destroy()..
Si vous nommez la variable fenetre, alors ce sera fenetre.destroy()...
----
Le withdraw() permet de réduire la fenêtre principale en arrière-plan, sans la détruire. Ce qui permet d'ouvrir une fenêtre secondaire en avant-plan avec Toplevel()
Pour la remettre en avant-plan, on utilise .deiconify()
---
Avant d'essayer de copier/coller mon code, avec votre code. Vous devriez essayer de comprendre l'exemple que je vous ai donné. Ce serait moins mélangeant pour vous.
Il y a plusieurs méthodes. Il faut simplement savoir que tkinter est une boucle infini. Lorsque vous faites ceci:
root = Tk() ## Fenetre principale (Tout le programme)
root.mainloop() ## Boucle infini
Le Toplevel est une fenêtre secondaire, elle a donc pas besoin de boucle infini, puisque root fonctionne encore.
Par contre non, ça revient pas à refaire ton programme depuis le début, c'est juste qu'il faut ajouter le préfixe à toutes les fonctions du module tkinter. C'est chiant mais ça n'impose pas de tout effacer pour tout refaire.
A noter quand même que les bonnes pratiques poussent à préférer import tkinter as tk plutôt que from tkinter import * pour éviter les conflits de nommage.
La forme de l'import change pas grand chose, c'est juste qu'on peut doner un alias au nom du module avant d'appeler une de ses fonctions (ou de ne pas l'écrire si on utilise *).
Oui, en enlevant tout les tk. sur les modules ça fonctionne mais j'ai encore un problème:
Le bouton que je créer pour ensuite afficher le damier et "withdraw" le menu est déjà créée, mais dans la mauvaise def.
En faite, dans ma def ça fait:
def jouer():
toplevel.destroy()
TEST_DC3.main(root)
toplevel=Toplevel(root)
#je créer le bouton en dessous
BU=Button(toplevel, text="Valider", command=jouer)
BU.pack()
root.withdraw()
Donc je recréer donc un bouton alors que qu'il est déjà crée dans une autre def:
def joueurs():
fen2=Toplevel(root)
fen2.geometry('200x100')
fen2.resizable(width=False, height=False)
fen2.title('Choix des Joueurs')
fen2['bg']='pale turquoise'
tex1=Label(fen2,text='Joueur 1 : ')
tex1.grid(row=1,column=1)
tex2=Entry(fen2)
tex2.grid(row=1,column=2)
tex3=Label(fen2,text='Joueur 2 : ')
tex3.grid(row=2,column=1)
tex4=Entry(fen2)
tex4.grid(row=2,column=2)
#Il est crée ici, dans un autre toplevel:
BU=Button(fenetre, text="Valider", command=jouer)
BU.pack()
BU.place(x=50,y=60)
BU2=Button(fen2, text="Règles", command=faireApparaitreLesRègles)
BU2.place(x=100,y=60)
fen2.mainloop()
Donc je ne sais pas comment m'y prendre pour mettre le bouton qui fonctionne (de la def jouer) dans la seconde fonctionne (def joueur) qui utilise un toplevel...
Ça sera la dernière erreur avant que ça fonctionne..
Je sais pas si c'est moi qui explique mal, mais je vois que vous avez pas compris grand chose
Pourquoi les fenêtres secondaires ( Toplevel() ) ont des .mainloop() ? (Ligne #25, du dernier code)
Il ne faut pas de .mainloop() dans une fenêtre secondaire... Seulement la fenêtre principale ( Tk() )
Pourquoi avez-vous des positionnement .pack et .place pour le même widget? (Ligne #20-21, du dernier code)
---
Pour ne pas vous mélanger, je vais recommencer du début.
J'utilisais des Toplevel, parce que normalement, on ne détruit pas la fenêtre principale, lorsque l'on change de fichier. On continue toujours avec la même fenêtre... On passe la fenêtre en argument dans une fonction de l'autre fichier. D’où la fonction .main(fenetre) dans le fichier damier_complet3
Sauf que je ne savais pas comment vos fichiers étaient composés..
Ce que j'essaye de comprendre, pour mieux vous aider est:
Comment sont fait vos fichiers..
Quels sont les fonctions dans vos fichiers.
Qu'es-ce qui devrait être afficher dans une fenêtre secondaire et ceux dans la fenêtre principale..
Si on oublie le Toplevel. On va faire comme vous vouliez au début, même si ce n'est pas la bonne manière de commencer à apprendre tkinter.
De plus, le mieux serait d'utiliser des classes. Plutôt que des fonctions, puisque vous aller devoir faire sortir vos variables de ces fonctions, avec global. Ce qui devient une mauvaise habitude. Mais bon, c'est une autre histoire.
Admettons que chaque fichier à besoin d'une fenêtre principale.... Tk(. Il faut donc, détruire les anciennes.
Voici comment vos fichiers pourraient être fait:
Exemple:
Voici le fichier TEST_WOR.py
from tkinter import *
import TEST_DC3
root = Tk() ## Première fenêtre principale
def valider():
root.destroy()
TEST_DC3.main() ## On appel la fonction main() du module TEST_DC3
boutonValider = Button(root, text='Valider', command=valider)
boutonValider.pack()
root.mainloop() ## Première boucle infini principale
Voici le fichier TEST_DC3.py
from tkinter import *
## La variable root2 sera la fenêtre principale.
## Elle n'est pas encore déclaré, puisqu'elle sera créé dans la fonction main()
root2 = None
def joueurs():
## root2.withdraw() ## On réduit la fenêtre principale. (À dé-commenter, pour voir la différence)
fen2=Toplevel(root2)
fen2.geometry('200x100')
fen2.resizable(width=False, height=False)
fen2.title('Choix des Joueurs')
fen2['bg']='pale turquoise'
tex1=Label(fen2,text='Joueur 1 : ')
tex1.grid(row=1,column=1)
tex2=Entry(fen2)
tex2.grid(row=1,column=2)
tex3=Label(fen2,text='Joueur 2 : ')
tex3.grid(row=2,column=1)
tex4=Entry(fen2)
tex4.grid(row=2,column=2)
def main():
## Pour que les autres fonctions utilisent cette fenêtre (root2).
## On déclare root2 comme étant global.
global root2
root2 = Tk() ## Deuxième fenêtre principale (La première doit être détruit)
label = Label(root2, text='Voici le Damier..')
label.pack()
boutonJoueurs = Button(root2, text='Joueurs', command=joueurs)
boutonJoueurs.pack()
root2.mainloop() ## Deuxième boucle infini principale
Normalement, le mieux sera d'utiliser des Toplevel, mais bon.. Comme vous le voyez, dans la fonction joueurs(), j'ai commenté la réduction de la fenêtre principale, avec root2.withdraw().
À partir de ce bout de code, vous devriez être en mesure de faire quelque chose de potable.
Si cela ne vous convient pas, ils faudrait savoir, quels sont les fonctions qui ne fonctionne pas.
Au pire, rien ne vous empêches de faire sortir la fenêtre secondaire (fen2), de la fonction, pour l'utiliser ailleurs. Grâce à global.
Je m'exprime juste très mal est j'avoue que ça devient problématique pour vous car vous ne comprenez pas ce que je veux dire et pour moi puisque le problème n'est toujours pas résolu.
Dans mon message précédent, les deux morceaux de codes que j'ai mis sont dans le même programme... BREF repartons de 0, je vais essayer de me débrouiller mieux que les messages précédents.
Le fichier World Of Random (WOR) est le menu, quand on lance le jeu.
Comme c'est la première fenêtre à s'ouvrir, elle est donc considéré comme la fenêtre principale.
Nous avons donc assigné "root=Tk()"
Quand l'on exécute le programme, il nous affiche ça:
Ensuite, si l'on clique sur jouer, il lancera la def nommé joueurs qui est un Toplevel (c'est important et c'est là que ça se complique !)
Voici ce que ça affiche (fenêtre bleu):
Ce que je voudrais, c'est quand l'on clique sur "Valider", ça destroy / withdraw ces deux fenêtres et lancer le damier, qui est une autre page de code (je crois que avez compris ça).
Voici le code qui permet de créer la seconde fenêtre bleu avec le bouton "valider":
Il faut donc qu'il y ait une def "jouer" disant qu'il faut destroy / withdraw les deux fenêtres et lancer le damier, mais il ne faut pas dire de recréer un bouton "valider", puisque qu'il est déjà créer dans la def ci-dessous... (100% c'est encore mal expliqué )
Ce qui ne fonctionnait pas dans les exemples précédents que vous m'avez donné, c'est que vous créez un bouton valider dans une autre def, alors que je veux que le bouton "valider" sois dans cette def.
Il n'y a pas vraiment de problème dans le fichier du damier, le problème persiste dans ce fichier, celui du menu.
J'espère avoir été le plus claire possible...
Je vous remercie encore pour votre patience sans faille
Vous créez des widgets dans des fonctions. Ce qui devient difficile de communiquer entre-elles. Il faut donc, sortir les variables des fonctions. (Si l'on peut, sinon on utiliser global)
Vous demander le nom des joueurs (grâce aux entries), qui est dans le premier fichier (WOR). Mais vous aller avoir besoin de ces noms dans le deuxième fichier. Il faudra donc, que le deuxième fichier demande des arguments (dans la fonction main())
Voici un exemple.
Fichier WOR:
from tkinter import *
import TEST_DC3
def regles():
top_regles = Toplevel()
blabla = Label(top_regles, text='Voici les règles...')
blabla.pack()
boutonFermer = Button(top_regles, text='FERMER', command=top_regles.destroy)
boutonFermer.pack()
def valider():
toplevel.destroy() ##détruit la fenêtre secondaire
print('VOICI LES NOMS:', nom_j1.get(), nom_j2.get())
root.destroy()## Détruit la fenêtre principale (root)
## Exécute la fonction main() du deuxième fichier.
## On inclus les noms des joueurs...
TEST_DC3.main(nom_j1.get(), nom_j2.get())
def jouer():
global toplevel
toplevel = Toplevel()
## Joueur1:
lbl_j1 = Label(toplevel, text='Joueur1:')
lbl_j1.grid(row=0, column=0)
entry_j1 = Entry(toplevel, textvariable=nom_j1)
entry_j1.grid(row=0, column=1)
## Joueur2:
lbl_j2 = Label(toplevel, text='Joueur2:')
lbl_j2.grid(row=1, column=0)
entry_j2 = Entry(toplevel, textvariable=nom_j2)
entry_j2.grid(row=1, column=1)
#Boutons:
boutonValider = Button(toplevel, text='Valider', command=valider)
boutonValider.grid(row=2, column=0)
boutonRegles = Button(toplevel, text='Règles', command=regles)
boutonRegles.grid(row=2, column=1)
root = Tk()
## Variables tkinter, pour les noms (On les sort de la fonction)
nom_j1 = StringVar()
nom_j2 = StringVar()
label = Label(root, text='Bienvenue sur notre Jeu!!')
label.pack()
boutonJouer = Button(root, text='Jouer!', command=jouer)
boutonJouer.pack()
boutonRegles = Button(root, text='Régles', command=regles)
boutonRegles.pack()
root.mainloop()
Fichier DC3:
from tkinter import *
## La variable de la fenêtre principale.
## Elle n'est pas encore déclaré, puisqu'elle sera créé dans la fonction main()
root2 = None
def main(nom1, nom2):
## Pour que les autres fonctions utilisent cette fenêtre (root2).
## On déclare root2 comme étant global.
global root2
root2 = Tk()
label = Label(root2, text='Voici le Damier..')
label.pack()
bienvenue1 = Label(root2, text='JOUEUR1: %s'%(nom1))
bienvenue1.pack()
bienvenue2 = Label(root2, text='JOUEUR2: %s'%(nom2))
bienvenue2.pack()
root2.mainloop()
Dans ce fichier, il y a la fonction main()... qui possède des paramètres, pour obtenir les noms du premier fichier.
Mais tout, cela revient à ce que j'avais écris dans les premiers posts.
Vous aviez qu'à enlever ou modifier le bouton VALIDER, si c'était que cela qui vous perturbait...
PS: Vous remarquerez qu'il n'y a aucun .mainloop() pour tous les toplevel. Puisqu'ils sont des fenêtres secondaires.
J'espère que c'est que vous demandiez.
Sinon, je suis certains qu'il y a tout ce qu'il vous faut, pour que cela fonctionne!!. Il faut seulement mettre du vôtre, pour comprendre le fonctionnement de TKINTER.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Blond, bouclé, toujours le sourire aux lèvres...
Blond, bouclé, toujours le sourire aux lèvres...