Here is my a simple code, which uses Python socket and threading. Here the thread cannot able to run a function of adding widget List dynamically.
Note: The thread is able to successful run all function except the function for add_widget.
Thanks in Advance.
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.uix.textfield import MDTextField, MDTextFieldRound
from kivymd.uix.button import MDFillRoundFlatButton, MDIconButton,MDRectangleFlatButton
import sys
import socket
from kivy.uix.scrollview import ScrollView
from kivymd.uix.list import OneLineListItem, IRightBody
import threading
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.clock import mainthread
kv="""
ScreenManager
LoginPage:
MsgPlatform:
<LoginPage>:
name:'login'
MDTextField:
id:ip
hint_text:'Enter ip-Addresh'
pos_hint:{'center_x':0.5,'center_y':0.7}
size_hint_x:0.3
MDTextField:
id:port
hint_text:'Enter port'
pos_hint:{'center_x':0.5,'center_y':0.6}
size_hint_x:0.3
MDFillRoundFlatButton:
text:'Join'
pos_hint:{'center_x':0.5,'center_y':0.5}
on_release:
root.login()
root.manager.transition.direction='left'
root.manager.transition.duration= 0.2
root.manager.current='msgplatform'
<MsgPlatform>:
name:'msgplatform'
ScrollView:
MDList:
id:container
ScrollView:
MDList:
id:cont
MDIconButton:
icon:'send.jpg'
pos_hint:{'center_x':0.95,'center_y':0.05}
size_hint:0.04,0.03
on_release:
root.send_msg()
root.clear_msg()
"""
s=socket.socket()
data=''
class recvThread(object):
def __init__(self):
thread = threading.Thread(target=self.recv, args=())
thread.daemon = True
thread.start()
def recv(self):
while True:
global data
data=str(s.recv(5000),'utf-8')
if str(data)!='':
MsgPlatform().recvMsg()
class LoginPage(Screen):
def login(self):
host=str(self.ids.ip.text)
port=int(self.ids.port.text)
s.connect((host,port))
class MsgPlatform(Screen):
def on_pre_enter(self):
recvThread()
def recvMsg(self):
cont=self.ids.container
global data
print(data)
c=cont.add_widget(OneLineListItem(text=str(data)))
sm=ScreenManager()
sm.add_widget(LoginPage(name='login'))
sm.add_widget(MsgPlatform(name="msgplatform"))
class MainApp(MDApp):
def build(self):
script=Builder.load_string(kv)
return script
if __name__=='__main__':
MainApp().run()
Here is Thread:
class recvThread(object):
def __init__(self):
thread = threading.Thread(target=self.recv, args=())
thread.daemon = True
thread.start()
def recv(self):
while True:
global data
data=str(s.recv(5000),'utf-8')
if str(data)!='':
MsgPlatform().recvMsg()
Here is the thread implementation function.
def recvMsg(self):
cont=self.ids.container
global data
print(data)
c=cont.add_widget(OneLineListItem(text=str(data)))
Related
How is it possible that the Kivy GUI app is not load the whole code at the time of initialization?
Is it possible that when we called some function so the execution of the code which is inside that function starts at runtime.
The code is:
from kivymd.app import MDApp
from kivymd.uix.card import MDCard
from kivymd.uix.screen import MDScreen
from kivymd.uix.selectioncontrol import MDCheckbox
from kivymd.uix.textfield import MDTextField
from kivymd.uix.label import MDLabel
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.metrics import dp
from kivymd.uix.fitimage import FitImage
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
from kivy.uix.screenmanager import Screen,ScreenManager
class my_mdcard(MDCard,RoundedRectangularElevationBehavior):
pass
class Item_Menu(Screen,MDBoxLayout):
list_of_information={"checkbox":[],"labels":[],"quantity":[]}
selected_items= {"checkbox": [], "labels": [], "quantity": []}
def __init__(self,**kwargs):
super(Item_Menu,self).__init__(**kwargs)
self.size_hint=(1,0.9)
self.pos_hint={"top":1}
self.orientation="vertical"
scrollbarwin=ScrollView()
content_box=BoxLayout(orientation='vertical',padding=dp(8),spacing=dp(8),size_hint=(1,None))
content_box.bind(minimum_height=content_box.setter('height'))
for i in range(0,50):
Template_card= my_mdcard(
size_hint_y=None,
size_hint_x=.960,
height = dp(100),
padding = dp(4),
pos_hint={'center_y': .5, 'center_x': .490},
radius = [20,],
elevation = 4,
)
checkbox=MDCheckbox(
size_hint=(None, None),
size= (dp(48),dp(48)),
pos_hint={'center_y': .5}
)
checkbox.bind(active=lambda instance,value:self.Selected_checkbox(instance,value))
self.list_of_information["checkbox"].append(checkbox)
image_box=MDBoxLayout(adaptive_size=True)
image=FitImage(
source="D:/Study/Python/Kivy/images/2.jpg",
size_hint= (None, None),
height=dp(80),
width=dp(130),
radius=[12,],
pos_hint={'center_y':0.5}
)
image_box.add_widget(image)
text_box=MDBoxLayout(orientation="vertical",adaptive_height=True,pos_hint={'center_y':0.5},padding=[12,0,0,0])
item_name=MDLabel(text=f"item{i+1}",font_style="H5",size_hint=(1,None),bold=True,theme_text_color="Primary")
item_name.bind(texture_size=item_name.setter('size'))
self.list_of_information["labels"].append(item_name)
price=MDLabel(text=u"Price: \u20B910/per",font_style="Subtitle1",size_hint=(1,None),bold=True,theme_text_color="Hint")
price.bind(texture_size=price.setter('size'))
quantitybox=MDBoxLayout(orientation='vertical',adaptive_height=True,size_hint_x=0.2,pos_hint = {'center_y': .5,'center_x':0.5})
quantityfield=MDTextField(
hint_text= "Quantity",
mode= "rectangle",
size_hint=(None,None),
width=dp(80),
height= dp(40),
padding=[0,0,15,0]
)
self.list_of_information["quantity"].append(quantityfield)
quantitybox.add_widget(quantityfield)
Template_card.add_widget(checkbox)
Template_card.add_widget(image_box)
Template_card.add_widget(text_box)
text_box.add_widget(item_name)
text_box.add_widget(price)
Template_card.add_widget(quantitybox)
content_box.add_widget(Template_card)
scrollbarwin.add_widget(content_box)
buttonbox=MDBoxLayout(orientation="vertical",pos_hint={"top":0.1},adaptive_height=True)
button=MDRaisedButton(text="Selected!!!",size_hint=(1,0.2))
button.bind(on_release=lambda x:self.Change_window(x))
buttonbox.add_widget(button)
self.add_widget(scrollbarwin)
self.add_widget(buttonbox)
def Selected_checkbox(self,instance,value):
for i in range(0,len(self.list_of_information["checkbox"])):
if instance==self.list_of_information["checkbox"][i] and value== True:
self.selected_items["labels"].append(self.list_of_information["labels"][i])
self.selected_items["quantity"].append(self.list_of_information["quantity"][i])
elif instance==self.list_of_information["checkbox"][i] and value== False :
self.selected_items["labels"].remove(self.list_of_information["labels"][i])
self.selected_items["quantity"].remove(self.list_of_information["quantity"][i])
def Change_window(self,instance):
MyApp.sm.current="Item Description"
class Description_item(Screen):
def __init__(self,**kwargs):
super(Description_item,self).__init__(**kwargs)
print(Item_Menu.selected_items)
wholeContentBoxContainer=MDBoxLayout(orientation="vertical")
for item in range(0,len(Item_Menu.selected_items["labels"])):
label=MDLabel(text=Item_Menu.selected_items["labels"][item].text)
print(Item_Menu.selected_items["labels"][item].text)
quantity=MDLabel(text=Item_Menu.selected_items["quantity"][item].text)
wholeContentBoxContainer.add_widget(label)
wholeContentBoxContainer.add_widget(quantity)
self.add_widget(wholeContentBoxContainer)
class MyApp(MDApp):
sm=ScreenManager()
def build(self):
self.sm.add_widget(Item_Menu(name="Item Menu"))
self.sm.add_widget(Description_item(name="Item Description"))
self.theme_cls.theme_style="Dark"
return self.sm
MyApp().run()
When you run this code so you will see that at the time of initialization of the app the print function is getting print the the dictionary "selected_items" which I never want to be print it out at the time of initialization of the code.
Here is a picture will help you to better understand:
Due to this reason I am unable to access the data of the dictionary "selected_items" in the class "Description_item" because it points to empty list which is the value of the dictionary keys.
So how I can access the data of the dictionary "selected_items"?
i have problem when i use loop in kivy app to show update value for loop, so when i run app and press toggle button to start showing last value of loop i program crash.
this is code:
*.py
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from random import randint
class ShowLoopValueInterface(BoxLayout):
ToggleButton_label = StringProperty("normal")
Label_text_value = StringProperty("normal")
def togglebutton_on_state(self, widget):
if widget.state == "down":
self.ToggleButton_label = "down"
# self.to_text_value()
Clock.schedule_interval(self.to_text_value, 0.5)
else:
self.ToggleButton_label = "normal"
def to_text_value(self, _):
# def to_text_value(self):
while True:
self.Label_text_value = str(randint(0, 100))
class ShowLoopValueApp(App):
pass
ShowLoopValueApp().run()
*.kv
ShowLoopValueInterface:
<ShowLoopValueInterface>:
orientation: "vertical"
ToggleButton:
text: root.ToggleButton_label
on_state: root.togglebutton_on_state(self)
Label:
text: root.Label_text_value
I'm trying to display an animation while something else is done in the background and I have this code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from threading import Thread
from kivymd.app import MDApp
from kivy.animation import Animation
import multiprocessing
import time
sm = ScreenManager()
Builder.load_string("""
<LoadingScreen>:
BoxLayout:
Button:
id: loading_anim
text: 'Hello'
<MainLayout>:
BoxLayout:
Button:
text: 'world'
""")
class MainLayout(Screen):
pass
class LoadingScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def on_pre_enter(self):
t = multiprocessing.Process(target=self.loading_anim)
t.start()
t.join()
def loading_anim(self, *args):
print('sleeping after starting animation')
loading_anim = self.ids['loading_anim']
anim = Animation(
d=.7,
opacity=1
)
anim += Animation(
d=.7,
opacity=.6
)
time.sleep(1)
anim.repeat = True
anim.start(loading_anim)
time.sleep(1)
print('awake')
def prepare_for_launch(self, *args):
sm.switch_to(MainLayout(name='settings'))
class TestApp(MDApp):
def build(self):
sm.add_widget(LoadingScreen(name='menu'))
sm.add_widget(MainLayout(name='settings'))
return sm
if __name__ == '__main__':
TestApp().run()
but it throws an error saying:
"TypeError: no default __reduce__ due to non-trivial __cinit__"
but if I don't use multiprocessing it works.
Replace
def on_pre_enter(self):
t = multiprocessing.Process(target=self.loading_anim)
t.start()
t.join()
with
def on_pre_enter(self):
self.loading_anim
and it works fine. (the fact that animation starts after sleeping is done is concerning me too as I initiate it before sleeping.)
Struggling to pass a variable to kivy window. I have read similar threads all over the place but none of the fixes seem to work for me. Im sure this is simple to someone who knows their way around tiny, unfortunately I don't.
main.py
import kivy
from kivy.uix.togglebutton import ToggleButton
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.app import App
kivy.require('1.10.0')
from phue import Bridge
import nest
b = Bridge('xxx.xxx.x.xxx')
b.connect()
b.get_api()
lights = b.lights
class Controller(GridLayout):
print("launching")
def __init__(self):
super(Controller, self).__init__()
def KitchenSpot1(self,state):
lights[0].name
lights[0].on = state
def update(dt):
if b.get_light(1, 'on')== True:
#print("down") # When this line is commented out I get an continuous accurate update on the status of the light, showing that its working.
return 'down' # This is the part I want passed to the state criteria in the ivy window
else:
#print("up")# When this line is commented out I get an continuous accurate update on the status of the light, showing that its working.
return 'down' # This is the part I want passed to the state criteria in the ivy window
class ActionApp(App):
def build(self):
Clock.schedule_interval(Controller.update, 1.0 / 60.0)
return Controller()
myApp = ActionApp()
myApp.run()
action.kv
<Controller>:
cols: 4
rows: 3
spacing: 10
ToggleButton:
id: KitchenSpot1Toggle
text: "Kitchen Spot 1"
on_press: root.KitchenSpot1(True)
#on_release: root.KitchenSpot1(False)
#state1 = app.update.h
state: Controller.update # This is the part that is throwing up the error.
The error:
11: #on_release: root.KitchenSpot1(False)
12: #state1 = app.update.h
>> 13: state: Controller.update
14:
15:
...
NameError: name 'Controller' is not defined
Thanks in advance to anyone that can help me.
Make update an instance method and use a StringProperty to update state property in your kv:
main.py:
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.togglebutton import ToggleButton
from phue import Bridge
import nest
b = Bridge('xxx.xxx.x.xxx')
b.connect()
b.get_api()
lights = b.lights
class Controller(GridLayout):
state = StringProperty('normal') # <<<<<<<<<<<<
def __init__(self, **kwargs):
super(Controller, self).__init__(**kwargs)
Clock.schedule_interval(self.update, 1.0 / 60.0)
def KitchenSpot1(self,state):
lights[0].name
lights[0].on = state
def update(self, dt):
if b.get_light(1, 'on'):
self.state = 'down' # <<<<<<<<<<<<
else:
self.state = 'normal' # <<<<<<<<<<<<
class ActionApp(App):
def build(self):
return Controller()
if __name__ == "__main__":
myApp = ActionApp()
myApp.run()
action.kv:
<Controller>:
cols: 4
rows: 3
spacing: 10
state: "normal" # <<<<<<<<<<<<
ToggleButton:
id: KitchenSpot1Toggle
text: "Kitchen Spot 1"
on_press: root.KitchenSpot1(True)
#on_release: root.KitchenSpot1(False)
#state1 = app.update.h
state: root.state # <<<<<<<<<<<<
Here is a more generic simplified answer from the kivy documentation, look for the section called "Keyword arguments and init()" because there are some other ways to do it as well.
The following code passes myvar to the build() method of MyApp. It does this by over-riding the init() of the Kivy App class by a new init() that calls App.init() and then continues with whatever extra initialisation you want. You can then store variables in the MyApp class instances and use them in build().
from kivy.app import App
from kivy.uix.label import Label
myvar = 'Hello Kivy'
class MyApp(App):
def __init__(self, myvar, **kwargs):
super(MyApp, self).__init__(**kwargs)
self.myvar = myvar
def build(self):
widget = Label(text=self.myvar)
return widget
if __name__ == '__main__':
MyApp(myvar).run()
I am using kivy for UI. there is a Time_consuming function and when it runs, kivy ui will goes in black, so I used Threading.
I want to disable buttons until Time_consuming function finishes, and then enable button again. I have been used something like below:
from threading import Thread
from kivy.clock import Clock
from functools import partial
def run():
self.run_button.disabled=True
self.back_button.disabled=True
t=Thread(target=Time_consuming(), args=())
t.start()
Clock.schedule_interval(partial(disable, t.isAlive()), 8)
def disable(t, what):
print(t)
if not t:
self.run_button.disabled=False
self.back_button.disabled=False
but this dose not work, t.isAlive() in disable() even when Time_consuming() finishes, is True. where is the problem ?
question2: another problem is, Clock.schedule_interval will continue to run for ever. how can stop it when function finished?
I see you already answered your question. I was also building an example app to help you, while you were answering. I think it still can be of value to you and therefore I am posting it. One button shows you threading and the other one scheduling once. Happy coding :).
from kivy.app import App
from kivy.base import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
import time
import threading
Builder.load_string("""
<rootwi>:
label_to_be_changed1: label_to_be_changed1
label_to_be_changed2: label_to_be_changed2
button1: button1
button2: button2
orientation: 'vertical'
Button:
id: button1
text:'Button1 - Threading'
on_press: root.change_Label_text1()
Button:
id: button2
text: 'Button2 - schedule'
on_press: root.change_Label_text2()
Label:
id: label_to_be_changed1
Label:
id: label_to_be_changed2
""")
class rootwi(BoxLayout):
label_to_be_changed1 = ObjectProperty()
label_to_be_changed2 = ObjectProperty()
button1 = ObjectProperty()
button2 = ObjectProperty()
def change_Label_text1(self):
self.button1.disabled = True
threading.Thread(target=self.timeconsuming).start()
def timeconsuming(self):
#do your stuff
time.sleep(5)
self.label_to_be_changed1.text = 'thread has ended'
self.button1.disabled = False
def change_Label_text2(self):
self.button2.disabled = True
Clock.schedule_once(self.change_Label_text2_callback, 4)
def change_Label_text2_callback(self, *largs):
self.label_to_be_changed2.text = 'schedule has ended'
self.button2.disabled = False
class MyApp(App):
def build(self):
return rootwi()
if __name__ == '__main__':
MyApp().run()
I have found that:
question1: pass t instead of t.isAlive().this :
Clock.schedule_interval(partial(disable, t.isAlive()), 8)
changed to :
Clock.schedule_interval(partial(disable, t), 8)
question2: If the disable() returns False, the schedule will be canceled and won’t repeat.
def run_model():
self.run_button.disabled=True
self.back_button.disabled=True
t=Thread(target=run, args=())
t.start()
Clock.schedule_interval(partial(disable, t), 8)
def disable(t, what):
if not t.isAlive():
self.run_button.disabled=False
self.back_button.disabled=False
return False