Создавать и удалять виджеты Canvas и перемещать их одновременно - PullRequest
0 голосов
/ 08 сентября 2018

Я пытаюсь изучить Python с помощью простой программы, которая порождает квадраты, используя tkinter. Перемещает их по холсту и потом их убирает.

2 Проблемы.

  1. Как мне их убрать? Я узнал о методе canvas.destroy(), но он либо ничего не делает, либо я получаю ошибку вне диапазона.

  2. Я создаю Класс, который создает квадрат и имеет функцию перемещения внутри. Я вызываю функцию перемещения на экземпляре класса с помощью кнопки. Это работает, но теперь я хотел бы назвать их всех сразу, чтобы они двигались независимо друг от друга. Проблема в том, что, если я нажму кнопку, для Экземпляра, № 2, уже движущийся квадрат (Экземпляр № 1) перестанет работать. Зачем? и как я могу обойти это?

Вот мой код, только класс автомобиля. Полагаю, все остальное не важно: (простите, если это глупо ... Я новичок в этом

import tkinter as tk
from tkinter import messagebox
import time
import random

root = tk.Tk()
root.title("Timer TrafficLight")
root.geometry("500x500")
# root.resizable(0,0)

canvas = tk.Canvas(root, width= 500, height= 500, bg="darkgray")
canvas.pack(anchor = "s")

class Street(object):

    img_street_vertical = tk.PhotoImage(file="Street_vertical.gif")
    img_street_horizontal = tk.PhotoImage(file="Street_horizontal.gif")

    def __init__(self, x, y, alignment):
        self.x = x
        self.y = y
        self.alignment = alignment
        self.img = self.set_img()
        self.street = canvas.create_image(self.x, self.y, image = self.img, anchor = "nw")

    def set_img(self):
        if self.alignment == "h":
            return self.img_street_horizontal
        elif self.alignment == "v":
            return self.img_street_vertical
        else:
            print ("Please set the alingment to eigher h or v ")

.
.
.


class TrafficLight(object):

    def __init__(self, rx1, ry1, rx2, ry2):
        #Trafficlight outer lines
        self.rx1 = rx1
        self.ry1 = ry1
        self.rx2 = rx2
        self.ry2 = ry2
        self.lines = canvas.create_rectangle(self.rx1, self.ry1, self.rx2, self.ry2)

        #Light Bulbs

        self.top_state = "gray"
        self.middle_state = "gray"
        self.under_state = "gray"
        self.total_state = "gray"
        self.after_id = ""

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = "gray")
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = "gray")
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = "gray")

    def set_off(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "gray"
        self.middle_state = "gray"
        self.under_state = "gray"
        self.total_state = "gray"


        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)


    def set_green(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "gray"
        self.middle_state = "gray"
        self.under_state = "green"
        self.total_state = "green"

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)


    def set_yellow(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "gray"
        self.middle_state = "yellow"
        self.under_state = "gray"
        self.total_state = "yellow"

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)

    def set_red(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "red"
        self.middle_state = "gray"
        self.under_state = "gray"
        self.total_state = "red"

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)

    def timer(self):
        red_timer = 50
        yellow_timer = 40
        green_timer = 50

        if self.total_state == "gray":
            self.set_red()
            self.after_id = canvas.after(red_timer, self.timer)
        elif self.total_state == "red":
            self.set_green()
            self.after_id = canvas.after(green_timer, self.timer)
        elif self.total_state == "yellow":
            self.set_red()
            self.after_id = canvas.after(red_timer, self.timer)
        elif self.total_state ==  "green":
            self.set_yellow()
            self.after_id = canvas.after(yellow_timer, self.timer)
        else:
            messagebox.showerror("Error", "Traffic Light had invalid Value Initialisation only allows Values: gray,red,yellow or green")
            exit()

    def stop_timer(self):
        canvas.after_cancel(self.after_id)

    def walk(self):
        #need to include a "if" in case that state is "red" or "yellow" when the button is pressed.
        self.stop_timer()
        canvas.after(5000, self.set_yellow)
        canvas.after(5000, self.set_red)
        canvas.after(10000, self.timer)


