Ejemplo n.º 1
0
    def __init__(self, window):
        """
		Constructeur par défaut de l'interface du menu multijoueur
		Prend comme argument la fenêtre
		
		Ce menu n'est absolument pas encore travaillé et n'est là qu'en prévision
		"""
        GUI.__init__(self, window, True)

        # Création des boutons
        local = tk.Button(window,
                          textvariable=msgs.LOCAL,
                          font=("Plantagenet Cherokee", 30),
                          anchor="center",
                          width=15,
                          borderwidth=4,
                          bg=utils.BUTTON_BACKGROUND,
                          relief="raise",
                          command=lambda: utils.showMessageDialog(
                              msgs.SOON, msgs.FUTURE_FEATURE))
        online = tk.Button(window,
                           textvariable=msgs.ONLINE,
                           font=("Plantagenet Cherokee", 30),
                           anchor="center",
                           width=15,
                           borderwidth=4,
                           bg=utils.BUTTON_BACKGROUND,
                           relief="raise",
                           command=lambda: utils.showMessageDialog(
                               msgs.SOON, msgs.FUTURE_FEATURE))
        backBtn = tk.Button(window,
                            textvariable=msgs.BACK,
                            font=("Plantagenet Cherokee", 30),
                            anchor="center",
                            width=15,
                            borderwidth=4,
                            bg=utils.BUTTON_BACKGROUND,
                            relief="raise",
                            command=lambda: back(window))

        # Affichage et positionnement des boutons sur l'interface
        local.place(relx=.025, rely=.37, relwidth=.42, relheight=.11)
        online.place(relx=.025, rely=.49, relwidth=.42, relheight=.11)
        backBtn.place(relx=.74, rely=.88, relwidth=.26, relheight=.12)

        # Ajout des boutons comme enfants
        self.appendChild(local)
        self.appendChild(online)
        self.appendChild(backBtn)
