我是预科班的法国学生,明年我的考试工作要做。我的项目是模拟和优化高速公路上的botlleneck。我正在使用Tkinter作为GUI,我在画布上使用create_rectangle显示汽车。问题是,我的main函数使用after_idle方法进行循环,似乎在循环期间多次运行。例如,汽车的颜色(取决于汽车的类型,我的'模型'变量(抱歉用法语编码,但代码将很快变得相当复杂,我希望我班上的任何人或教师能够阅读它))在执行过程中发生了变化,即使它在我的代码中从未修改过。我看到的唯一选项是在循环期间修改列表,因此'creer_voiture'功能添加的汽车颜色也显示在其他汽车上。因此看起来索引在循环期间发生了变化,我将汽车的数据替换为另一个。如果有人找到答案,我会很高兴,并且会对那些花时间阅读我的代码的人表示满意。
###Imports
try:
import tkinter as tk
except:
import Tkinter as tk
import random as rd
import time
import copy
import numpy as np
from operator import itemgetter
###Largeur de l'ecran
try:
import ctypes
user32 = ctypes.windll.user32
LARGEUR_ECRAN = user32.GetSystemMetrics(0)
except ImportError:
LARGEUR_ECRAN =1024
###Constantes et parametres
NOMBRE_VOIES = 5
LONGUEUR_VOIES = 1000#m
LARGEUR_VOIES = 3.5#m
ABSCISSE_DEPART = 50#inferieur au quart de la longueur de voies
VITESSE_MAX = 130/3.6
TEMPS_NOUVELLE_VOITURE = 3
longueur_voiture = (4, 3.5, 3)#m
largeur_voiture = (1.5,2,1.8)#m
acceleration_voiture = (2.8, 2.5, 3)# m/s²
couleur = ('red', 'green', 'blue')
###Definition des variables
voitures = []#liste de voitures
#le format est (x,y,v,modele),
# avec (x,y) les coordonees du coin en haut a gauche de la voiture
voitures_prec = []#liste de voitures utilisées pour avoir les données avant l'actualisation
voitures_aff = []#les ID des voitures affichées
temps_prec = time.time()#en secondes, servira pour le dt aparaissant dans les formules
temps_derniere_voiture = time.time()#temps depuis l'ajout de la derniere voiture
###Variables additionelles
PAUSE = False#pour mettre l'execution en pause
###
###Debut programme
###
###GUI
root = tk.Tk()
root.geometry('{}x600'.format(str(LARGEUR_ECRAN)))
root.resizable(0, 0)
###Fonctions auxiliaires
def creer_voiture(voie, vitesse, modele):
"""
cree une voiture et en ajoute les caracteristiques dans les differents listes
"""
#ajout dans les listes:
voitures.append((ABSCISSE_DEPART,3.5*(voie-1) + 3.5 - largeur_voiture[modele]- 0.2, vitesse, modele))
L = longueur_voiture[modele]*echelle_x
l = largeur_voiture[modele]*echelle_x
x = ABSCISSE_DEPART*echelle_x
y = (3.5*(voie-1) + 3.5 - largeur_voiture[modele]- 200)*echelle_x
voitures_aff.append(route.create_rectangle(x, y, x+L, y+l, fill = couleur[modele]))
def creer_route():
"""
initialise l'affichage des voies
"""
global LONGUEUR_VOIES, NOMBRE_VOIES
l = LARGEUR_ECRAN
NOMBRE_VOIES = int(def_nb_voies.get())
LONGUEUR_VOIES = float(def_longueur_voies.get())
route.delete('all')#reinitialise l'affichage
for i in range(1, NOMBRE_VOIES*4):
for j in range(int(LONGUEUR_VOIES)//(13*4) +1):
if i%NOMBRE_VOIES == 0:
route.create_line(0, i*400/(NOMBRE_VOIES*4), l,\
i*400/(NOMBRE_VOIES*4), width = '3.0')
#les lignes continues separant les differents troncons
else:
route.create_line(j*13*4*l/LONGUEUR_VOIES, i*400/(NOMBRE_VOIES*4),\
(j*13 + 3)*l*4/LONGUEUR_VOIES, i*400/(NOMBRE_VOIES*4))
#les lignes discontinues separant les voies
route.create_line(0, 400, l, 400, width = '3.0')
def lancer_sim():
"""
demarre ou relance la simulation
"""
route.delete('all')
creer_route()
global PAUSE, temps_prec, temps_derniere_voiture, echelle_x, echelle_y
echelle_x = 4*LARGEUR_ECRAN/LONGUEUR_VOIES
echelle_y = 400/(4*3.5*NOMBRE_VOIES)
PAUSE = False
temps_prec = time.time()
temps_derniere_voiture = time.time()
main()
def pause_sim():
"""
met la simulation en pause
"""
global PAUSE
PAUSE = True
###Calcul de la position de la i-eme voiture:
def pos(i, dt):
x, y, v, modele = voitures_prec[i]
#detection de la voiture precedante
return x+v*dt, y
###Boucle principale
def main():
#variables globales
global voitures, temps_prec, temps_derniere_voiture, voitures_prec
#initialisation des variables
voitures.sort(key = itemgetter(0))#les voitures sont dans l'ordre inverse!!!
voitures_prec = voitures
dt = time.time() - temps_prec
temps_prec += dt
a_retirer = []
for i in range(len(voitures_prec)):
#initialisation des variables
x, y, v, modele = voitures[i]
L = longueur_voiture[modele]
l = largeur_voiture[modele]
#teste si la voiture sort du troncon:
if x > LONGUEUR_VOIES:
#la marque comme indesirable
a_retirer += [i]
#sinon:
else:
#calcule la position
xs, ys = pos(i, dt)
#met a jour la liste voitures
if dt > 1e-3:#si le temps es trop faible, on considere la vitesse inchangee
v = (xs-x)/dt
voitures[i] = (xs, ys, v, modele)
#deplace la voiture
route.coords(voitures_aff[i], (xs%(LONGUEUR_VOIES//4))*echelle_x,\
(ys+(3.5*NOMBRE_VOIES*((4*xs)//LONGUEUR_VOIES)))*echelle_y, \
((xs%(LONGUEUR_VOIES//4)+L))*echelle_x,\
(ys+(3.5*NOMBRE_VOIES*((4*xs)//LONGUEUR_VOIES))+l)*echelle_y)
#retire ce qu'il faut
for i in list(reversed(a_retirer)):
del voitures[i]
route.delete(voitures_aff[i])
#rajoute une voiture au besoin
if time.time()-temps_derniere_voiture > 2:
creer_voiture(rd.randint(1, NOMBRE_VOIES), \
rd.randint(90,130)/3.6, rd.randint(0,2))
temps_derniere_voiture = time.time()
lbl.configure(text = str(voitures))
if not PAUSE:
root.after_idle(main)
###Configuration de la fenetre et execution
route = tk.Canvas(root, width = LARGEUR_ECRAN, height = 400, bg = 'white')
route.grid(row = 0, column = 0, rowspan = 9, columnspan = 9)
tk.Label(root, text = 'set lanes number : ').grid(row = 9, column = 0)
tk.Label(root, text = 'set lanes length : ').grid(row = 10, column = 0)
def_nb_voies = tk.Entry(root)
def_nb_voies.grid(row = 9, column = 1)
def_nb_voies.insert(0, '5')
def_nb_voies.bind('<Return>', lancer_sim)
def_longueur_voies = tk.Entry(root)
def_longueur_voies.grid(row = 10, column = 1)
def_longueur_voies.insert(0, '1000')
def_longueur_voies.bind('<Return>', lancer_sim)
lancer = tk.Button(root, text = "Lancer ou reprendre la simulation",\
command = lancer_sim, bg = 'green')
lancer.grid(row = 10, column = 8)
lbl_frame = tk.Frame(root, width = LARGEUR_ECRAN, height = 100)
lbl_frame.grid(row = 13, column = 0, columnspan = 9, rowspan = 3)
lbl_frame.grid_propagate(False)
lbl = tk.Label(lbl_frame, bg = 'white')
lbl.grid()
pause_btn = tk.Button(root, command = pause_sim, text = 'Pause', bg = 'red')
pause_btn.grid(row = 11, column = 8)
creer_route
root.mainloop()
答案 0 :(得分:0)
我可能已经发现了这个问题:在我的主要功能的开头,我用汽车的坐标对列表进行排序,但是我没有用画布上的矩形的ID对列表进行排序。我还有的问题是如何做到这一点?我需要在第一个列表上做的每一项更改都在第二个列表中进行,比如
from operator import itemgetter
l1 = [(x1, y1, type1), (x2, y2, type2),...]
l2 = [road.create_rectangle(x1, y1, x1 +length, y1 +width),...]
l1.sort(key = itemgetter(0))
l2.sort#??????
感谢@BryanOakley的回答
我真的不知道,所以请告诉我是否需要创建另一个帖子