Обновите несколько овальных координат на холсте в Python с помощью tkinter

Я работаю над графическим интерфейсом для непрерывной анимации подбрасывания монеты по одному. У меня есть два класса cointoss.py и flipbell.py.

Класс Cointoss генерирует изменение стоимости монет, а flipbell используется для анимации процесса.

Как будто теперь у меня есть код, работающий для анимации одной монеты за раз, но не всех монет за раз.

Когда я говорю, что все монеты, это логика: сначала одна монета падает в соответствии с изменением стоимости, затем другая падает, но стоимость первой монеты также обновляется соответствующим образом и так далее.

Мне нужна помощь, как продвигаться вперед в том, что я пробовал до сих пор. Я использовал циклы for для анимации процесса и думал об использовании рекурсивного метода для логической части.

Любая помощь с существующим кодом или идеями по продвижению была бы замечательной.

flipbell.py

from tkinter import Tk, Canvas, Button, W, E
import random
from math import pi, sin, cos
from cointoss import *


class FlipBell(object):
    """
    GUI to simulate cointoss.
    """
    def __init__(self, wdw, dimension, increment, delay):
        """
        Determines the layout of the GUI.
        wdw : top level widget, the main window,
        dimension : determines the size of the canvas,
        increment : step size for a billiard move,
        delay : time between updates of canvas.
        """
        wdw.title('Coin flips and Bell Curve')
        self.dim = dimension # dimension of the canvas
        self.inc = increment
        self.dly = delay
        self.togo = False # state of animation
        # initial coordinates of the ball
        self.xpt = self.dim/2
        self.ypt = 0
        self.cnv = Canvas(wdw, width=self.dim,\
            height=self.dim, bg='white')
        self.cnv.grid(row=0, column=0, columnspan=2)
        self.bt0 = Button(wdw, text='start',\
            command=self.start)
        self.bt0.grid(row=1, column=0, sticky=W+E)
        self.bt1 = Button(wdw, text='stop',\
            command=self.stop)
        self.bt1.grid(row=1, column=1, sticky=W+E)

    def map2table(self, pnt):
        """
        Keeps the ball on the canvas table.
        """
        if pnt < 0:
            (quo, rest) = divmod(-pnt, self.dim)
        else:
            (quo, rest) = divmod(pnt, self.dim)
        return rest

    def placecoin(self, xpt, ypt):
        self.cnv.create_oval(xpt-1, ypt-1, xpt+1, ypt+1,\
            width=2, outline='red', fill='red', tags='coin')

    def drawball(self):
        """
        Draws the ball on the canvas.
        """
        xpt = self.map2table(self.xpt)
        ypt = self.map2table(self.ypt)
        self.cnv.delete('dot')
        self.cnv.create_oval(xpt-1, ypt-1, xpt+1, ypt+1,\
            width=1, outline='black', fill='red', tags='dot')

    def animate(self):
        """
        Performs the animation.
        """
        self.drawball()
        val = []
        for k in range(400):
            val1 = CoinToss.cointoss(3,k,self.dim//2)
            val.append(val1)

        points = {}
        for i in range(1,401):
            points[i] = 0
        for i in range(0,400):
            for j in range(0,400):
                (xpt, ypt) = (self.xpt, self.ypt)
                self.xpt = val[i][1][j]
                # print("x %d",self.xpt)
                self.ypt = ypt + 1
                # print("y %d",self.ypt)
                self.cnv.after(self.dly)
                self.drawball()
                self.cnv.update()

                #Puts the coin on top each other
                if self.ypt == 400:
                    if points[self.xpt]>=1:
                        self.placecoin(val[i][1][-1],400-points[self.xpt])
                    else:
                        self.placecoin(val[i][1][-1],400)
                    points[self.xpt]+=3
                    self.ypt = 0

    def start(self):
        """
        Starts the animation.
        """
        self.togo = True
        self.animate()

    def stop(self):
        """
        Stops the animation.
        """
        self.togo = False

def main():
    """
    Defines the dimensions of the canvas
    and launches the main event loop.
    """
    top = Tk()
    dimension = 400 # dimension of canvas
    increment = 10  # increment for coordinates
    delay = 1      # how much sleep before update
    num_flips = 3
    num_value = dimension//2
    FlipBell(top, dimension, increment, delay)
    top.mainloop()

if __name__ == "__main__":
    main()

cointoss.py

from random import randint
import random


class CoinToss:
    coin = 0
    def __init__(self, value,num_flip):
        # self.id = 1
        self.v = value
        self.state = 1
        self.flip = num_flip
        CoinToss.coin += 1


    def cointoss(self,coin,value):
        print('The ball at the start: ball: %d, state: %d, value: %d' % (coin, self, value))
        value_change = value
        coin_change = []
        for i in range(1,400+1):
            value = value_change
            value_change = CoinToss.flip(value)
            print('after flip %d, ball: %d, state: %d, value: %d' % (i,coin, i, value_change))
            coin_change.append(value_change)
        return([coin,coin_change])


    def flip(self):
        rand_value = randint(0, 1)
        if rand_value == 1:
            self +=1
        else:
            self -=1
        return self

person Abhi    schedule 02.02.2016    source источник


Ответы (1)


Вы назвали и функцию, и переменную в CoinToss, что сбивает с толку. Кроме того, вы используете ключевое слово «теги», и оно должно быть «тег». Есть несколько способов закодировать это. Приведенный ниже код не является полным решением, а представляет собой простой пример, показывающий, как использовать класс CoinToss для создания и перемещения отдельного мяча (не проверяет перемещение за пределы холста). Класс FlipBell сохраняет каждый экземпляр CoinToss в списке и вызывает функцию «перевернуть» для каждого класса каждый раз, когда создается мяч. Вы также можете использовать «после» в классе CoinToss, чтобы функция переворота вызывалась неоднократно.

from tkinter import *
from random import randint

class FlipBell(object):
    """
    GUI to simulate cointoss.
    """
    def __init__(self, wdw, dimension, delay):
        """
        Determines the layout of the GUI.
        wdw : top level widget, the main window,
        dimension : determines the size of the canvas,
        increment : step size for a billiard move,
        delay : time between updates of canvas.
        """
        wdw.title('Coin flips and Bell Curve')
        self.cnv = Canvas(wdw, width=dimension,
                          height=dimension, bg='white')
        self.cnv.grid()

        self.ct_instances=[]
        self.colors=["blue", "red", "yellow", "gray", "green"]
        self.delay=delay
        self.offset=0
        self.create_next()

    def create_next(self):
        """ create one ball for each color in self.colors
            and call each existing ball's flip function to
            move it a random amount
        """
        x=5
        y=5
        incr=10*self.offset
        CT=CoinToss(self.cnv, x+incr, y+incr, self.colors[self.offset])
        ##save each CoinToss (ball) instance in a list
        self.ct_instances.append(CT)
        self.offset += 1

        ## call flip (move ball) for each instance
        for instance in self.ct_instances:
            instance.flip()

        if self.offset < len(self.colors):
            self.cnv.after(self.delay, self.create_next)

class CoinToss:
    def __init__(self, canvas, start_x, start_y, color):
        self.cnv=canvas
        self.cointoss(start_x, start_y, color)


    def cointoss(self, start_x, start_y, color):
        self.this_ball=self.cnv.create_oval(start_x-5, start_y-5, start_x+5, start_y+5,
                       outline='black', fill=color, tag="dot")

    def flip(self):
        """ move the ball created for this class instance by a random amount
        """
        rand_value = randint(10, 50)
        self.cnv.move(self.this_ball, rand_value, rand_value)

if __name__ == "__main__":
    top = Tk()
    dimension = 400 # dimension of canvas
    delay = 500     # how much sleep before update --> 1/2 second
    num_flips = 3
    FP=FlipBell(top, dimension, delay)
    top.mainloop()
person Community    schedule 03.02.2016
comment
Спасибо вам за помощь. Это помогло мне придумать другой способ сделать это. - person Abhi; 03.02.2016