Google Analytics

Wednesday, May 7, 2014

Learning Kivy - Part 4


Prev

Table of Contents




  • Learning Kivy - Part 1
  • Learning Kivy - Part 2
  • Learning Kivy - Part 3
  • Learning Kivy - Part 4
  • Learning Kivy - Part 5
  • Learning Kivy - Part 6



    So, what did I learn from Part 3?  I learned that I can instantiate a thread, and have that thread block via a sleep, and not impact the Kivy run method.  

    That's good to know.

    And, that's all I need to know, at this point, about creating a thread for a socket outside of the main thread.

    However, that begs the question: how to get the data from the socket thread to the Kivy thread?

    Well, one way is through Python's global values.  I don't like this approach myself, but let's take a look at it anyway.

    For this example, I'm going to want Kivy to change the displayed GUI text, from
    text: "Hello World from inside simple.kv, via Box_a"
    to something more dynamic, meaning something not static - I want to be able to have the text changed that is being displayed to something originating from the thread.

    Kivy has an ObjectProperty class that allows class attributes to be exchanged between Python code and Kivy Language attributes.  Some additional information on Kivy's Properties.

    This requires a new import statement:
    from kivy.properties import ObjectProperty 

    To recap where we are, and where we're needing to go:

    • Have gotten Threads to work
    • Need to find a way to update the Kivy display
    The kivy.org site has a tutorial called Pong.  I had run this, and played around a little bit a while back.  Today it came to mind when I was trying to find a way to update displayed information.  It occurred to me that Pong has the following elements that have to be updated:
    • The paddles.  The displayed position of these has to be updated as you play the game.
    • The ball.  The displayed position of the ball is constantly changing, and as such, it has to be updated.
    • The score.  This was my main focus: it's a text item.  Checking the code, sure enough, it's a Label.  So it's worth digging deeper into this!
    After studying it, I wanted to reduce it to the bare bones, and then have it display the 'score'.  I didn't want to work through all of the code that is playing a game, no ball nor paddles, just the 'score'.  So I edited the .py code and the .kv code to a minimal point, invoked it, and sure enough - it was updating the score!

    Here's the reduced .py file:
    =====Pong.py====

    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.properties import NumericProperty
    from kivy.clock import Clock


    class Player(Widget):
        score = NumericProperty(0)

    class PongGame(Widget):
        player1 = Player()
        
        def update(self, dt):
            self.player1.score += 1


    class PongApp(App):
        def build(self):
            game = PongGame()
            Clock.schedule_interval(game.update, 1.0/2.0)
            return PongGame()

    def main():
        PongApp().run()

    if __name__ == '__main__':

        main()

    ===============pong.kv===========
    #I've modified this for a test I'm doing on how to dynamically update
    #Label text
    :    
        
        
        Label:
            font_size: 70  
            text: str(root.player1.score)
            

    Saving these to two files in the same directory (that's very important for Kivy), running it, and I've got a numeric display that's counting up at a rate of twice per second.

    That's a demonstration of what I needed (to be able to dynamically update the text of a Label), so now how does it work?

    Here's a breakout of the code elements that are important:
    • class PongApp(App):
      • This extends the App class.  it's the class called within the main() element that starts the program: PongApp().run()
    • def build(self):
      • This is the method that is called by Kivy itself.  You don't see this call, but ultimately it's invoked by your invocation of 'run()'
    • game = PongGame()
      • This creates an instance of PongGame and assigns it to the build method variable game.
    • class PongGame(Widget):
      • This extends the Widget class, and this is important to Kivy, since everything that's displayed is a Widget.
      • It has a class variable: player1, which is of type Player.
      • Note that there is also a <PongGame>: statement in the pong.kv file.  There is a direct association between this class definition of PongGame in the Pong.py file, and the class definition in the pong.kv file.
      • player1 is instantiated as a type Player instance.  In creating this Player instance, note that Player extends Widget, and that it has a class variable of score, which is of type NumericProperty.  This is an important notation, as it will directly affect our ability to dynamically update our Label's text (Label is in the pong.kv file).
    At this point, I'm going to move to Part 5, and go into a little more detail of the NumericProperty object.


    No comments:

    Post a Comment