class Car(object):

    spawns = ["left", "right", "top", "buttom"]

    xd = 0
    yd = 0

    def __init__(self):
        self.spawnpoint = random.choice(self.spawns)
        self.spawn_coords = self.spawn()
        self.square = canvas.create_rectangle(self.spawn_coords[0], self.spawn_coords[1], self.spawn_coords[2], self.spawn_coords[3], fill="red", tags = "test")
        self.coords = canvas.coords(self.square)

    def spawn(self):
        if self.spawnpoint == "left":
            return [10,260,40,270]
        elif self.spawnpoint == "right":
            return [485,220,455,230]
        elif self.spawnpoint == "top":
            return [220,10,230,40]
        elif self.spawnpoint == "buttom":
            return [260,485,270,455]
        else:
            print ("invalid spawn Point")
            exit()

    def move(self):
        while True:
            if self.spawnpoint == "left":
                self.xd = 5
                self.yd = 0

                if self.coords[2] + self.xd >= 500:
                    print ("Left reached")
                    return False

            elif self.spawnpoint == "right":
                self.xd = -5
                self.yd = 0

                if self.coords[0] + self.xd <= 0:
                    print ("Right reached")
                    return False

            elif self.spawnpoint == "top":
                self.xd = 0
                self.yd = 5

                if self.coords[3] + self.xd >= 500:
                    print ("top reached")
                    return False

            elif self.spawnpoint == "buttom":
                self.xd = 0
                self.yd = -5

                if self.coords[1] + self.xd <= 0:
                    print ("buttom reached")
                    return False

            else:
                print ("invalid spawn Point")
                exit()

            canvas.move(self.square, self.xd, self.yd)
            self.coords = canvas.coords(self.square)
            root.update()
            # canvas.after(500, self.move)
            time.sleep(.05)

        #X1 = 0
        #X2 = 2
        #y1 = 1
        #y2 = 3






#between x1 and x2 = 30 pixels
#between y and y2 = 65 pixels
l1 = TrafficLight(170, 140, 200, 205)
l2 = TrafficLight(300, 140, 330, 205)
l3 = TrafficLight(170, 295, 200, 360)
l4 = TrafficLight(300, 295, 330, 360)

s1= Street(0, 208, "v")
s2= Street(208, 0, "h")

c1= Car()
c2= Car()
c3= Car()
c4= Car()


m = Menus(root)

while True:
  c1.move()
  c2.move()
  c3.move()
  c4.move()
  time.sleep(.05)

root.mainloop()

1 Ответ

0 голосов
/ 08 сентября 2018

Слишком много кода, который не подключен, и слишком много вопросов для одного поста.

Пожалуйста, избегайте использования time.sleep в графическом интерфейсе и петли while в сочетании с mainloop

Я не знаю, почему вы используете exit(), но он, вероятно, не делает то, что вы хотели.

Избегайте использования root.update, обычно в этом нет необходимости.

Вероятно, у вас должен быть класс TimerControl, независимый от TrafficLights; на самом деле TrafficLights должны быть рабами TimerControl

Вы должны предоставить используемые изображения, чтобы ваш код не становился бременем; Кроме того, ваш код не запускается и нуждается в исправлении, прежде чем мы сможем ответить на ваш вопрос.

Следующие команды видят, как ваши машины едут к противоположному краю, а затем останавливаются:

import tkinter as tk
from tkinter import messagebox
import time
import random

root = tk.Tk()
root.title("Timer Traffic-Light")
root.geometry("500x500")

canvas = tk.Canvas(root, width=500, height=500, bg="darkgray")
canvas.pack(anchor="s")

class Street(object):

    img_street_vertical = tk.PhotoImage(file="Street_vertical.gif")
    img_street_horizontal = tk.PhotoImage(file="Street_horizontal.gif")

    def __init__(self, x, y, alignment):
        self.x = x
        self.y = y
        self.alignment = alignment
        self.img = self.set_img()
        self.street = canvas.create_image(self.x, self.y, image=self.img, anchor="nw")

    def set_img(self):
        if self.alignment == "h":
            return self.img_street_horizontal
        elif self.alignment == "v":
            return self.img_street_vertical
        else:
            print ("Please set the alingment to eigher h or v ")