Ejemplo n.º 2
0
    def __init__(self, window: tk.Tk, gameBuilder: GameBuilder):
        """
		Constructeur par défaut du sélecteur de voiture
		Prend comme argument la fenêtre et le constructeur de partie
		"""
        GUI.__init__(self, window)

        self.builder = gameBuilder

        # master représente un cadre dans lequel sera incorporé le sélecteur ainsi que les barres de défilement
        master = tk.Frame(window,
                          width=window.winfo_screenwidth(),
                          height=window.winfo_screenheight())
        master.place(x=0, y=0, relwidth=1, relheight=1)
        self.appendChild(master)

        # Création des barres de défilement
        vscrollbar = tk.Scrollbar(master, orient=tk.VERTICAL)
        hscrollbar = tk.Scrollbar(master, orient=tk.HORIZONTAL)
        vscrollbar.pack(side=tk.RIGHT, fill=tk.Y, expand=tk.FALSE)
        hscrollbar.pack(side=tk.BOTTOM, fill=tk.X, expand=tk.FALSE)
        self.appendChild(vscrollbar)
        self.appendChild(hscrollbar)

        # Afin de pouvoir déplacer la fenêtre, nécessité de passer par un canevas
        # x(y)scrollcommand : Contrôle la taille des barres de défilement
        # scrollregion : Définit la zone de défilement (pour des raisons obscrures, nécessité de définir cela de façon statique)
        canvas = tk.Canvas(master,
                           xscrollcommand=hscrollbar.set,
                           yscrollcommand=vscrollbar.set,
                           width=window.winfo_screenwidth(),
                           height=window.winfo_screenheight(),
                           scrollregion="0 0 %s %s" %
                           (window.winfo_screenwidth() + 54,
                            window.winfo_screenheight() - 100))
        # Création du cadre dans lequel seront déposés les composants
        frame = tk.Frame(canvas,
                         width=window.winfo_screenwidth(),
                         height=window.winfo_screenheight())
        # Placement du cadre dans le canevas
        canvas.create_window(0, 0, window=frame, anchor=tk.NW)
        # Placement du canevas
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.FALSE)
        canvas.xview_moveto(0)
        canvas.yview_moveto(0)

        # Définition de l'action des barres de défilement (déplacer le canevas)
        vscrollbar.config(command=canvas.yview)
        hscrollbar.config(command=canvas.xview)

        for i in range(len(cars.CARS)):
            # Pour chaque voiture, affichae d'une ligne d'informations
            car = cars.CARS[i]
            # Chargement de l'image de miniature grâce au module PIL
            image = Image.open("images/thumbnails/" + car.thumbnail_file)
            # Redimensionnement de l'image en 100x100 avec anti-crénelage
            image = image.resize((100, 100), Image.ANTIALIAS)
            # Remplacement de l'image
            image.save("images/thumbnails/" + car.thumbnail_file,
                       car.thumbnail_file[-3:])
            # Conversion de l'image en Tkinter
            thumbnail = tk.PhotoImage(file="images/thumbnails/" +
                                      car.thumbnail_file)
            # Passage de l'image en Label et placement dans l'interface
            thumbnailLabel = tk.Label(frame, image=thumbnail)
            thumbnailLabel.image = thumbnail
            thumbnailLabel.grid(row=5 * i, column=0, rowspan=4)
            # Affichage du nom de la voiture
            label = tk.Label(frame,
                             textvariable=car.name,
                             font=("Plantagenet Cherokee", 30))
            label.grid(row=5 * i, column=1, rowspan=4)
            # Affichage de la vitesse de la voiture
            speedLabel = tk.Label(frame,
                                  textvariable=msgs.MAX_SPEED.format(
                                      car.max_speed),
                                  font=("Plantagenet Cherokee", 16))
            speedLabel.grid(row=5 * i, column=2)
            # Affichage de la capacité d'accélération de la voiture
            accelerateLabel = tk.Label(frame,
                                       textvariable=msgs.ACCELERATION.format(
                                           60 * car.acceleration),
                                       font=("Plantagenet Cherokee", 16))
            accelerateLabel.grid(row=5 * i + 1, column=2)
            # Affichage de la taille de la voiture
            sizeLabel = tk.Label(frame,
                                 textvariable=msgs.SIZE.format(
                                     car.width, car.height),
                                 font=("Plantagenet Cherokee", 16))
            sizeLabel.grid(row=5 * i + 2, column=2)
            # Affichage de la maniabilité de la voiture (présenté comme unité arbitraire sans réellement en être une)
            maniabilityLabel = tk.Label(frame,
                                        textvariable=msgs.MANIABILITY.format(
                                            2 * car.maniability),
                                        font=("Plantagenet Cherokee", 16))
            maniabilityLabel.grid(row=5 * i + 3, column=2)
            # Affichage du bouton de sélection
            choose = tk.Button(frame,
                               textvariable=msgs.CHOOSE,
                               bg=utils.BUTTON_BACKGROUND,
                               font=("Plantagenet Cherokee", 22))
            choose.grid(row=5 * i, column=3, rowspan=4)

            # Si la voiture a déjà été choisie (pour modification), affichage d'un check à côté
            if self.builder.car == car:
                ok = tk.Label(frame, text="ü", font=("Wingdings", 42))
                ok.grid(row=5 * i, column=4, rowspan=4)
                self.appendChild(ok)

            # Si ce n'est pas la dernière voiture, affichage d'une ligne grisée
            if i < len(cars.CARS) - 1:
                canvas = tk.Canvas(frame,
                                   width=window.winfo_screenwidth(),
                                   height=5,
                                   bg="lightgray")
                canvas.grid(row=5 * i + 4, columnspan=4)
                self.appendChild(canvas)

            # Inscription de l'écouteur pour le click du bouton de sélection
            self.registerChooseListener(window, choose, car)

            # Ajout de tous les composants comme enfants
            self.appendChild(frame)
            self.appendChild(thumbnailLabel)
            self.appendChild(label)
            self.appendChild(speedLabel)
            self.appendChild(accelerateLabel)
            self.appendChild(sizeLabel)
            self.appendChild(maniabilityLabel)
            self.appendChild(choose)

        # Ajout du bouton retour
        backBtn = tk.Button(frame,
                            textvariable=msgs.BACK,
                            bg=utils.BUTTON_BACKGROUND,
                            font=("Plantagenet Cherokee", 30),
                            anchor="center",
                            width=20,
                            borderwidth=10,
                            relief="groove",
                            command=lambda: back(window))
        backBtn.grid(row=5 * (len(cars.CARS) + 1), columnspan=4, pady=100)
        self.appendChild(backBtn)

        # Configuration des poids (rapports de longueur) de chaque colonne
        frame.columnconfigure(0, weight=1)
        frame.columnconfigure(1, weight=2)
        frame.columnconfigure(2, weight=3)
        frame.columnconfigure(3, weight=2)
        frame.columnconfigure(4, weight=1)

        # Mise à jour de la zone de scroll lorsque le cadre est redimensionné
        # En apparence mystérieusement non fonctionnel
        # noinspection PyUnusedLocal
        def _configure_frame(eventf):
            size = (frame.winfo_reqwidth(), frame.winfo_reqheight())
            canvas.config(scrollregion="0 0 %s %s" % size)

        frame.bind("<Configure>", _configure_frame)
