I am wrote a piece of python code that handles multiple processes and
it works great, but I am trying to add a Kivy based display to this
code. I have updated the code to be able to use threads instead of
processes, which works. The issue that I have is that I can't seem to
get the threads to write back to the screen. I am using @mainthread
. I found a sample code here, and was able to get the threads to update the screen, but for some reason my code doesn't seem to work.
Here is menu.kv
#:import functions functions
#:import labelB labelB
<UpdateButton@LabelB>:
font_size: '36sp'
<ScreenManagement>:
MenuScreen:
RunScreen:
ProgramScreen:
<MenuScreen>:
name: 'menu'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
GridLayout:
cols: 2
# orientation: 'horizontal'
padding: 20
spacing: 10
Button
text: "Start Application"
on_release: root.manager.current = 'run'
<RunScreen>:
name: 'run'
BoxLayout:
orientation: 'vertical'
GridLayout:
cols: 2
orientation: 'horizontal'
padding: 20
spacing: 10
Label:
text: "How many fillers are to be used [1-4]? "
TextInput:
text: '1'
id: NumberofFillers
input_type: 'number'
# on_text_validate: functions.RepresentsFloat(
Label:
text: "What is the blanket weight (Lbs)? "
halign: 'right'
TextInput:
text: '12'
id: BlanketWeight
Label:
text: "What is the Material weight (grams) ? "
halign: 'right'
TextInput:
text: '819'
id: MaterialWeight
Label:
text: "How many Columns are there? "
halign: 'right'
TextInput:
text: '4'
id: NumberofCols
Label:
text: "How many rows are there? "
halign: 'right'
TextInput:
text: '1'
id: NumberofRows
BoxLayout:
size: 1, .1
size_hint: 1, .15
Button
text: "Start"
on_release: root.routine()
Button
text: "Return"
on_release: root.manager.current = 'menu'
<ProgramScreen>:
numberofcells: numberofcells
cellweight: cellweight
filler1: filler1
filler2: filler2
filler3: filler3
filler4: filler4
name: 'program'
BoxLayout:
orientation: 'vertical'
GridLayout:
size_hint: 1, .20
cols: 2
Label:
text: "Total Number of Cells"
halign: 'center'
Label:
text: "Target weight for each cup"
halign: 'center'
Label:
id: numberofcells
text: 'Start_C'
halign: 'center'
Label:
id: cellweight
text: 'Start_W'
halign: 'center'
GridLayout:
cols: 4
UpdateButton:
id: filler1
text: 'Filler 1'
halign: 'center'
padding_y: '300'
bcolor: 1,0,1,1
UpdateButton:
id: filler2
text: 'Filler 2'
halign: 'center'
padding_y: '300'
bcolor: 1,0,0,1
UpdateButton:
id: filler3
text: 'Filler 3'
halign: 'center'
padding_y: '300'
bcolor: 1,0,1,0
UpdateButton:
id: filler4
text: 'Filler 4'
halign: 'center'
padding_y: '40 '
bcolor: 0,0,1,1
Here is my main.py
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
from functools import partial
import time
import numpy # sudo apt-get python-numpy
import threading
import labelB
import config
########################################################################
class ScreenManagement(ScreenManager):
pass
class MenuScreen(Screen):
pass
class RunScreen(Screen):
def routine(self):
NumberofFiller = int(self.ids.NumberofFillers.text)
BlanketWeight = int(self.ids.BlanketWeight.text)
MaterialWeight =int(self.ids.MaterialWeight.text)
NumberofRows = int(self.ids.NumberofRows.text)
NumberofCols = int(self.ids.NumberofCols.text)
NumberofCells = NumberofRows * NumberofCols
config.CellWeight = round((( ( float(BlanketWeight)*453.592) - MaterialWeight) / NumberofCells),9)
print ("Each of the %d cells will get %.3fg of pellets" % (NumberofCells,config.CellWeight) )
Number = self.manager.get_screen('program').numberofcells
Number.text = str(NumberofCells)
Weight = self.manager.get_screen('program').cellweight
Weight.text = str(round(config.CellWeight,4))
self.parent.current = 'program'
# time.sleep(1)
threading.Thread(target=ProgramScreen().build, args=(NumberofFiller , NumberofCells,)).start()
# ProgramScreen().build(NumberofFiller , NumberofCells)
class ProgramScreen(Screen):
@mainthread
def update_label(self, int_counter, new_text):
# def update_label(self, int_counter, new_text, *largs):
if int_counter == 0 :
print "here ", int_counter, new_text
# fill = self.manager.get_screen('program').filler1
# fill.text = 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):
Clock.schedule_once(lambda dt: self.update_label( int(value), str(i)), 0)
# Clock.schedule_once(self.update_label:
# self.update_label(int(value),str(i))
print value, i
time.sleep(1)
print 'func', value, 'finishing'
def build(self, NumberofFiller, NumberofCells):
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
if (CellCounter >= NumberofCells):
break
for x in threads:
x.join()
# print (threads)
except (KeyboardInterrupt, SystemExit):
functions.cleanAndExit()
"""
#to go back to main menu when program has finished running.
self.parent.current = 'menu'
"""
########################################################################
#Builder.load_file("Menu_red.kv") #Not needed
class Menu_redApp(App):
def build(self):
return ScreenManagement()
#----------------------------------------------------------------------
if __name__ == "__main__":
Menu_redApp().run()
The only way that I could find to have the screen update, after executing self.parent.current = 'program'
was to run the rest of the code as a thread. But I now I can't seem to
get the threads to write back to the main function to update the
screen. In the end, once the text has been updated, I will need to
change the color of the boxes, but that will come in due course.
Thought/comments/suggestions would be greatly appreciated. I noticed
that there isn't a lot on this subject from a Python kivy point of view. I have attached the two files to this email.
thank you