Python tkinter同时进行多次更新?

时间:2018-04-18 11:22:38

标签: python python-3.x tkinter

我是预科班的法国学生,明年我的考试工作要做。我的项目是模拟和优化高速公路上的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()

1 个答案:

答案 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的回答

我真的不知道,所以请告诉我是否需要创建另一个帖子