2017-04-16 164 views
0

複数のプロセスを処理するPythonコードを書きましたが、うまくいきましたが、このコードにKivyベースのディスプレイを追加しようとしています。プロセスの代わりにスレッドを使用できるようにコードを更新しました。これは動作します。私が持っている問題は、スレッドがスクリーンに書き戻すように見えないことです。私は@mainthreadを使用しています。サンプルコードhereが見つかりましたが、画面を更新するスレッドを取得することができましたが、何らかの理由で私のコードが動作していないようです。
- >編集、私は私の質問に関係するとは思わない余分なコードを削除しました。
- >編集#2:私はまだ私が裸であると思うものにコードを単純化しました。私が持っている問題をまだ示す。私が読んだことから、それは私に問題の原因となっているx.joinコードであり、メインループをロックしている可能性があります。私はwhileループを5回実行する必要がありますが、一度に2つのスレッドしか実行できません。先に進む前にスレッドが終了している間、whileループをノンブロッキング状態に保持する必要があります。ここでKivyマルチスレッドとアップデート画面

はここmenu.kv

<ScreenManagement>: 
    MenuScreen: 
    ProgramScreen: 


<MenuScreen>: 
    name: 'menu' 
    AnchorLayout: 
     GridLayout: 
      cols: 2 
      Button 
       text: "Start Application" 
       on_release: root.routine() 

<ProgramScreen>: 
    filler1: filler1 
    filler2: filler2 
    filler3: filler3 
    filler4: filler4 
    name: 'program' 
    GridLayout: 
     cols: 4 
     Button: 
      id: filler1 
      text: 'Filler 1' 
      halign: 'center' 
      padding_y: '300' 
      bcolor: 1,0,1,1 
     Button: 
      id: filler2 
      text: 'Filler 2' 
      halign: 'center' 
      padding_y: '300' 
      bcolor: 1,0,0,1 
     Button: 
      id: filler3 
      text: 'Filler 3' 
      halign: 'center' 
      padding_y: '300' 
      bcolor: 1,0,1,0 
     Button: 
      id: filler4 
      text: 'Filler 4' 
      halign: 'center' 
      padding_y: '40 ' 
      bcolor: 0,0,1,1 

である私のmain.pyは、私は、画面の更新を持つように見つけることができる唯一の方法は、self.parent.current = 'program'を実行した後、残りを実行することでした

from kivy.app import App 
from kivy.uix.togglebutton import ToggleButton 
from kivy.uix.widget import Widget 
from kivy.uix.boxlayout import BoxLayout 
from kivy.uix.gridlayout import GridLayout 
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition 
from kivy.lang import Builder 
from kivy.properties import * 
from kivy.core.window import Window 
from kivy.clock import Clock, mainthread 
import threading 
import time 


######################################################################## 
class ScreenManagement(ScreenManager): 
    pass 

class MenuScreen(Screen): 
    def routine(self): 
     self.parent.current = 'program' 
     threading.Thread(target=ProgramScreen().build).start() 

class ProgramScreen(Screen): 

    @mainthread 
    def update_label(self, int_counter, new_text): 
     if int_counter == 0 : 
      print "here ", int_counter, new_text 
      self.filler1.text = new_text 
     elif int_counter == 1 : 
      self.filler2.text = new_text 
     elif int_counter == 2 : 
      self.filler3.text = new_text 
     elif int_counter == 3 : 
      self.filler4.text = new_text 
     else: 
      self.filler1.text = "fault" 

#dummy function to be replaced with a function that will call GPIO for input and feedback. 
    def func (self,value): 
     print 'func', value, 'starting' 
     for i in xrange(10*(value+1)): 
      if ((i%3) == 0): 
       self.update_label(int(value),str(i)) 
       print value, i 
       time.sleep(1) 
     print 'func', value, 'finishing' 

    def build(self): 
     NumberofFiller = 2 
     NumberofCells = 5 
     CellCounter = 0 
     while CellCounter < NumberofCells: 
      try: 
       threads = [] 
       print ('Counter:',CellCounter,'Fillers:',NumberofFiller,'Cells:',NumberofCells)  
       for i in range (NumberofFiller): 
        t = threading.Thread(target=self.func, args=((CellCounter%NumberofFiller),)) 
        t.start() 
        threads.append(t) 
        CellCounter = CellCounter +1 

       for x in threads: 
        #Problem I believe is here. 
        x.join() 
        #Need a way to pause the While loop for the first set of threads to finish before starting the next threads. 
#    print (threads) 
      except (KeyboardInterrupt, SystemExit): 
       functions.cleanAndExit() 


######################################################################## 
#Builder.load_file("Menu_red.kv") #Not needed 
class Menu_red2App(App): 
    def build(self): 
     return ScreenManagement() 

#---------------------------------------------------------------------- 
if __name__ == "__main__": 
    Menu_red2App().run() 

ですスレッドとしてコードの。しかし、私は今、スレッドをメイン関数に書き戻して画面を更新するようには思えません。最終的に、テキストが更新されたら、ボックスの色を変更する必要がありますが、それは間に合うでしょう。

+0

問題の最低限の例に役立つだろう。 https://stackoverflow.com/help/mcve – EL3PHANTEN

+0

こんにちは、私は問題の一部ではないと思われる「余分な」コードを削除しました。 – user1086924

答えて

0

routineメソッドで外側のスレッドを開始するとき、ターゲットをProgramScreen().buildに設定すると、実際には新しいスクリーンが作成されるという問題があります。したがって、スクリーンマネージャーの画面には影響しません。
スクリーンマネージャーに入ったProgramScreenbuildメソッドにターゲットを設定するには、そのスクリーンをその名前で取得できます。
あなたはすでにそれに名前を付けましたprogram
だからあなたMenuScreenクラスは次のようになります。

class MenuScreen(Screen): 
    def routine(self): 
     self.parent.current = 'program' 
     threading.Thread(target=self.manager.get_screen('program').build).start() 
+0

それは私がやったと思ったことです。メインプログラムはスレッド 'threading.Thread(target = ProgramScreen()。build、args =(NumberofFiller、NumberofCells))。start()'を作成し、メインプログラムとは独立していなければなりません。次に、これは別々のスレッドを呼び出します。問題は私がスレッドに "参加"していることです(私はすべてのサブスレッドが完了するまで続行したくありません)。しかし、私はこれがメインコードをどのようにブロックするのか分かりません。現時点では何もラズベリーパイに接続していません。 – user1086924

+0

@ user1086924あなたのコードを、私のように「貼り付け/実行可能ファイル」という最小限の例に絞り込み、それでも問題を再現できれば、簡単に手助けすることができます。そして、あなたはその時点で自分自身で問題を見るかもしれません。あなただけのスレッドの問題が残っているまで、物事を取り除いてください。 – EL3PHANTEN

+0

@ user1086924 okey updated – EL3PHANTEN

関連する問題