Вызов метода из существующего экземпляра


Мое понимание объектно-ориентированного программирования немного шаткое, поэтому, если у вас есть какие-либо ссылки, которые помогут объяснить концепции, было бы здорово их увидеть!

Я несколько сократил код. Основной принцип заключается в том, что у меня есть игра, которая начинается с экземпляра класса main Controller. При открытии игры открывается всплывающий класс. События происходят следующим образом:

  1. кнопка запуска во всплывающем окне нажата
  2. метод start_click() работает
  3. , который вызывает метод start_game() в экземпляре контроллера
  4. что в свою очередь изменяет состояние игры на 'True' в исходном экземпляре контроллера

Моя проблема связана с шагом 3. Я получаю сообщение об ошибке:

TypeError: unbound method start_game() must be called with Controller 
instance as first argument (got nothing instead)

Я думаю, что должна быть какая-то ссылка на класс контроллера в классе StartPopUp. Но я не совсем понимаю, как создать эту ссылку?

import kivy
kivy.require('1.8.0')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.properties import BooleanProperty, NumericProperty, ObjectProperty
from kivy.uix.popup import Popup
from kivy.lang import Builder

Builder.load_string('''
<StartPopUp>            
    size_hint: .2, .2
    auto_dismiss: False
    title: 'Welcome'
    Button:
        text: 'Play'
        on_press: root.start_click()
        on_press: root.dismiss()

''')

class StartPopUp(Popup):

    def __init__(self, **kw):
        super(StartPopUp, self).__init__(**kw)

    def start_click(self):
        Controller.start_game()                    

class Controller(Widget):
    playing_label = BooleanProperty(False)          #Intitial phase of game is off

    def __init__(self, **kw):
        super(Controller, self).__init__(**kw)        

    def start_popup(self, dt):    
        sp = StartPopUp()
        sp.open()

    def start_game(self):
        self.playing_label = True
        print self.playing_label   

class MoleHuntApp(App):

    def build(self):
        game = Controller()
        Clock.schedule_once(game.start_popup, 1)
        return game

if __name__ == '__main__':
    MoleHuntApp().run() 

Заранее спасибо!

4 2

4 ответа:

Вы можете передать экземпляр следующим образом

class StartPopUp(Popup):

    def __init__(self, controller, **kw):
        super(StartPopUp, self).__init__(**kw)
        self.controller = controller

    def start_click(self):
        self.controller.start_game()

И в контроллере

def start_popup(self, dt):    
    sp = StartPopUp(self)
    sp.open()

Необходимо вызвать start_game() на экземпляре класса Controller. Например,

def start_click(self):
    controller = Controller()
    controller.start_game()

Таким образом, Аргумент startgame() self будет указывать на объект controller. Но затем вам нужно отслеживать созданный экземпляр Controller, чтобы иметь возможность позже изменить его снова. В этом случае нет никакой причины иметь playing_label в качестве статической переменной.

То, что вы, вероятно, хотите иметь, - это статический метод, который можно просто вызвать, не имея экземпляра класса Controller. Для этого вы можете сделать start_game() статическим методом с использованием staticmethod декоратор Вот так:
@staticmethod
def start_game():
    Controller.playing_label = True
    print Controller.playing_label

Затем вы можете продолжить использовать Controller.start_game().

Как видно из сообщения об ошибке, метод start_game() должен быть вызван для конкретного экземпляра класса контроллера. Вы можете добавить метод getInstance() для класса контроллера, который возвращает текущий активный экземпляр контроллера. Вызовите это из Метода start_click() перед вызовом метода start_game(). Скажем, он возвращается instanceC. Тогда вы можете вызвать метод start_game() как instanceC.start_game() из start_click().

Попробуйте передать игровой объект в тот момент, когда вы создаете объект StartPopUp и делаете StartPopUp, чтобы сохранить ссылку на него, поэтому вы можете использовать этот экземпляр позже для метода start_click (), например:

class StartPopUp(Popup):

    def __init__(self, game_ctrl, **kw):
        super(StartPopUp, self).__init__(**kw)
        self.game_ctrl = game_ctrl

    def start_click(self):
        self.game_ctrl.start_game()                    

class Controller(Widget):
    playing_label = BooleanProperty(False)          #Intitial phase of game is off

    def __init__(self, **kw):
        super(Controller, self).__init__(**kw)        

    def start_popup(self, dt):    
        sp = StartPopUp(self)
        sp.open()

    def start_game(self):
        self.playing_label = True
        print self.playing_label