2014-05-09 15 views
5

Sono nuovo di zecca per Kivy, e anche nuovo per la GUI, ma non nuovo per la programmazione.Kivy - thread, code, orologi e prese Python

Mi manca completamente la barca, la canoa e l'aereo usando Kivy.

In 30 anni di programmazione, da codice macchina, assembly, Fortran, C, C++, Java, Python, non ho mai provato a utilizzare un linguaggio come Kivy la cui documentazione è così sottile, perché è così nuova. So che andrà meglio, ma sto cercando di usarlo ora.

Nel mio codice, sto cercando di implementare l'accodamento, in modo da poter ottenere i dati del socket Python. Nella normale programmazione di Python, avrei IPC tramite una coda: inserire i dati, ottenere i dati.

Ho capito da Kivy, per lo più da quello che ho letto in vari forum, ma non posso dire che ho trovato nella documentazione in kivy.org, che non posso effettuare le seguenti operazioni:

  • Kivy deve essere nella sua stessa discussione.
  • Nulla in Kivy dovrebbe dormire.
  • Nulla in Kivy dovrebbe bloccare l'IO.

Dopo un sacco di ricerche Google, l'unica cosa che ho trovato che si avvicina di essere utile, è un informative note here on StackOverFlow. Tuttavia, mentre risolve quasi il mio problema, la risposta presuppone che conosco più cose su Kivy di me; Non so come incorporare la risposta.

Se qualcuno potesse dedicare del tempo a mettere insieme una breve demo COMPLETA di utilizzo di quell'esempio, o una delle vostre uniche risposte COMPLETE, lo apprezzerei molto!

Ecco un codice breve che ho messo insieme, ma non funziona, perché blocca sulla chiamata get().

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

class ClockedQueue(BoxLayout): 
    text1 = StringProperty("Start") 

    def __init__(self): 
     super(ClockedQueue,self).__init__() 
     self.q = Queue() 
     self.i=0 
     Clock.schedule_interval(self.get, 2) 

    def get(self,dt): 
     print("get entry") 

     val = self.q.get() 
     print(self.i + val) 
     self.i += 1 

class ClockedQueueApp(App): 

    def build(self): 
     return ClockedQueue() 

class SourceQueue(Queue): 
    def __init__(self): 
     q = Queue() 
     for word in ['First','Second']: 
      q.put(word) 
     print("SourceQueue finished.") 

def main(): 

    th = Thread(target=SourceQueue) 
    th.start() 

    ClockedQueueApp().run() 
    return 0 

if __name__ == '__main__': 


    main() 

Grazie!

+0

Non stai avendo un problema con Kivy qui, hai un problema con tutto il resto nel tuo codice. 'SourceQueue' non fa nulla, in quanto crea solo una variabile locale temporanea. Inoltre, non fa mai riferimento a nient'altro nel tuo codice. Non ha bisogno di essere in una discussione, e sicuramente non dovrebbe essere il 'target' di una discussione. Per quanto riguarda il blocco di 'get', è semplice come usare 'get_nowait' e prendere' Queue.Empty'. –

risposta

4

Ecco un codice breve che ho messo insieme, ma non funziona, perché blocca sulla chiamata get().

Quindi quello che vuoi veramente è ottenere gli articoli dalla tua coda in modo non bloccante?

Ci sono molti modi per farlo. Il più semplice sembra essere quello di controllare se la coda ha qualche elemento prima di averne uno - Queue ha diversi metodi che aiutano, incluso controllare se è vuoto o impostare se get può bloccare (impostando il suo primo argomento su False). Se lo fai, invece di chiamare lo get da solo, non blocchi le cose in attesa che la coda abbia qualche elemento - se è vuoto o non puoi immediatamente fare get, non fai nulla.

Non so cosa si vuole fare con gli elementi che si ottengono dalla coda, ma se si tratta di operazioni brevi che non richiedono molto tempo, non sarà necessario altro. Ad esempio, è possibile eseguire il Clock.schedule_interval metodo get per ogni frame, non fare nulla se la coda è vuota o operare sui dati se si ottiene qualcosa indietro. Nessun blocco e nessun problema con i tuoi thread.

È possibile anche creare il tuo proprio thread ed eseguire il codice di blocco in esso, che è il modo generale per trattare problemi di blocco, in particolare compiti che non possono essere suddivisi in sezioni brevi che possono essere eseguite tra i fotogrammi. Non conosco i dettagli di questo, ma dovrebbe semplicemente coinvolgere normalmente i thread python. Puoi controllare la fonte di Kivy's UrlRequest per un esempio, questo può scaricare una fonte web in un thread in background.

Edit: Anche la tua SourceQueue è incasinato (si ignora la sua __init__ per fare una nuova coda che non archiviare ovunque), e la vostra programmazione orologio ha un insignificante terzo argomento false che non è nemmeno definito. Non so cosa sta succedendo qui, probabilmente influisce su quello che stai cercando di fare, ma non ha importanza per la mia risposta generale sopra.

+0

Grazie inclemente, ma come ho detto, sto cercando un esempio di come fare questo o implementare il link StackOverflow che ho postato. Ma grazie per la tua considerazione nel rispondere. Grazie per la presa sul 'falso'; Proverò a modificarlo. – user3621831

+0

Quello che alla fine vorrei fare è: 1) avere un thread in esecuzione che può interfacciarsi con un socket. Ho già un sacco di codice in quell'arena che deve essere in esecuzione. 2) che il thread in esecuzione ottiene i dati dal socket, funziona, quindi trasferisce i risultati su una coda che può essere letta da Kivy. 3) Kivy legge la coda di input, aggiorna la GUI. Grazie ancora per la tua domanda. – user3621831

+0

Quello che ho detto sopra copre la struttura di base di ciò che è necessario per la parte kivy - qualcosa come 'Clock.schedule_interval' una funzione che controlla la coda e agisce su di essa se ha delle voci. Però non ne so molto dei thread, quindi temo di non poter aiutare lì. Dovrebbe essere indipendente dalla stessa kivy, quindi puoi seguire direttamente la domanda su come eseguire il codice in una discussione - in questo caso, leggendo da un socket e spingendo fino alla tua coda. – inclement

3

Sono finalmente riuscito a creare qualcosa che funzionasse.

Grazie a tutti per i vostri suggerimenti!

Ecco il codice (perché io sono nuovo, StackOverflow non mi permetteva di postare come rispondere alla mia domanda fino a 5:00)

#!/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=''' 

<ShowGUI>: 
    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") 
     for i in range(10): 
      print(".....threaded.....SimSocket.put_on_queue(): Loop " + str(i)) 
      time.sleep(1)#just here to sim occassional data send 
      self.some_data = ["SimSocket.put_on_queue(): Data Loop " + str(i)] 
      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) 

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

inoltre, puoi dare un'occhiata a http://kivy.org/docs/guide/other-frameworks.html#using-twisted-inside-kivy per l'integrazione di twisted. Ti permetterà di fare una chiamata asincrona –