Google Analytics

Monday, May 12, 2014

Learning Kivy - Part 6

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



  • After a LOT OF WORK, I was finally able to get some code working that incorporates the following:


    • Thread, with a simulation of a Socket.  This writes to a Queue.
    • Main thread - Kivy GUI thread, that reads from the Queue
    • Queues
    Where I've been having issues is:
    • Getting both threads up and running (Thread for Socket simulation, thread for main Kivy GUI), while not causing either thread to block.  Over the years, I've written a lot of Thread software, yet there still issues.  I still don't know what the problem was.
    • Getting both threads to use the same Queue.  For some brain-fart reason, I was creating two (2) Queues, one in each thread, then was surprised that the data I was pushing into the Queue wasn't available to be read on the other Queue!  Clearly a misunderstanding on my part.  I've used Queues before, and knew how they worked, so I don't even have the excuse of ignorance to justify this - it was just a plain brain-fart.  In the code, I create a global variable that has the Queue, which makes it available for each thread.  I'm not saying that's the best approach, but I wasn't trying to research the best approach for Queues, I was trying to get Kivy going.
    • These were the two (2) main problems.

    Here's the code.  It does the following:
    1. Builds a simple Kivy Language BoxLayout (via my ShowGUI class) via the 'Bulder.load_string' command.
    2. Creates a global variable q and assigns Queue instance to it.
    3. Creates an instance of my SimSocket class.  The class has methods that will create some data, then push it onto the Queue.
    4. Creates a Thread named 'simSocket' that links to the callback SimSocket method "put_on_queue".
    5. Starts the 'simSocket' thread.
    6. Runs Kivy.
    Once running, the following takes place:
    1. On the Terminal, initialization messages, followed by comments that say data is being written to the Queue, and shows the data.
    2. A pop-up GUI appears.
    3. Data is read from the queue.
    4. The GUI updates with the  the data that is being pulled from the queue, at a rate of 1/60 of a second.
    5. It continues to run until you stop it, or it reaches 1 million messages.
    ======Python Code Follows=========

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #
    #  threads_and_kivy.py
    #  
    '''threads_and_kivy.py
    Trying to build up a foundation that satisfies the following:
        - has a thread that will implement code that:
            - simulates reads data from a Python socket
            - works on the data
            - puts the data onto a Python Queue
        - has a Kivy mainthread that:
            - via class ShowGUI
                - reads data from the Queue
                - updates a class variable of type StringProperty so it will
                    update the label_text property.
              
    '''

    from threading import Thread
    from Queue import Queue, Empty
    import time


    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout
    from kivy.properties import StringProperty
    from kivy.lang import Builder
    from kivy.clock import Clock


    kv='''

    :
        Label:
            text: str(root.label_text)
    '''

    Builder.load_string(kv)

    q = Queue()    

            
    class SimSocket():
        global q

        def __init__(self, queue):
            self.q = queue

        def put_on_queue(self):
            print("<----- ..threaded..simsocket.put_on_queue="" entry="" font="">
            for cntr in range(1000000):
                print(".....threaded.....SimSocket.put_on_queue(): Loop " + str(cntr))
                self.some_data = ["SimSocket.put_on_queue(): Data Loop: cntr: " + str(cntr)]
                self.q.put(self.some_data)
            print("..threaded..SimSocket.put_on_queue(): thread ends")

    class ShowGUI(BoxLayout):
        label_text = StringProperty("Initial - not data")
        global q
        
        def __init__(self):
            super(ShowGUI, self).__init__()
            print("ShowGUI.__init__() entry")
            Clock.schedule_interval(self.get_from_queue, 1.0 / 60.0)

        def get_from_queue(self, dt):
            print("---------> ShowGUI.get_from_queue() entry")
            try:
                queue_data = q.get(timeout = 5)
                self.label_text = queue_data[0]
                for qd in queue_data:
                    print("SimKivy.get_from_queue(): got data from queue: " + qd)
            except Empty:
                print("Error - no data received on queue.")
                print("Unschedule Clock's schedule")
                Clock.unschedule(self.get_from_queue)
        
        
    class KivyGui(App):
        def build(self):
            return ShowGUI()
        

    def main():

        global q
        ss = SimSocket(q)
        
        simSocket_thread = Thread(name="simSocket",target=ss.put_on_queue)
        simSocket_thread.start()
        
        
        print("Starting KivyGui().run()")

        KivyGui().run()
        
        
        return 0

    if __name__ == '__main__':

        main()



    BBQ Review - Hickory Pit Bar-B-Queue, Chattanooga, Tennessee

    BBQ Review - Hickory Pit Bar-B-Queue, Chattanooga, Tennessee

    Note: I don't publish any negative reviews at all, so you only see reviews for places I stop at and enjoy.  I don't think it's fair to write a negative review for an establishment that might have had an off day.

    These guys (Mr. and Mrs. Ford) just won Fifth in a Nation-wide award from TripAdvisor!  That's no small feat; per TripAdvisor, their "community of millions of travelers" had decided that this BBQ restaurant is worthy of 5th place in the USA!

    The award was posted Thursday, May 8, 2014.  I learned of it on Friday, May 9, 2014.  I was there eating a big-ol' BBQ Pork sandwich on Saturday, May 10 - the next day!

    My wife and I planned the trip for Saturday, May 10th, 2014, to see relatives in Chattanooga TN that would require us to go right by this restaurant on our way to visit!

    Coming from Atlanta on I-75 N., we took Exit 1B for Ringgold Ave, then headed West for one (1) mile, and located the restaurant on the right side of the highway.

    It's small!  Like 2 tables outside, 4 or 5 tables inside!

    We tried to time our arrival at 11:30, so that hopefully we might avoid the major crush I was expecting.  Well, I was wrong - there was already a major crush, and it just got bigger and longer as we waited....45 minutes to be served, after waiting about 15 minutes to order.

    The staff was doing all they could, but they were overwhelmed.  Everyone was pleasant though, and we didn't hear anyone complain about the wait.

    They were, however, in addition to taking orders from the people that stood in line to place their order at the counter, also taking orders at the drive-up window, as well as orders over the phone.  That meant anyone placing an order via their car or over the phone was jumping to the head of the line and this meant the line was at least 3 times as long as what we saw standing in line. 

    At some point Mrs. Ford realized this wasn't fair to the people that had traveled to eat with them, and stopped taking any further orders over the phone, which continued to ring non-stop!

    There was no where to sit for us, so we took 'take-out', and ate it in our vehicle.  That was a little difficult, because this was a huge BBQ Pork sandwich, heavily laden with sauce!  Careful attention was required, after multiple wraps with napkins, to try and keep it off of our cloths - we both succeeded, which I would have thought would be impossible!

    So - what did we think?

    WE LIKED IT A LOT!

    Worth the wait?  No, but then nothing would have been worth the wait!  The wait will change as the excitement wears thin, or they adjust their staff to the new reality.

    WOULD WE GO BACK!  YES!  After the excitement has died down somewhat.

    This is ONE HUGE BBQ PORK SANDWICH.  Next time, I'll ask for it to be NAKED, so I can better judge the meat, but it's the real-deal!

    Friday, May 9, 2014

    BBQ in the News - Smokin' Ribs

    This is from an article on smoking ribs on a bullet-style smoker that caught my attention, and wanted to share with you.

    Link to complete article at HoddyToddy.com:


    Excerpts from the article:

    Pork Belly Slim’s Method for Mouth-Watering Barbecued Ribs

    POSTED ON 
    This photo, from D'Artagnan (dartagnan.com) shows ribs finished with coffee barbecue sauce.
    This photo, from D’Artagnan (dartagnan.com) shows ribs finished with coffee barbecue sauce (not the method used by Pork Belly Slim, but similar).










    It’s that time of year. The flowers are in bloom, the weather is warm and we’re all excited to get outside after a colder winter than we’ve had in a few years.  For me, and a lot of others, spring means BBQ season is open, and it’s time to dust off the smoker, grab some charcoal and wood for smoke, and start the fire.

    BBQ in the News - Best BBQ Restaurants

    BBQ joints travelers say are best in ratings for TripAdvisor.

    There are more restaurants in the articles, but the following are close to home


    Article From FoxNews reporting on an article from TripAdvisor:



    Wiley’s Championship BBQ, Savannah, Georgia


    TripAdvisor
    With more than 30 years of experience winning awards on the national barbecue competition scene, husband and wife team Wiley and Janet McCrary opened their first brick and mortar restaurant in 2008. The joint pleases palates with low-and-slow cooked meats including savory St. Louis cut ribs.

    Hickory Pit Bar-B-Que, Chattanooga, Tennessee


    TripAdvisor
    Amid the Ridge-and-Valley Appalachian Mountains in southeastern Tennessee, this log cabin style restaurant feeds famished barbecue fans with an emphasis on Southern hospitality. Dry-rubbed meats are smoked over hickory wood, and can be served on a plate, as a sandwich, or even stuffed inside a “killer” baked potato.

    Jim’s Smokin’ Que, Blairsville, Georgia


    TripAdvisor
    Open Thursday through Saturday, this northern Georgia smokehouse advises guest to arrive early, as their succulent meats – including ribs, brisket, pulled pork, chicken and turkey – often sell out. Those lucky enough to score a meal can also enjoy their choice of satisfying sides, from Brunswick stew to banana pudding.

    Joe’s BBQ, Blue Ridge, Georgia


    TripAdvisor
    In the midst of the Blue Ridge Mountains, this joint satisfies hungry guests with tender and moist meats complemented by a selection of sauces including “Alabama white,” a mayonnaise-based mixture that has found fame in several Southeastern states.

    Thursday, May 8, 2014

    Learning Kivy - Part 5


    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




  • This is a continuation of Learning Kivy - Part 4

    As noted in Part 4 for Pong.py and pong.kv, we've come across an important type in the Player class, of NumericProperty, the instance of which is assigned to player1 class variable.

    With respect to this program, it is an important part of being able to dynamically update the Label's text with the changing score.

    Looking at kivy.org site to get some insight into the NumericProperty, I noticed the following:

    Theses properties implement the Observer pattern. They help you to:
    • Easily manipulate widgets defined in the Kv language
    • Automatically observe any changes and dispatch functions/code accordingly
    • Check and validate values
    • Optimize memory management

    I know from previous experience what an Observer pattern is, but in essence, it allows one part of code to inform other interested parts of code that something has changed - the change is an event, and those parties that have registered their interest through a callback function, are informed of this change.  Here's a more detailed explanation from Wikipedia: Observer Pattern

    It appears that, by setting the class PongGame's attribute player1 to an instance Player, and Player is of type Widget, and Player has an attribute of score which is of type NumericProperty, we are making use of the Observer Pattern via the NumericProperty, which will(from kivy.org) "...automatically observe any changes and dispatch functions/code accordingly".  So that appears to be the magic that let's us change.

    In other words, I'm thinking it means: when we update the 'score' attribute, since it's of type NumericProperty, then it gets updated in the pong.kv class Label text, because Label text is set to "str(root.player1.score)".  Thus the new value is displayed.

    Recommended additional info
    Here's a good question/answer thread on Kivy NumericProperty.  Here's a clip from it.


    [Alexandar Taylor]: Properties hook into kivy's event system to reference each other in automatically updated ways, dispatch events when changed etc. In comparison, a normal python class level property...doesn't. Kivy properties also take care of class uniqueness, whereas class attributes are shared by all class instances which can cause you unexpected problems if they're mutable.

    For the ReferenceListProperty, this creates a property that looks like a list, but whose elements when accessed or changed automatically reference or change the component velocity_x or velocity_y. In comparison, your example of just using a tuple does none of that - if you access velocity[0] you'll probably not even get a number but instead the NumericProperty object you defined it to point at. In contrast, the ReferenceListProperty acesses and returns the velocity_x property.

    Same goes for the NumericProperty. You could create class level python attributes if you wanted (or, more usefullly, standard instance attributes created in __init__), but then you can't bind to their changes etc. with kivy's event system. Learning more about kivy will make it clear how it ties together, you generally always will be thinking in terms of properties affecting each other via the bindings that kivy properties allow.
    The guy that wrote the above, Alexander Taylor, also has a series of youtube casts.  Here's one dealing with this issue.

    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.


    Learning Kivy - Part 3

    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



  • This part is going to work through some of the issues of working with a Kivy GUI while communicating with networked resources.  Dusty's articles have a lot of insight on obtaining weather information from a URL, but this isn't what I'm doing.  I'm having to communicate with Python sockets.  So, this part is going to work through some of the issues I'm encountering, using just simple screens to work with so the 'Learning' part of this isn't overwhelming!

    For the Home Security/Automation project I'm working on, I have a distributed design: 
    • The Sensor portion is running on a Beaglebone Black (BBB), which is connected to all of the wired sensors, and to the local network.
    • The Controller portion, is running on one of the computers here, which is also connected to the local network.
    • The GUI portion, will be running on many of the computers here, which are also connected to the local network.
    • Future - GUI external to the local network.
    Here's a text diagram:


    Sensor     <========>Controller<=======>GUI
    On BBB                         computer                    computer

    • The Sensor sends/receives messages with the Controller.
    • The GUI sends/receives messages with the Controller.
    • The Sensor detects, and sends info to the Controller.  It also responds to the Controller on queries from the Controller.
    • The GUI displays as directed by the Controller.  It also responds to the Controller on queries from the Controller.
    • The Controller is directing everything; it has all of the program logic in it.
    Since these processes are running on different computers, they are talking via the local network, which means using Python Sockets.

    I've struggled with implementing the GUI and having it communicate with the Controller.

    Here's what I'm currently (subject to change!) understanding about communications between the Controller and the GUI:
    1. The GUI code needs to be in a thread.  Per some insight from web pages I've come across, this needs to be the main thread.  I'm taking this to mean not in a thread I'm creating via a Thread call.
    2. The Socket code needs to be in a separate thread.
    3. Once I make a call to the run method of the class that extends App (e.g., in the previous examples, the Simple(App) class), the GUI doesn't return until after the GUI window is closed.
    I'm going to write a small test, based on our Simple.py and simple.kv classes, that will test item 3.

    The code for simple.kv stays the same (see previous articles if you need the listing).

    The code for Simple.py follows:

    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout

    class Box_a(BoxLayout):    
        print("Box_a entry")
    class Simple(App):
        def build(self):
            print("inside build")        
            return  Box_a()            

    def main():    
        print("===========BEFORE CALL TO SIMPLE.RUN=======")    
        b = Simple()    
        b.run()

        print("===========AFTER CALL TO SIMPLE.RUN=======")        
        return 0

    if __name__ == '__main_':
        main()


    The output from running this shows a black GUI with the words "Hello World from inside simple.kv, via Box_a".  The terminal shows the text printed
    "Box_a entry", "===BEFORE CALL TO SIMPLE.RUN===", and "inside build".

    It does not have "===AFTER CALL TO SIMPLE.RUN===", which means the GUI is still inside the b.run() invocation of the Simple object.

    So any ability to communicate with a Python Socket has either got to come before the call to Simple.run(), or somehow within Simple.run().

    Since this is the GUI, it's going to mainly be concerned with receiving network messages from the Controller via Python Sockets.

    After a Socket is bound for receiving messages within the GUI, it blocks on a call to receive a message.  This means, if I were to put the part of the code that reads the Python socket prior to the Kivy App run method (Simple.run()), then the code will never get to the Simple.run() method, because it is blocking on the Socket receive method.  And, I can't put the Socket receive code after the Simple.run() because it never returns either.

    The typical approach to avoiding Socket blocking is to put this portion of the code into a thread.  This means the part of the code that reads the socket has to be put into a thread prior to the call to Simple.run().

    I want to see if a thread can be called before the Simple.run() is invoked.

    So, I'm going to create a class that has a method that will:

    • be invoked via a Thread call back.
    • this method will sleep for a time long enough for the GUI to come up
    • Do a print method to see if it shows up in the terminal before the GUI is exited.
    Note a couple of things about the new code:

    • It has a new class ThreadedClass, which has a callable method delayed_print, which has a sleep for 5 seconds call in it before printing out a statement.
    • It makes use of a Thread, which invokes the ThreadedClass callback delayed_print
    • It starts the Thread via the Thread.start() method, which causes the callback method to be executed within the thread.
    • It has two new import statements, in order to support Thread and sleep.
    • It makes print statements that show up, in time-sequence, to the terminal.  Because the thread callback method delayed_print has a sleep(5) seconds, the printout from this method will be behind everything else
    • Remember to give enough time for the sleep to finish before you shutdown the program!!!

    So here's the new code for Simple.py:


    import time
    from threading import Thread
    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout


    class Box_a(BoxLayout):
        print("Box_a entry")
        

    class Simple(App):
            
        def build(self):
            print("inside build")
            return  Box_a()

    class ThreadedClass():
        def delayed_print(self):
            print("===inside delayed_print=====")
            time.sleep(5)
            print("==========time.sleep has elapsed======")        
        
    def main():
        
        print("===========BEFORE CALL TO THREADEDCLASS=======")
        tc = ThreadedClass()
        threadRef = Thread(name="ThreadedClassName",target=tc.delayed_print)
        threadRef.start()
        print("===========AFTER CALL TO THREADEDCLASS=======")
        
        print("===========BEFORE CALL TO SIMPLE.RUN=======")
        b = Simple()
        b.run()

        print("===========AFTER CALL TO SIMPLE.RUN=======")
        
        return 0

    if __name__ == '__main__':

        main()


    Here's the output from my terminal from my run, after giving the sleep statement time to execute:

    [INFO   ] Kivy v1.7.2
    [INFO   ] [Logger      ] Record log in /home/superben/.kivy/logs/kivy_14-05-07_71.txt
    [INFO   ] [Factory     ] 144 symbols loaded
    [DEBUG  ] [Cache       ] register with limit=None, timeout=Nones
    [DEBUG  ] [Cache       ] register with limit=None, timeout=60s
    [DEBUG  ] [Cache       ] register with limit=None, timeout=Nones
    [INFO   ] [Image       ] Providers: img_tex, img_dds, img_pygame, img_pil, img_gif 
    [DEBUG  ] [Cache       ] register with limit=1000, timeout=60s
    [DEBUG  ] [Cache       ] register with limit=1000, timeout=3600s
    Box_a entry
    ===========BEFORE CALL TO THREADEDCLASS=======
    ===inside delayed_print=====
     ===========AFTER CALL TO THREADEDCLASS=======
    ===========BEFORE CALL TO SIMPLE.RUN=======
    [DEBUG  ] [App         ] Loading kv <./simple.kv>
    inside build
    [DEBUG  ] [Window      ] Ignored (import error)
    [INFO   ] [Window      ] Provider: pygame(['window_egl_rpi'] ignored)
    [DEBUG  ] [Window      ] Display driver x11
    [DEBUG  ] [Window      ] Actual window size: 800x600
    [DEBUG  ] [Window      ] Actual color bits r8 g8 b8 a0
    [DEBUG  ] [Window      ] Actual depth bits: 24
    [DEBUG  ] [Window      ] Actual stencil bits: 8
    [DEBUG  ] [Window      ] Actual multisampling samples: 2
    [INFO   ] [GL          ] OpenGL version <4 .4.0="" 331.20="" nvidia="">
    [INFO   ] [GL          ] OpenGL vendor
    [INFO   ] [GL          ] OpenGL renderer
    [INFO   ] [GL          ] OpenGL parsed version: 4, 4
    [INFO   ] [GL          ] Shading version <4 .40="" cg="" compiler="" nvidia="" via="">
    [INFO   ] [GL          ] Texture max size <16384>
    [INFO   ] [GL          ] Texture max units <32>
    [DEBUG  ] [Shader      ] Fragment compiled successfully
    [DEBUG  ] [Shader      ] Vertex compiled successfully
    [DEBUG  ] [ImagePygame ] Load
    [INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
    [INFO   ] [Text        ] Provider: pygame
    [INFO   ] [OSC         ] using for socket
    [DEBUG  ] [Base        ] Create provider from mouse
    [DEBUG  ] [Base        ] Create provider from probesysfs
    [DEBUG  ] [ProbeSysfs  ] using probsysfs!
    [INFO   ] [Base        ] Start application main loop
    [INFO   ] [GL          ] NPOT texture support is available
    ==========time.sleep has elapsed======





    Learning Kivy - Part 2

    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



    In our previous lesson, the Simple class extends App.  When the Simple.run() method is invoked, it will build the actual GUI screen.  But as you saw, at this point, that's an empty screen.

    The build method for Simple returned an instance of the Box_a class, which extended BoxLayout.

    If we put this Box_a class into the Kivy Language file simple.kv correctly, then we will have a GUI element, or widget, displayed.

    So, let's build the simple.kv file.  (Note: most articles I've seen have you instantiate a root window, but I'm not taking that approach.  See Dusty's articles for more insight on this topic.)


    I'm going to add two class definitions; Box_a and Simple.  These are coded in Kivy Language as:
    <Box_a>:
    <Simple>:

    I'm putting two class definitions into this Kivy Language file, but with the current .py code, only the Box_a  will cause anything to be displayed; I'm putting the Simple class here to show that it doesn't get invoked.  Also, notice the indenting - it's the same required as Python; Kivy, afterall, is a GUI for Python.

    So, here's the complete simple.kv file:
    <Box_a>:
        Label:
            text: "Hello World from inside simple.kv, via Box_a"

    <Simple>:
        Label:
            text: "Hello World from inside simple.kv, via Simple"



    If we now run our Simple.py file, we will see a GUI with the contents of "Hello World from inside simple.kv, via Box_a"

    If you look at the output from the terminal window, you will still see the printouts "Box_a entry" and "inside build" text.

    Part of what I'm doing is learning the Kivy language.  And for me, that also means learning what it isn't; so I tend to play around with things to see what breaks.  The following is an example of what breaks, and why I tried it.

    Changing Simple.py, the class method for build to return a reference to Simple.self instead of an instance of 'Box_a', causes the program to terminate.

    If you want to try this, in build, change the line
        return Box_a()
    to
        return self

    It causes the GUI to flash onto and off the screen, and an error message:
    Attribute Error: 'Simple' ojbect has no attribute 'canvas'.

    I think my problem is with the fact that Simple extends App, instead of a Widget.

    So, you .run() the App class, but return a root widget.

    So, remove the useless <Simple>: class definition from the .kv file, as it won't ever be called!

    Learning Kivy - Part 1

    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

  • Kivy provides a GUI interface.  It provides Python programmers with a method to present a Graphical User Interface.  More at kivy.org

    I'm learning Kivy, and frankly, am struggling with it.  While I have an extensive programming background, almost none of that experience is associated with GUI programming.  Kivy, being new, has very doesn't have as much documentation available for it as does other GUI tools, such as TkInter.  So I thought, if I was struggling, my movement through the learning process might be of interest to others....so here we are!  (BTW - here's a link to an excellent series of articles by Dusty Phillips.  Dusty also has a book out on Kivy, which I've found very useful, but a little more advanced than where I'm at today, thus my need to experiment.)

    Dusty's site has a good approach, where he places a 'Table of Contents' with links on each page.  I'm going to duplicate that approach, as one of the issues with having a blog is it isn't very easy to pull articles together to make a coherent package...this will help.

    In the early parts, I'm going to be treating really basic stuff.  However, I'm not going to be treating setup, installation and running of Kivy nor Python.  Dusty's site, and kivy.org, should be consulted.

    Kivy typically has two components: a Python program portion, with a file extension of .py, and a Kivy Language portion, with a file extension of .kv

    Suggested approaches are to put the programming logic into the Python portion, and the Kivy Language portion in the Kivy .kv file.

    While it's possible to just do everything from Python, and not have a Kivy Language .kv file, I'm not going to take that approach - I'll be developing correlated .py and .kv files for each project.

    Simple Insight for this page:
    • There must be a Python class in the .py file that extends App.  This means App must be previously defined, and it is; it's in kivy.app.  To get this into the Python page, it must be imported, via this command:
      • from kivy.app import App
    • The example class I'm going to build is Simple.  So the Python statement for the class is:
      • class Simple(App):
    • This Simple class must define a method, build.  Here's the build method:
      • def build(self):
    Together, so far, we have:

    class Simple(App):
        def build(self):


    Per Kivy, the build method has to return something - an instance of the class that's being created in the .kv file.  So, even though I haven't yet created the .kv file, I'm going to have the build method return an instance of Box_a.  I'm doing things a little bit differently than you might find in other examples, but I'm doing this because I wanted to point out some differences.  Most articles aimed at learning Kivy will have you using the Simple class for everything, but here I'm not - I'm using the Simple.py, the simple.kv, but a Box_a class.

    If you know Python, you also know that the Box_a instance must be a class, and therefore this class must be defined.  So the next code snippet will have the Box_a class defined, and instantiated and returned in the build method.

    The snippet will also include a main method to invoke everything (you should be familiar with this from common Python programming).  Within this main method, it will create an instance of the Simple class placed into s, and then run it via a call to s.run().

    I'm also going to put a couple of print statements into the code, so you can see (when you execute your program) where these calls are made, because you don't actually call the Simple.build() method anywhere!  Kivy does that.

    Note one more thing: class Box_a is going to extend BoxLayout which means we've got to import it too.

    So here's a complete listing, including the required import statements:

    from kivy.app import App
    from kivy.uix.boxlayout import BoxLayout

    class Box_a(BoxLayout):
        print("Box_a entry")

    class Simple(App):
        def build(self):
            print("inside build")
            return Box_a()

    def main():
        s = Simple()
        s.run()

    if __name__ == '__main__':
        main()

    When you run this Python program, you should get a terminal window (aka console window) with information from Kivy, then a blank popup window.   If you look at the terminal window carefully, you should see something similar to this (be sure and look for the 'Box_a entry' and 'inside build' printouts within that output - I've highlighted below, but your system won't do this):

    [INFO   ] Kivy v1.7.2
    [INFO   ] [Logger      ] Record log in /home/superben/.kivy/logs/kivy_14-05-07_56.txt
    [INFO   ] [Factory     ] 144 symbols loaded
    [DEBUG  ] [Cache       ] register with limit=None, timeout=Nones
    [DEBUG  ] [Cache       ] register with limit=None, timeout=60s
    [DEBUG  ] [Cache       ] register with limit=None, timeout=Nones
    [INFO   ] [Image       ] Providers: img_tex, img_dds, img_pygame, img_pil, img_gif 
    [DEBUG  ] [Cache       ] register with limit=1000, timeout=60s
    [DEBUG  ] [Cache       ] register with limit=1000, timeout=3600s
    Box_a entry
    [DEBUG  ] [App         ] Loading kv <./simple.kv>
    inside build
    [DEBUG  ] [Window      ] Ignored (import error)
    [INFO   ] [Window      ] Provider: pygame(['window_egl_rpi'] ignored)
    [DEBUG  ] [Window      ] Display driver x11
    [DEBUG  ] [Window      ] Actual window size: 800x600
    [DEBUG  ] [Window      ] Actual color bits r8 g8 b8 a0
    [DEBUG  ] [Window      ] Actual depth bits: 24
    [DEBUG  ] [Window      ] Actual stencil bits: 8
    [DEBUG  ] [Window      ] Actual multisampling samples: 2
    [INFO   ] [GL          ] OpenGL version <4 .4.0="" 331.20="" nvidia="">
    [INFO   ] [GL          ] OpenGL vendor
    [INFO   ] [GL          ] OpenGL renderer
    [INFO   ] [GL          ] OpenGL parsed version: 4, 4
    [INFO   ] [GL          ] Shading version <4 .40="" cg="" compiler="" nvidia="" via="">
    [INFO   ] [GL          ] Texture max size <16384>
    [INFO   ] [GL          ] Texture max units <32>
    [DEBUG  ] [Shader      ] Fragment compiled successfully
    [DEBUG  ] [Shader      ] Vertex compiled successfully
    [DEBUG  ] [ImagePygame ] Load
    [INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
    [INFO   ] [OSC         ] using for socket
    [DEBUG  ] [Base        ] Create provider from mouse
    [DEBUG  ] [Base        ] Create provider from probesysfs
    [DEBUG  ] [ProbeSysfs  ] using probsysfs!
    [INFO   ] [Base        ] Start application main loop

    But a blank GUI window (notice it's entitled 'Simple' at the top) doesn't do much, does it?

    This is where the Kivy Language file (simple.kv) comes into play.

    Create a file, in the same directory as your Simple.py file (this is important!), and name it simple.kv (the lower case is important too - if not, it won't be found).  The name of this file simple.kv must be named after your class that inherits the App class - you can have a different name for your Python class (e.g., Simpleton) than the class name that extends App, but whatever you have, the .kv file must be named from that class, not the Python file name.

    Because we have a class definition:

    class Simple(App):

    Then the Kivy Language .kv file must be named simple.kv

    If instead, our class that extends App were to be named

    class SimpleA(App):

    Then the Kivy Language .kv file must be named simplea.kv  Notice even the later capitalized 'A' must be changed to 'a'.

    Kivy does make one recommendation, and that is that you name your App extending class to be ended with App, such as SimpleApp, in which case Kivy will strip off the App portion, and only look for simple.kv - the choice is yours.

    Part 2 will move forward from this point, and implement a simple.kv file.