Ejemplo n.º 3
0
 def choose_map():
     self.builder.map = map
     back(window)
Ejemplo n.º 4
0
    def __init__(self, window: tk.Tk, gameBuilder: GameBuilder):
        """
		Constructeur par défaut du sélecteur de carte
		Prend comme argument la fenêtre et le constructeur de partie
		"""
        GUI.__init__(self, window)

        self.builder = gameBuilder

        for i in range(len(maps.MAPS)):
            # Pour chaque carte, affiche une ligne d'informations et de sélection
            map = maps.MAPS[i]
            # Lecture de l'image de miniature grâce au module PIL
            image = Image.open("images/thumbnails/" + map.thumbnail)
            # Redimensionnement de l'image en 100x100 avec anti-crénelage
            image = image.resize((100, 100), Image.ANTIALIAS)
            # Remplacement de l'ancien fichier
            image.save("images/thumbnails/" + map.thumbnail,
                       map.thumbnail[-3:])
            # Conversion de l'image en image Tkinter
            thumbnail = tk.PhotoImage(file="images/thumbnails/" +
                                      map.thumbnail)
            # Placement de l'image dans un label et positionnement dans l'interface
            thumbnailLabel = tk.Label(window, image=thumbnail)
            thumbnailLabel.image = thumbnail
            thumbnailLabel.grid(row=i, column=0, rowspan=1)
            # Affichage du nom de la carte
            label = tk.Label(window,
                             textvariable=map.name,
                             font=("Plantagenet Cherokee", 30))
            label.grid(row=i, column=1, rowspan=1)
            # Affichage de la taille (en pixels) de la carte
            sizeLabel = tk.Label(window,
                                 textvariable=msgs.SIZE.format(
                                     map.width, map.height),
                                 font=("Plantagenet Cherokee", 22))
            sizeLabel.grid(row=i, column=2)
            # Affichage du bouton de sélection de la carte
            choose = tk.Button(window,
                               textvariable=msgs.CHOOSE,
                               bg=utils.BUTTON_BACKGROUND,
                               font=("Plantagenet Cherokee", 22))
            choose.grid(row=i, column=3, rowspan=1)

            # Si une carte était déjà sélectionné, affichage d'un check à côté
            if self.builder.map == map:
                ok = tk.Label(window, text="ü", font=("Wingdings", 42))
                ok.grid(row=i, column=4, rowspan=1)
                self.appendChild(ok)

            # Inscription de l'écouteur pour le clic du bouton
            self.registerChooseListener(window, choose, map)

            # Ajout des enfants
            self.appendChild(thumbnailLabel)
            self.appendChild(label)
            self.appendChild(sizeLabel)
            self.appendChild(choose)

        # Configuration des poids des colonnes
        window.columnconfigure(0, weight=1)
        window.columnconfigure(1, weight=2)
        window.columnconfigure(2, weight=3)
        window.columnconfigure(3, weight=2)
        window.columnconfigure(4, weight=1)

        # Affichage du bouton retour
        backBtn = tk.Button(window,
                            textvariable=msgs.BACK,
                            font=("Plantagenet Cherokee", 30),
                            bg=utils.BUTTON_BACKGROUND,
                            anchor="center",
                            width=20,
                            borderwidth=10,
                            relief="groove",
                            command=lambda: back(window))
        backBtn.grid(row=len(cars.CARS) * 2 + 1,
                     column=0,
                     columnspan=5,
                     pady=100)
        self.appendChild(backBtn)
