سؤال

Good Afternoon all thanks for any insight....again!

How do I call the def clearwidgets from def changetxt within an instance, if I use self.parent.clearwidgets, I receive anchor layout does not support this, which would be correct, as the ultimate parent instance is named root or GameApp? Which is the parent above the parent. If that make sense.

What I'm trying to achieve is like a screen manager/controller to swap from one layout to another: start menu, main play area, end game, credits etc.

I’ve looked at Kivy source code on Github for the demo game but they just go straight to the play area with no splash screen etc.

I even tried adding root=anchorlayout just under the imports and using global root in the changetxt() but receive the error global none not found.

Again Thanks and Appreciated

import kivy


from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.lang import Builder




class launchScreenMenu(FloatLayout):
    def __init__(self, **kwargs):
        super(launchScreenMenu, self).__init__(**kwargs)

        menuanchor = AnchorLayout(anchor_x='left',anchor_y='bottom')
        menu = StackLayout(orientation='bt-lr',size_hint=(0.5,1))
        about_btn = Button(text='About',size_hint=(0.3,0.1))
        help_btn = Button(text='Settings',size_hint=(0.3,0.1))
        settings_btn = Button(text='Help',size_hint=(0.3,0.1))

        menu.add_widget(about_btn)
        menu.add_widget(help_btn)
        menu.add_widget(settings_btn)
        menuanchor.add_widget(menu)
        return self.add_widget(menuanchor)

class launchScreenBtn(AnchorLayout):
    def __init__(self, **kwargs):
        super(launchScreenBtn, self).__init__(**kwargs)
        play_btn = Button(text="Play")
        self.anchor_x = 'center'
        self.anchor_y = 'center'
        self.size_hint = 0.2,0.2
        self.add_widget(play_btn)
        play_btn.bind(on_press=self.changetxt)


    def changetxt(self,play_btn):
        play_btn.text = 'Game Over'
        clearwidgets()

class GameApp(App):
    def build(self):
        root = AnchorLayout()
        root.add_widget(launchScreenMenu())
        root.add_widget(launchScreenBtn())

        return root

    def clearwidgets(self):
        root.clear_widgets()



if __name__=='__main__':
    GameApp().run()
هل كانت مفيدة؟

المحلول

An essential idea of object-oriented programming (and of programming in general) is that you need to keep references to objects you want to do things with.

For example, in your GameApp.build method, you're creating an AnchorLayout object, assign it to the root local variable, and then add widgets to it through that local variable.

Your question seems to be, "how do I keep issuing commands to that object after the build method has finished running?" I'm noticing an attempt to call root.clear_widgets() in the clearWidgets method, which of course doesn't work because root is a local variable -- it has no existence outside of the method it's used in.

This is where object attributes come in. See, an object is a chunk of state that you can pass around in your program. You can add more state to any object you create. For example, in your launchScreenBtn class's __init__ method, you're setting the anchor_x, anchor_y and size_hint attributes of the instance being created. As long as you have a reference to a launchScreenBtn instance, you can access those attributes (with e.g. my_lsbtn.anchor_x), regardless of whether you're in a function/method.

So what you want to do is make use of that mechanism more. In your GameApp.build method, you don't want to make root a local variable: you want to make it an attribute instead (self.root = AnchorLayout()). That way, in your clearwidgets method, you can access it, calling self.root.clear_widgets().

Apply similar principles through the rest of your application: whenever you have something you'd like to keep manipulating after you've exited the method it's defined in, it's a sign you want to make it an attribute.

While you're at it, you should read a few tutorials on object-oriented programming, because it looks like your grasp of it is shaky. Start with the Python tutorial's section on classes: http://docs.python.org/2/tutorial/classes.html

نصائح أخرى

When you add widgets for and launchScreenBtn() can you modify the class to accept the GameApp instance of self?

class launchScreenBtn(AnchorLayout):
    def __init__(self, mainApp,**kwargs):
        super(launchScreenBtn, self).__init__(**kwargs)
        self.mainApp = mainApp # Local variable to reference parent
        self.play_btn = Button(text="Play")
        self.anchor_x = 'center'
        self.anchor_y = 'center'
        self.size_hint = 0.2,0.2
        self.add_widget(play_btn)
        self.play_btn.bind(on_press=self.changetxt)


    def changetxt(self,play_btn):
        self.play_btn.text = 'Game Over'
        self.mainApp.clearwidgets()

class GameApp(App):
    def build(self):
        self.root = AnchorLayout()
        self.root.add_widget(launchScreenMenu())
        self.root.add_widget(launchScreenBtn(self)) # Add GameApp reference self to Btn Class

        return self.root

    def clearwidgets(self):
        self.root.clear_widgets()

This is usually how I would handle something like this in wxPython, and I believe it should work here as well.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top