class TrafficLight(object):

    def __init__(self, rx1, ry1, rx2, ry2):
        #Trafficlight outer lines
        self.rx1 = rx1
        self.ry1 = ry1
        self.rx2 = rx2
        self.ry2 = ry2
        self.lines = canvas.create_rectangle(self.rx1, self.ry1, self.rx2, self.ry2)

        #Light Bulbs

        self.top_state = "gray"
        self.middle_state = "gray"
        self.under_state = "gray"
        self.total_state = "gray"
        self.after_id = ""

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = "gray")
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = "gray")
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = "gray")

    def set_off(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "gray"
        self.middle_state = "gray"
        self.under_state = "gray"
        self.total_state = "gray"


        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)


    def set_green(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "gray"
        self.middle_state = "gray"
        self.under_state = "green"
        self.total_state = "green"

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)


    def set_yellow(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "gray"
        self.middle_state = "yellow"
        self.under_state = "gray"
        self.total_state = "yellow"

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)

    def set_red(self):
        canvas.delete(self.top_bulb)
        canvas.delete(self.middle_bulb)
        canvas.delete(self.under_bulb)

        self.top_state = "red"
        self.middle_state = "gray"
        self.under_state = "gray"
        self.total_state = "red"

        self.top_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 5, self.rx1 + 25, self.ry1 + 20, fill = self.top_state)
        self.middle_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 25, self.rx1 + 25, self.ry1 + 40, fill = self.middle_state)
        self.under_bulb = canvas.create_oval(self.rx1 + 5, self.ry1 + 45, self.rx1 + 25, self.ry1 + 60, fill = self.under_state)

    def timer(self):
        red_timer = 50
        yellow_timer = 40
        green_timer = 50

        if self.total_state == "gray":
            self.set_red()
            self.after_id = canvas.after(red_timer, self.timer)
        elif self.total_state == "red":
            self.set_green()
            self.after_id = canvas.after(green_timer, self.timer)
        elif self.total_state == "yellow":
            self.set_red()
            self.after_id = canvas.after(red_timer, self.timer)
        elif self.total_state ==  "green":
            self.set_yellow()
            self.after_id = canvas.after(yellow_timer, self.timer)
        else:
            messagebox.showerror("Error", "Traffic Light had invalid Value Initialisation only allows Values: gray,red,yellow or green")
            exit()

    def stop_timer(self):
        canvas.after_cancel(self.after_id)

    def walk(self):
        #need to include a "if" in case that state is "red" or "yellow" when the button is pressed.
        self.stop_timer()
        canvas.after(5000, self.set_yellow)
        canvas.after(5000, self.set_red)
        canvas.after(10000, self.timer)
class Car(object):

    spawns = ["left", "right", "top", "buttom"]

    xd = 0
    yd = 0

    def __init__(self):
        self.spawnpoint = random.choice(self.spawns)
        self.spawn_coords = self.spawn()
        self.square = canvas.create_rectangle(self.spawn_coords[0], self.spawn_coords[1], self.spawn_coords[2], self.spawn_coords[3], fill="red", tags = "test")
        self.coords = canvas.coords(self.square)

    def spawn(self):
        if self.spawnpoint == "left":
            return [10,260,40,270]
        elif self.spawnpoint == "right":
            return [485,220,455,230]
        elif self.spawnpoint == "top":
            return [220,10,230,40]
        elif self.spawnpoint == "buttom":
            return [260,485,270,455]
        else:
            print ("invalid spawn Point")
            exit()

    def move(self):
        if self.spawnpoint == "left":
            self.xd = 5
            self.yd = 0 
        if self.coords[2] + self.xd >= 500:
                print ("Left reached")
                return False
        elif self.spawnpoint == "right":
            self.xd = -5
            self.yd = 0
            if self.coords[0] + self.xd <= 0:
                print ("Right reached")
                return False
        elif self.spawnpoint == "top":
            self.xd = 0
            self.yd = 5
            if self.coords[3] + self.xd >= 500:
                print ("top reached")
                return False
        elif self.spawnpoint == "buttom":
            self.xd = 0
            self.yd = -5
            if self.coords[1] + self.xd <= 0:
                print ("buttom reached")
                return False
        else:
            print ("invalid spawn Point")
            root.after_forget(self.move)
        canvas.move(self.square, self.xd, self.yd)
        self.coords = canvas.coords(self.square)
        root.after(100, self.move)


l1 = TrafficLight(170, 140, 200, 205)
l2 = TrafficLight(300, 140, 330, 205)
l3 = TrafficLight(170, 295, 200, 360)
l4 = TrafficLight(300, 295, 330, 360)

s1= Street(0, 208, "v")
s2= Street(208, 0, "h")

c1= Car()
c2= Car()
c3= Car()
c4= Car()


def move_cars():
    for car in [c1, c2, c3, c4]:
        car.move()

move_cars()

root.mainloop()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...