Ejemplo n.º 5
0
 def choose_car():
     self.builder.car = car
     back(window)
Ejemplo n.º 6
0
    def __init__(self, window):
        """
		Constructeur par défaut de l'interface du menu un joueur
		Prend comme argument la fenêtre
		"""
        GUI.__init__(self, window, True)

        # builder représente le constructeur de partie actuel (créé si inexistant)
        builder = GameBuilder.CURRENT_GAME_BUILDER
        if builder is None:
            builder = GameBuilder.CURRENT_GAME_BUILDER = GameBuilder(
                GameBuilder.SINGLE_PLAYER_MODE)

        # Création des boutons
        car = tk.Button(window,
                        textvariable=msgs.CAR_CHOICE,
                        font=("Plantagenet Cherokee", 30),
                        anchor="center",
                        width=15,
                        borderwidth=4,
                        bg=utils.BUTTON_BACKGROUND,
                        relief="raise",
                        command=lambda: CarChooser(window, builder))
        chooseMap = tk.Button(window,
                              textvariable=msgs.MAP_CHOICE,
                              font=("Plantagenet Cherokee", 30),
                              anchor="center",
                              width=15,
                              borderwidth=4,
                              bg=utils.BUTTON_BACKGROUND,
                              relief="raise",
                              command=lambda: MapChooser(window, builder))
        start = tk.Button(window,
                          textvariable=msgs.START,
                          font=("Plantagenet Cherokee", 30),
                          anchor="center",
                          width=15,
                          borderwidth=4,
                          bg=utils.BUTTON_BACKGROUND,
                          relief="raise",
                          state=tk.DISABLED if builder.car is None
                          or builder.map is None else tk.NORMAL,
                          command=lambda: builder.start(window))
        backBtn = tk.Button(window,
                            textvariable=msgs.BACK,
                            font=("Plantagenet Cherokee", 30),
                            anchor="center",
                            width=15,
                            borderwidth=4,
                            bg=utils.BUTTON_BACKGROUND,
                            relief="raise",
                            command=lambda: back(window))

        # Positionnement des boutons sur l'interface
        car.place(relx=.025, rely=.25, relwidth=.42, relheight=.11)
        chooseMap.place(relx=.025, rely=.37, relwidth=.42, relheight=.11)
        start.place(relx=.025, rely=.49, relwidth=.42, relheight=.11)
        backBtn.place(relx=.74, rely=.88, relwidth=.26, relheight=.12)

        # Ajout des boutons comme enfants
        self.appendChild(car)
        self.appendChild(chooseMap)
        self.appendChild(start)
        self.appendChild(backBtn)
