Передача холста tkinter между классами без вызова дочернего элемента из родительского класса. - PullRequest
1 голос
/ 30 апреля 2020

Я немного новичок, когда дело доходит до Python, но я решил, что хочу написать основную c 2-ью детскую физическую площадку. Неожиданно я столкнулся с проблемой при попытке настроить структуру basi c.

Мой план состоит в том, чтобы создать GUI с холстом в родительской функции с именем mainWindow, затем я решил создать дочерний класс (Hero), который создает круг, которым пользователь может манипулировать на холсте. Кажется, это работает довольно хорошо.

Проблема возникает, когда я пытаюсь что-то сделать с классом Hero, например, вызвать функцию для удаления круга, чтобы я мог перерисовать его в каком-то направлении. Я не могу передать холст из главного окна в класс Hero. Буду очень признателен за любую помощь, в том числе и за то, что скажу, что это неправильный способ сделать что-либо.

Я добавляю два документа, с которыми я работаю, так как за моим болтовней, вероятно, трудно следить.

I запустите программу из документа phesics.py, в результате появится GUI с моим холстом и красным кружком. Когда я закрываю окно, я получаю следующую ошибку:

classes.py ", строка 29, в moveHeroBody canvas.delete (heroBody) NameError: имя 'canvas' не определено

Unfortionetly i не знаю, как донести «мир» до ребенка

classes.py

from tkinter import *


class mainWindow():
    def __init__(self):
            #Setup the GUI
            root = Tk()
            root.geometry('800x600')
            # Setup the canvas within the GUI (master)
            world = Canvas(root, height = 600, width = 800, bg = "#FFFFFF")
            world.place(relx = 0.5, rely = 0.5, anchor = CENTER)

            Hero(world)

            root.mainloop()

class Hero(mainWindow):
    def __init__(self,world):
        #Initial creation of hero at coordinates
        x1 = 10
        y1 = 10
        x2 = 70
        y2 = 70
        heroBody = world.create_oval(x1,y1,x2,y2, fill = "#FF0000", outline = "#FF0000")

    #Move the hero
    def moveHeroBody():
        print("moveHeroBody")
        world.delete(heroBody)

phesics.py

from tkinter import *
from classes import *

mainWindow1 = mainWindow()
moveHero = Hero.moveHeroBody()

Ответы [ 2 ]

2 голосов
/ 30 апреля 2020

Вы проходите это нормально, но вы отбрасываете значение. Кроме того, Hero не должно наследоваться от mainWindow.

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

class Hero():
    def __init__(self,world):
        self.world = world
        ...

Затем вы можете использовать self.world для ссылки на холст:

def moveHeroBody():
    print("moveHeroBody")
    self.world.delete(heroBody)

Хотя приведенный выше код завершится ошибкой, поскольку heroBody является локальной переменной для __init__ - вам нужно сделать то же самое с ним:

class Hero():
    def __init__(self,world):
        self.world = world
        ...
        self.heroBody = world.create_oval(...)

    #Move the hero
    def moveHeroBody():
        print("moveHeroBody")
        self.world.delete(self.heroBody)
1 голос
/ 30 апреля 2020

Я думаю, вам нужно инициализировать класс Hero в вашем классе mainWindow. Изменения, которые необходимо выполнить в коде:

classes.py

from tkinter import *
from time import sleep


class mainWindow():
    def __init__(self):
            #Setup the GUI
            self.jump_gap = 25
            root = Tk()
            root.geometry('800x600')
            # Setup the canvas within the GUI (master)
            self.world = Canvas(root, height = 600, width = 800, bg = "#FFFFFF")
            self.world.place(relx = 0.5, rely = 0.5, anchor = CENTER)

            self.hero = Hero(self.world)
            self.world.pack()
            root.bind("<space>",self.jump) # -> [1] Binds the SPACE BAR Key to the function jump 
            root.mainloop()

    def jump(self,event):
        gaps = list(range(self.jump_gap))
        for i in gaps:
            self.world.after(1,self.hero.moveHeroJump(h=i))  # [2] -> Binds the moveHeroJump method with the window action to a queue of updates
            self.world.update() #[2] updates the canvas
            sleep(0.01*i) # Added some linear wait time to add some look to it
        gaps.reverse()
        for i in gaps:
            self.world.after(1,self.hero.moveHeroJump(h=-i))
            self.world.update()
            sleep(0.01*i)


class Hero():
    def __init__(self,world):
        #Initial creation of hero at coordinates
        self.world = world
        self.x1 = 10
        self.y1 = 410
        self.x2 = 70
        self.y2 = 470
        self.heroBody = self.world.create_oval(self.x1,self.y1,self.x2,self.y2, fill = "#FF0000", outline = "#FF0000")

    #Move the hero
    def moveHeroJump(self,h):
        print("moveHeroBody")
        self.y1 -= h
        self.y2 -= h
        self.world.delete(self.heroBody)
        self.heroBody = self.world.create_oval(self.x1,self.y1,self.x2,self.y2, fill = "#FF0000", outline = "#FF0000")

Physics.py

from tkinter import *
from classes import *

mainWindow1 = mainWindow()

Пожалуйста, дайте мне знать, если это сработало! : D

Редактировать

Так что это заставило меня сыграть несколько минут go, и я исследовал некоторые источники из стека, чтобы завершить этот вопрос. Вот источники (также упоминаемые в коде):

  1. Как привязать клавишу пробела к определенному методу в tkinter python
  2. Moving Tkinter Canvas

Решение, отредактированное выше, способно выполнить простую анимацию прыжка мяча. self.jump_gap - фиксированная величина, которая сообщает мячу, сколько ему нужно, чтобы прыгнуть. jump анализирует определенную высоту h для метода moveHeroJump, чтобы заставить шар изменить свою позицию, после того как изменение позиции поставлено в очередь в Canvas, вызывается обновление, чтобы увидеть изменения в шаре.

Пожалуйста, дайте мне знать, если это помогло, мне было очень весело играть с этим!

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