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()



    No comments:

    Post a Comment