Ejemplo n.º 7
0
	def __init__(self, window : tk.Tk):
		"""
		Constructeur par défaut du menu de scores
		Prend comme argument la fenêtre et le constructeur de partie
		"""
		GUI.__init__(self, window)

		# Création du bouton retour
		backBtn = tk.Button(window, textvariable = msgs.BACK, font = ("Plantagenet Cherokee", 30), anchor = "center", width = 15, borderwidth = 4, bg = utils.BUTTON_BACKGROUND, relief = "groove", command = lambda : back(window))
		backBtn.place(relx = .74, rely = .88, relwidth = .26, relheight = .12)
		self.appendChild(backBtn)

		# Détermination du nombre de colonnes (1 colonne pour la carte, 1 colonne pour le temps, 1 colonne pour la voiture, autant de colonnes qui il y a de tours au maximum
		columns = 3
		for map in maps.MAPS:
			columns = max(columns, map.max_laps + 3)

		# Définition du poids de chaque colonne à 1
		for i in range(columns):
			window.columnconfigure(i, weight = 1)

		# Définition et affichage des en-têtes
		total_time_label = tk.Label(window, textvariable = msgs.TOTAL_TIME, font = ("Plantagenet Cherokee", 18, "bold"), relief = "groove")
		total_time_label.grid(row = 0, column = 1, sticky = "nsew")
		self.appendChild(total_time_label)
		car_label = tk.Label(window, textvariable = msgs.CAR, font = ("Plantagenet Cherokee", 18, "bold"), relief = "groove")
		car_label.grid(row = 0, column = columns - 1, sticky = "nsew")
		self.appendChild(car_label)

		# Affichage des en-têtes des temps par tour
		for lap in range(0, columns - 3):
			lap_time_label = tk.Label(window, textvariable = msgs.LAP_TIME.format(lap + 1), font = ("Plantagenet Cherokee", 18, "bold"), relief = "groove")
			lap_time_label.grid(row = 0, column = lap + 2, sticky = "nsew")
			self.appendChild(lap_time_label)

		# Curseur donnant la ligne actuelle du tableau
		row_index = 1

		for map_index in range(len(maps.MAPS)):
			# Pour chaque carte, récupérer la liste des scores triés par le temps effectués sur cette carte
			map = maps.MAPS[map_index]
			map_scores = list()
			for score in utils.SCORES:
				if score.map == map:
					map_scores.append(score)
			map_scores.sort()

			# Afficher le nom de la carte à gauche
			mapLabel = tk.Label(window, textvariable = map.name, font = ("Plantagenet Cherokee", 18, "bold"), relief = "groove")
			mapLabel.grid(row = row_index, column = 0, rowspan = max(1, len(map_scores)), sticky = "nsew")
			self.appendChild(mapLabel)

			for score in map_scores:
				# Pour chaque score, afficher le temps total et la voiture utilisée
				total_time_label = tk.Label(window, text = score.total_time, font = ("Plantagenet Cherokee", 18), relief = "groove")
				total_time_label.grid(row = row_index, column = 1, sticky = "nsew")
				self.appendChild(total_time_label)
				car_label = tk.Label(window, textvariable = score.car.name, font = ("Plantagenet Cherokee", 18), relief = "groove")
				car_label.grid(row = row_index, column = columns - 1, sticky = "nsew")
				self.appendChild(car_label)

				for lap in range(map.max_laps):
					# Pour chaque tour, afficher le temps effectué
					lap_time_label = tk.Label(window, text = score.laps_time[lap], font = ("Plantagenet Cherokee", 18), relief = "groove")
					lap_time_label.grid(row = row_index, column = lap + 2, sticky = "nsew")
					self.appendChild(lap_time_label)
				# Incrémenter le compteur de ligne
				row_index += 1
Ejemplo n.º 8
0
	def __init__(self, window):
		"""
		Constructeur par défaut de l'interface de paramètres (Fond d'écran actif)
		Prend en paramètre la fenêtre
		"""
		GUI.__init__(self, window, True)

		# Définition des textes des boutons de (dés)activation de la musique et des effets sonores en fonction des paramètres actuels
		switchMusicMsg = (msgs.DISABLE_MUSIC if window.music_enabled else msgs.ENABLE_MUSIC).clone()
		switchSoundsMsg = (msgs.DISABLE_SOUNDS if window.sounds_enabled else msgs.ENABLE_SOUNDS).clone()

		# Création des boutons
		music = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = switchMusicMsg, font = ("Plantagenet Cherokee", 30), anchor = "center", width = 22, borderwidth = 4, relief = "raise")
		sounds = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = switchSoundsMsg, font = ("Plantagenet Cherokee", 30), anchor = "center", width = 22, borderwidth = 4, relief = "raise")
		changeLanguage = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = msgs.CHANGE_LANGUAGE,  font = ("Plantagenet Cherokee", 30), anchor = "center", width = 22, borderwidth = 4, relief = "raise", command = msgs.switchLanguage)
		controls = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = msgs.CHANGE_CONTROLS, font = ("Plantagenet Cherokee", 30), anchor = "center", width = 22, borderwidth = 4, relief = "raise", command = lambda : Controls(window))
		back = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = msgs.BACK, font = ("Plantagenet Cherokee", 30), anchor = "center", width = 15, borderwidth = 4, relief = "groove", command = lambda : guis.back(window))

		# Affichage des boutons
		music.place(relx = .025, rely = .25, relwidth = .42, relheight = .11)
		sounds.place(relx = .025, rely = .37, relwidth = .42, relheight = .11)
		changeLanguage.place(relx = .025, rely = .49, relwidth = .42, relheight = .11)
		controls.place(relx = .025, rely = .61, relwidth = .42, relheight = .11)
		back.place(relx = .74, rely = .88, relwidth = .26, relheight = .12)

		def switchMusicState():
			"""
			Change l'état d'activation de la musique
			La musique est lancée dans le sous-module audio
			"""
			if window.music_enabled:
				switchMusicMsg.switch(msgs.ENABLE_MUSIC)
			else:
				switchMusicMsg.switch(msgs.DISABLE_MUSIC)
			window.music_enabled ^= True
			saveSettings()

		def switchSoundsState():
			"""
			Change l'état d'activation des effets sonores
			"""
			if window.sounds_enabled:
				switchSoundsMsg.switch(msgs.ENABLE_SOUNDS)
			else:
				switchSoundsMsg.switch(msgs.DISABLE_SOUNDS)
			window.sounds_enabled ^= True
			saveSettings()

		# Affectation des évenements de clics
		music.config(command = switchMusicState)
		sounds.config(command = switchSoundsState)

		# Ajout des enfants
		self.appendChild(music)
		self.appendChild(sounds)
		self.appendChild(changeLanguage)
		self.appendChild(controls)
		self.appendChild(back)
Ejemplo n.º 9
0
	def __init__(self, window):
		"""
		Constructeur par défaut de l'interface de changements des contrôles (fond d'écran actif)
		Prend en paramètre la fenêtre
		"""
		super().__init__(window, True)

		# Création des labels et des boutons
		forwardLabel = tk.Label(window, textvariable = msgs.FORWARD, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		forwardText = tk.StringVar(window, utils.CONTROLS["forward"].replace("_", " "))
		forward = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = forwardText, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		leftLabel = tk.Label(window, textvariable = msgs.TURN_LEFT, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		leftText = tk.StringVar(window, utils.CONTROLS["left"].replace("_", " "))
		left = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = leftText, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		backwardLabel = tk.Label(window, textvariable = msgs.BACKWARD, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		backwardText = tk.StringVar(window, utils.CONTROLS["backward"].replace("_", " "))
		backward = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = backwardText, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		rightLabel = tk.Label(window, textvariable = msgs.TURN_RIGHT, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")
		rightText = tk.StringVar(window, utils.CONTROLS["right"].replace("_", " "))
		right = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = rightText, font = ("Plantagenet Cherokee", 21), width = 10, relief ="raise")

		# Création du bouton retour
		back = tk.Button(window, bg = utils.BUTTON_BACKGROUND, textvariable = msgs.BACK, font = ("Plantagenet Cherokee", 30), anchor = "center", width = 15, borderwidth = 4, relief ="groove", command = lambda : guis.back(window))

		# Affichage des boutons sur l'interface
		forwardLabel.place(relx = .025, rely = .30, relwidth = 0.275, relheight = .07)
		forward.place(relx = .35, rely = .30, relwidth = .2, relheight = .07)
		leftLabel.place(relx = .025, rely = .38, relwidth = .275, relheight = .07)
		left.place(relx = .35, rely = .38, relwidth = .2, relheight = .07)
		backwardLabel.place(relx = .025, rely = .46, relwidth = .275, relheight = .07)
		backward.place(relx = .35, rely = .46, relwidth = .2, relheight = .07)
		rightLabel.place(relx = .025, rely = .54, relwidth = .275, relheight = .07)
		right.place(relx = .35, rely = .54, relwidth = .2, relheight = .07)
		back.place(relx = .74, rely = .88, relwidth = .26, relheight = .12)

		def requestNewKey(index, buttonText, label):
			"""
			Affiche une boîte de dialogue demandant la nouvelle touche à affecter à l'action
			 Le paramètre index représente le numéro de l'action
			 Le paramètre buttonText représente l'affichage du bouton, soit le nom de la touche
			 Le paramètre label représente le nom de l'action (localisé/traduit)
			"""
			# Création d'une boîte de dialogue
			popup = tk.Toplevel(window)
			# Ajout du texte dans la boîte
			label = tk.Label(popup, textvariable = msgs.WHAT_KEY_FOR.format(label.get().lower()), font = ("Plantagenet Cherokee", 30))
			label.grid(row = 0, column = 0, padx = 10, pady = 10)
			# Définition de la géométrie de la boîte ainsi que son positionnement sur l'écran (centré)
			width = label.winfo_reqwidth() + 20
			height = label.winfo_height() + 80
			screenWidth = popup.winfo_screenwidth()
			screenHeight = popup.winfo_screenheight()
			popup.geometry(str(width) + "x" + str(height) + "+" + str(int((screenWidth - width) / 2)) + "+" + str(int((screenHeight - height) / 2) - 40))
			# Variable expliquée plus tard
			sound_started = tk.BooleanVar(False)
			def catch_key_event(event):
				"""
				Méthode invoquée lorsqu'une touche est pressée
				Paramètre : informations par rapport à l'évennemment "appuyer sur une touche"
				"""
				# event.keycode est le numéro de la touche dans la table ASCII
				key = event.keycode
				# La touche 27 est la touche ÉCHAP qui annule alors la modification de contrôle
				if key == 27:
					popup.destroy()
					return
				# On vérifie si la touche n'est pas déjà assignée et si ce n'est pas la touche F11 (utile pour le plein écran)
				if event.keysym.upper() in utils.CONTROLS.values() or event.keysym.upper() == "F11":
					# Si on est sous windows, le son d'erreur est alors déclenché
					# La variable sound_started permet alors de savoir si ce son a déjà été déclenché
					if utils.isWindows():
						import winsound, threading
						if not sound_started.get():
							def start_sound():
								sound_started.set(True)
								winsound.PlaySound("*", winsound.SND_ALIAS)
								sound_started.set(False)
							threading.Thread(target = start_sound).start()
					return
				# Changement du texte du bouton avec le nouveau contrôle
				buttonText.set(event.keysym.upper().replace("_", " "))
				# Affectation du nouveau contrôle
				utils.CONTROLS[index] = event.keysym.upper()
				# Fermeture de la boîte de dialogue
				popup.destroy()
				# Écriture des paramètres
				saveSettings()
			# Appelle la fonction catch_key_event lors de l'appui de n'importe quelle touche de clavier
			popup.bind("<KeyPress>", catch_key_event)
			# Force la mise en avant de la boîte de dialogue et la laisse en avant-plan
			popup.focus_force()
			popup.wm_attributes("-topmost", 1)
			popup.grab_set()

		forward.bind("<ButtonRelease-1>", lambda event : requestNewKey("forward", forwardText, msgs.FORWARD))
		left.bind("<ButtonRelease-1>", lambda event : requestNewKey("left", leftText, msgs.TURN_LEFT))
		backward.bind("<ButtonRelease-1>", lambda event : requestNewKey("backward", backwardText, msgs.BACKWARD))
		right.bind("<ButtonRelease-1>", lambda event : requestNewKey("right", rightText, msgs.TURN_RIGHT))

		window.columnconfigure(0, weight = 3)
		window.columnconfigure(1, weight = 2)

		# Ajout des enfants
		self.appendChild(forwardLabel)
		self.appendChild(forward)
		self.appendChild(leftLabel)
		self.appendChild(left)
		self.appendChild(backwardLabel)
		self.appendChild(backward)
		self.appendChild(rightLabel)
		self.appendChild(right)
		self.appendChild(back)