Related
I have an App with 3 screens managed by a ScreenManager: MainScreen, ScanScreen, PinScreen. From MainScreen I have 2 buttons, 1 to go to ScanScreen, 1 to go to PinScreen. In ScanScreen I have a button to go into PinScreen and in PinScreen I have a button to go in ScanScreen. I want to go to MainScreen after some interval of time. I managed to make it works only if I go to secondary screens from MainScreen. If I go from MainScreen to ScanScreen and from ScanScreen to PinScreen then it wont work. I get this error:
line 16, in timeout
self.parent.current = 'mainScreen'
AttributeError: 'NoneType' object has no attribute 'current'
This is what I got so far:
kv file
ScreenManagement:
id:'screenManager'
MainScreen:
ScanScreen:
PinScreen:
FinalScreen:
<MainScreen>:
name: "mainScreen"
MDCard:
radius: [36, ]
size_hint: .8, .9
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: [20, 50, 20, 150]
spacing: 50
orientation: 'vertical'
MDIcon:
icon: "face-recognition"
font_size: 120
halign: 'center'
size_hint: 1, .5
MDFillRoundFlatButton:
text: "Scan Face"
font_size: 32
pos_hint: {"center_x": 0.5}
#size_hint: 1, .25
on_release:
root.manager.current = 'scanScreen'
root.manager.transition.direction = 'left'
MDFillRoundFlatButton:
text: "Access with PIN"
font_size: 32
pos_hint: {"center_x": 0.5}
#size_hint: 1, .25
on_release:
root.manager.current = 'pinScreen'
root.manager.transition.direction = 'left'
<ScanScreen>:
on_pre_enter: app.title = 'Scan Screen'
name: "scanScreen"
#on_enter: TODO timer function
MDCard:
radius: [36, ]
size_hint: .9, .95
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: [20, 50, 20, 150]
spacing: 50
orientation: 'vertical'
Image:
id: "frame_feed"
size_hint: 1, .8
MDFillRoundFlatButton:
text: "Access with PIN"
font_size: 32
pos_hint: {"center_x": 0.5}
on_release:
root.manager.current = 'pinScreen'
root.manager.transition.direction = 'left'
<PinScreen>:
on_pre_enter: app.title = 'PIN Screen'
name: "pinScreen"
MDBoxLayout:
orientation: 'vertical'
MDBoxLayout:
orientation: 'vertical'
size_hint: (1, .5)
MDIconButton:
icon: "arrow-left-drop-circle"
#icon_size: '32sp' this should be the right way but its not working
user_font_size: '32sp' #this should be deprecated but it's working
on_release:
root.manager.current = 'scanScreen'
root.manager.transition.direction = 'right'
MDIcon:
icon: "account-lock"
font_size: 60
halign: 'center'
MDLabel:
text: "Enter your passcode"
halign: "center"
font_style: "Body1"
MDGridLayout:
size_hint: (.5, 1)
pos_hint: {"center_x": .5}
cols: 6
#padding: [80,0,80,0]
#halign: "center"
MDIcon:
icon:"checkbox-blank-circle-outline"
MDIcon:
icon:"checkbox-blank-circle-outline"
MDIcon:
icon:"checkbox-blank-circle-outline"
MDIcon:
icon:"checkbox-blank-circle-outline"
MDIcon:
icon:"checkbox-blank-circle-outline"
MDIcon:
icon:"checkbox-blank-circle-outline"
Widget:
size_hint_y: None
height: 100
MDBoxLayout:
orientation: 'vertical'
size_hint: (1, .5)
MDGridLayout:
size_hint: (.5, 1)
pos_hint: {"center_x": .385}
cols:3
spacing: 20
MDFillRoundFlatButton:
text: "1"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "2"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "3"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "4"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "5"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "6"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "7"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "8"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: "9"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatButton:
text: ""
md_bg_color: 1,0,0,0
MDFillRoundFlatButton:
text: "0"
text_color: .95,.953,.956,1
font_size: 20
font_style: 'H4'
md_bg_color: .4, .4, .4, 1
MDFillRoundFlatIconButton:
icon: "backspace"
padding: [40,0,0,0]
font_style: 'H4'
icon_color: .827,.827,.827,1
md_bg_color: 1,0,0,0
<FinalScreen>:
on_pre_enter: app.title = 'Final Screen'
name: "finalScreen"
python file
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.clock import Clock
Window.size = (414, 736) #This is the viewport of iPhone 6 Plus/6S Plus/7 Plus/8 Plus
import cv2
class MainScreen(Screen):
pass
class ScanScreen(Screen):
def timeout(self, *args):
self.parent.current = 'mainScreen'
def on_enter(self, *args):
Clock.schedule_once(self.timeout, 2)
class PinScreen(Screen):
def timeout(self, *args):
self.parent.current = 'mainScreen'
def on_enter(self, *args):
Clock.schedule_once(self.timeout, 2)
class FinalScreen(Screen):
def timeout(self, *args):
self.parent.current = 'mainScreen'
def on_enter(self, *args):
Clock.schedule_once(self.timeout, 2)
class ScreenManagement(ScreenManager):
pass
class MainApp(MDApp):
def __init__(self, **kwargs):
self.title = "Main Screen"
super().__init__(**kwargs)
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Green"
self.theme_cls.accent_palette = "Teal"
return Builder.load_file('main.kv')
def return_to_main_screen(self):
pass
if __name__ == "__main__":
MainApp().run()
I also tried this:
class ScanScreen(Screen):
def timeout(self, *args):
MDApp.get_running_app().root.manager.current = 'mainScreen'
#self.parent.current = 'mainScreen'
def on_enter(self, *args):
Clock.schedule_once(self.timeout, 2)
but I get this error:
MDApp.get_running_app().root.manager.current = 'mainScreen'
AttributeError: 'ScreenManagement' object has no attribute 'manager'
So to clarify, I managed to do what I wanted by using get_running_app() method and accessing the root, which in my case is the ScreenManager. I made some changes to my code so it would reset the countdown after activity. This is what I have in each of the screen that I want to return to MainScreen after 30s of inactivity:
class ScanScreen(Screen):
def timeout(self, *args):
MDApp.get_running_app().root.current = 'mainScreen'
MDApp.get_running_app().root.transition.direction = 'right'
def reset_timeout(self, *args):
Clock.unschedule(self.timeout)
Clock.schedule_once(self.timeout, 30)
def on_enter(self, *args):
Clock.schedule_once(self.timeout, 30)
def on_leave(self, *args):
Clock.unschedule(self.timeout)
def on_touch_down(self, touch):
self.reset_timeout()
return super().on_touch_down(touch)
def on_touch_move(self, touch):
self.reset_timeout()
return super().on_touch_move(touch)
I am trying to build a simple messaging app, that uses rabbitmq as its message broker and kivy as its UI. So to receive incoming messages I have a receive function that is a loop, But when I try to multi-process the app and run it, kivy seems to be opening multiple windows. Kindly advise how I can tackle this issue.
.py file
import pika
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.card import MDCard
from database import Database as D
from kivy.core.window import Window
from multiprocessing import Process
from kivymd.uix.label import MDLabel
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDRectangleFlatButton
from kivy.uix.screenmanager import ScreenManager,Screen
Window.size = (400,700)
global logged_in_user
logged_in_user = ""
def receive():
CREDENTIALS = pika.PlainCredentials('redbarker', 'Redbarker#20-21')
PARAMETERS = pika.ConnectionParameters(credentials=CREDENTIALS)
connection = pika.BlockingConnection(PARAMETERS)
channel = connection.channel()
channel.exchange_declare(exchange='system_exchange', exchange_type='topic', durable=True)
result = channel.queue_declare(queue='', exclusive=True)
queue_name = result.method.queue
channel.queue_bind(exchange='system_exchange', queue=queue_name, routing_key="command.#")
def callback(ch, method, properties, body):
print(body)
channel.basic_consume(queue=queue_name, on_message_callback=callback, auto_ack=True)
channel.start_consuming()
class LoginScreen(Screen):
def validate_user(self):
uname = self.ids.uname_input.text
pword = self.ids.pword_input.text
is_found = D().login(uname,pword)
self.ids.uname_input.text = ""
self.ids.pword_input.text = ""
if is_found:
logged_in_user = uname
self.parent.current = "users_screen"
class SignupScreen(Screen):
def signin(self):
uname = self.ids.uname_input.text
pword1 = self.ids.pword_input1.text
pword2 = self.ids.pword_input2.text
D().signup(uname,pword1,pword2)
self.parent.current = "login_screen"
class UsersScreen(Screen):
def to_inbox(self,text):
InboxScreen().change_header(text)
self.parent.current = 'inbox_screen'
def add_user(self,name):
container = self.ids.user_field
button = MDRectangleFlatButton(
text = name,
font_style = "H6",
text_color = (.95,.44,.49,1),
line_color = (.95,.44,.49,1),
pos_hint = {"center_x": .5, "center_y": .5},
on_press = self.to_inbox(self.text),
)
container.add_widget(button)
class CreateGroupScreen(Screen):
def add_group(self):
container = self.ids.user_field
name = self.ids.username.text
if len(name) > 0:
card = MDCard(
size_hint_y = None,
height = 50,
line_color = (.95,.44,.49,1),
radius = 10,
padding = 10
)
label = MDLabel(
halign = "left",
text = name,
theme_text_color = "Custom",
text_color = (.95,.44,.49,1)
)
card.add_widget(label)
container.add_widget(card)
self.ids.username.text = ""
def remove_all_users(self):
for child in [child for child in self.ids.user_field.children]:
self.ids.user_field.remove_widget(child)
class AddUserScreen(Screen):
users = []
def add_user(self):
for name in self.users:
pass
def append_user(self):
name = self.ids.username.text
if len(name) > 0:
container = self.ids.user_field
card = MDCard(
size_hint_y = None,
height = 50,
line_color = (.95,.44,.49,1),
radius = 10,
padding = 10
)
label = MDLabel(
halign = "left",
text = name,
theme_text_color = "Custom",
text_color = (.95,.44,.49,1)
)
card.add_widget(label)
container.add_widget(card)
self.users.append(name)
self.ids.username.text = ""
def remove_all_users(self):
for child in [child for child in self.ids.user_field.children]:
self.ids.user_field.remove_widget(child)
class InboxScreen(Screen):
def change_header(self, text):
self.ids.header.text = text
def build_widget(self,message):
container = self.ids.text_field
layout = MDBoxLayout(
size_hint_y = None,
height = 50,
padding = (10,0),
)
card = MDCard(
radius = (0,10,0,10),
padding = 10
)
place_holder = MDBoxLayout()
label = MDLabel(
halign = "right",
text = message,
font_style = "H6",
theme_text_color = "Custom",
text_color = (.95,.44,.49,1)
)
card.add_widget(label)
layout.add_widget(place_holder)
layout.add_widget(card)
container.add_widget(layout)
def send(self):
message = self.ids.message_input.text
if len(message) > 0:
CREDENTIALS = pika.PlainCredentials('redbarker', 'Redbarker#20-21')
PARAMETERS = pika.ConnectionParameters(credentials=CREDENTIALS)
consumer = self.ids.header.text
connection = pika.BlockingConnection(PARAMETERS)
channel = connection.channel()
channel.exchange_declare(exchange = 'system_exchange', exchange_type='topic', durable= True)
channel.basic_publish(exchange='system_exchange', routing_key=f"Temesgen.{consumer}", body=message)
self.build_widget(message)
class WindowManager(ScreenManager):
pass
class ChatApp(MDApp):
def build(self):
return Builder.load_file('test.kv')
#if __name__ == "__main__":
# ChatApp().run()
if __name__ == '__main__':
ChatApp().run()
p1 = Process(target=receive)
p1.start()
.kv file
WindowManager:
LoginScreen:
SignupScreen:
AddUserScreen:
UsersScreen:
CreateGroupScreen:
InboxScreen:
<LoginScreen>:
name: "login_screen"
MDBoxLayout:
orientation: "vertical"
padding: 0,1
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
spacing: 20
padding: 20,10
Widget:
size_hint_y: .33
MDLabel:
halign: "center"
text: "Login"
font_style: "H4"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
Widget:
size_hint_y: .33
MDBoxLayout:
orientation: "vertical"
size_hint_y: .4
spacing: 20
MDTextField:
id: uname_input
pos_hint: {"center_x": .5}
size_hint_x: None
width: 250
hint_text: 'Username'
mode: 'rectangle'
color: (0,1,1,1)
line_color_normal: (0,1,0,1)
text_color: (.95,.44,.49,1)
MDTextField:
id: pword_input
pos_hint: {"center_x": .5}
size_hint_x: None
width: 250
hint_text: 'Password'
mode: 'rectangle'
color: (0,1,1,1)
line_color_normal: (0,1,0,1)
text_color: (.95,.44,.49,1)
MDTextButton:
text: 'Sign Up'
underline: True
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
on_press: app.root.current = "signup_screen"
MDBoxLayout:
orientation: "vertical"
size_hint_y: .5
Widget:
size_hint_y: .33
MDRectangleFlatButton:
text: "Login"
font_size: 20
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.validate_user()
Widget:
size_hint_y: .6
<SignupScreen>:
name: "signup_screen"
MDBoxLayout:
orientation: "vertical"
padding: 0,1
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
spacing: 20
padding: 20,10
MDBoxLayout:
size_hint_x: .25
MDIconButton:
size_hint_x: .25
icon: "keyboard-backspace"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "login_screen"
MDLabel:
size_hint_x: .5
halign: "center"
text: "Signin"
font_style: "H4"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
MDBoxLayout:
size_hint_x: .25
Widget:
size_hint_y: .25
MDBoxLayout:
orientation: "vertical"
size_hint_y: .4
spacing: 20
MDTextField:
id: uname_input
pos_hint: {"center_x": .5}
size_hint_x: None
width: 250
hint_text: 'Username'
mode: 'rectangle'
color: (0,1,1,1)
line_color_normal: (0,1,0,1)
text_color: (.95,.44,.49,1)
MDTextField:
id: pword_input1
pos_hint: {"center_x": .5}
size_hint_x: None
width: 250
hint_text: 'Password'
mode: 'rectangle'
color: (0,1,1,1)
line_color_normal: (0,1,0,1)
text_color: (.95,.44,.49,1)
MDTextField:
id: pword_input2
pos_hint: {"center_x": .5}
size_hint_x: None
width: 250
hint_text: 'Confirm Password'
mode: 'rectangle'
color: (0,1,1,1)
line_color_normal: (0,1,0,1)
text_color: (.95,.44,.49,1)
MDBoxLayout:
orientation: "vertical"
size_hint_y: .5
Widget:
size_hint_y: .33
MDRectangleFlatButton:
text: "Signin"
font_size: 20
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.signin()
Widget:
size_hint_y: .6
<UsersScreen>:
name: "users_screen"
MDBoxLayout:
orientation: "vertical"
padding: 0,1
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
spacing: 20
padding: 20,10
MDIconButton:
size_hint_x: .3
icon: "logout"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "login_screen"
MDLabel:
halign: "center"
text: "Users"
font_style: "H4"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
MDBoxLayout:
size_hint_x: .4
MDIconButton:
icon: "account-plus"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "add_user_screen"
MDIconButton:
icon: "account-multiple-plus"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "create_group_screen"
MDBoxLayout:
orientation: "vertical"
size_hint_y: .9
ScrollView:
size: self.size
pos: self.pos
MDList:
id: user_field
spacing: 10
padding: 10
MDRectangleFlatButton:
text: 'User-1 '
font_style: "H6"
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.to_inbox(self.text)
MDRectangleFlatButton:
text: 'User-2 '
font_style: "H6"
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.to_inbox(self.text)
MDRectangleFlatButton:
text: 'User-3 '
font_style: "H6"
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.to_inbox(self.text)
<CreateGroupScreen>:
name: "create_group_screen"
MDBoxLayout:
orientation: "vertical"
padding: 0,1
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
spacing: 20
padding: 20,10
MDIconButton:
id: remove_button
size_hint_x: .2
icon: "keyboard-backspace"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "users_screen"
MDLabel:
halign: "center"
text: "Create Group"
font_style: "H4"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
MDBoxLayout:
orientation: "vertical"
size_hint_y: .9
padding: 20
spacing: 40
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
radius: 10
padding: 25,3
MDTextField:
id: username
pos_hint: {"center_x": .5, "center_y": .4}
size_hint_x: None
width: 250
hint_text: 'Username'
MDIconButton:
id: add_button
size_hint_x: .2
icon: "account-multiple-plus"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.add_user()
MDIconButton:
id: remove_button
size_hint_x: .2
icon: "account-multiple-remove"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.remove_all_users()
MDCard:
orientation: "vertical"
size_hint_y: .6
line_color: (.95,.44,.49,1)
radius: 10
MDLabel:
size_hint_y: .1
halign: "center"
text: "Add Users"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
MDBoxLayout:
size_hint_y: .9
ScrollView:
size: self.size
pos: self.pos
MDList:
id: user_field
spacing: 10
padding: 10
MDBoxLayout:
orientation: "vertical"
size_hint_y: .3
Widget:
size_hint_y: .33
MDRectangleFlatButton:
text: "Create Group"
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
Widget:
size_hint_y: .33
<AddUserScreen>:
name: "add_user_screen"
MDBoxLayout:
orientation: "vertical"
padding: 0,1
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
spacing: 20
padding: 20,10
MDIconButton:
size_hint_x: .33
icon: "keyboard-backspace"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "users_screen"
MDLabel:
halign: "center"
text: "Add Users"
font_style: "H4"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
Widget:
size_hint_x: .33
MDBoxLayout:
orientation: "vertical"
size_hint_y: .9
padding: 20
spacing: 40
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
radius: 10
padding: 25,3
MDTextField:
id: username
pos_hint: {"center_x": .5, "center_y": .4}
size_hint_x: None
width: 250
hint_text: 'Username'
MDIconButton:
id: add_button
size_hint_x: .2
icon: "account-multiple-plus"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.append_user()
MDIconButton:
id: remove_button
size_hint_x: .2
icon: "account-multiple-remove"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.remove_all_users()
MDCard:
orientation: "vertical"
size_hint_y: .6
line_color: (.95,.44,.49,1)
radius: 10
MDLabel:
size_hint_y: .1
halign: "center"
text: "Add Users"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
MDBoxLayout:
size_hint_y: .9
ScrollView:
size: self.size
pos: self.pos
MDList:
id: user_field
spacing: 10
padding: 10
MDBoxLayout:
orientation: "vertical"
size_hint_y: .3
Widget:
size_hint_y: .33
MDRectangleFlatButton:
text: "Add Users"
text_color: (.95,.44,.49,1)
line_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.add_user()
Widget:
size_hint_y: .33
<InboxScreen>:
name: "inbox_screen"
MDBoxLayout:
orientation: "vertical"
padding: 0,1
MDCard:
size_hint_y: .1
line_color: (.95,.44,.49,1)
spacing: 20
padding: 20,10
MDIconButton:
size_hint_x: .2
icon: "keyboard-backspace"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: app.root.current = "users_screen"
MDLabel:
id: header
halign: "center"
text: ""
font_style: "H4"
theme_text_color: "Custom"
text_color: (.95,.44,.49,1)
MDBoxLayout:
orientation: "vertical"
size_hint_y: .9
ScrollView:
size: self.size
pos: self.pos
MDList:
id: text_field
spacing: 10
MDCard:
size_hint_y: .075
line_color: (.95,.44,.49,1)
padding: 10,0
MDTextField:
id: message_input
size_hint: None,None
height: 100
width: 325
hint_text: 'Write'
color: (0,1,1,1)
line_color_normal: (.95,.44,.49,1)
text_color: (.95,.44,.49,1)
pos_hint: {"center_x": .5, "center_y": .3}
MDIconButton:
id: send_button
icon: "send"
pos_hint: {"center_x": .5, "center_y": .5}
on_press: root.send()
What you are pretending to do is to run kivy concurrently. The best choice for async events in kivy is to use asyncio (as the oficcial documentation suggest). First at all you have to be sure your app runs from asyncio.run() instead of App.run(). To do this, you have to import asyncio and also you have to add a method to your App class. See the example below:
import asyncio
######## MAIN APP ########
class ExampleApp(App):
def build(self):
#Your app stuff here
async def kivyCoro(self): #This is the method that's gonna launch your kivy app
await self.async_run(async_lib='asyncio')
print('Kivy async app finished...')
# This func will start all the "tasks", in this case the only task is the kivy app
async def base(self):
(done, pending) = await asyncio.wait({self.kivyCoro()},
return_when='FIRST_COMPLETED')
if __name__ == '__main__':
instanceApp = ExampleApp() #You have to instanciate your App class
asyncio.run(instanciaApp.base()) # Run in async mode
With the code above you'll be able to run tour kivy app as a task (concurrently).
So far, we just have run the kivy app in async mode (concurrently). To add other task inside the Kivy running loop:
import asyncio
######## MAIN APP ########
class ExampleApp(App):
def build(self):
#Your app stuff here
async def kivyCoro(self): #This is the method that's gonna launch your kivy app
await self.async_run(async_lib='asyncio')
print('Kivy async app finished...')
async def task2InsideKivyLoop(self): #Here you declare the other task
print('Another task running inside the kivy loop')
await asyncio.sleep(1)
# This func will start all the "tasks", in this case the only task is the kivy app
async def base(self):
(done, pending) = await asyncio.wait({self.kivyCoro(), task2InsideKivyLoop()},
return_when='FIRST_COMPLETED')
if __name__ == '__main__':
instanceApp = ExampleApp() #You have to instanciate your App class
asyncio.run(instanciaApp.base()) # Run in async mode
As you can see, to add another task inside the KivyLoop we just have to declare it as a async method of the App class, then just add it to asyncio.wait()
If you want to run the other task outside the kivyLoop you have to do the fllowing:
import asyncio
######## MAIN APP ########
class ExampleApp(App):
def build(self):
#Your app stuff here
async def kivyCoro(self): #This is the method that's gonna launch your kivy app
await self.async_run(async_lib='asyncio')
print('Kivy async app finished...')
# This func will start all the "tasks", in this case the only task is the kivy app
async def base(self):
(done, pending) = await asyncio.wait({self.kivyCoro()},
return_when='FIRST_COMPLETED')
######### GLOBAL COROUTINE #######
# Here you can import functions from other python files or just declare a global func
async def GlobalTask():
for i in range(10):
print('Other concurrently global task... ',i)
await asyncio.sleep(1)
if __name__ == '__main__':
async def mainThread():
instanceApp = ExampleApp() #Instanciate your App class
a = asyncio.create_task(instanceApp.base()) #Run kivyApp as a task
b = asyncio.create_task(GlobalTask()) #Run Global func as a task
(done, pending) = await asyncio.wait({a}, return_when='FIRST_COMPLETED')
asyncio.run(mainThread())
The examples above would let you do any async task during the kv loop wheter inside the kvLoop or not
The code:
if __name__ == '__main__':
ChatApp().run()
p1 = Process(target=receive)
p1.start()
will run your ChatApp, and then after you close the ChatApp, it will run the receive process. They will not run at the same time because the ChatApp().run() will not return until the ChatApp closes. Try changing the order to:
if __name__ == '__main__':
p1 = Process(target=receive)
p1.start()
ChatApp().run()
So im trying to get a variable added to screen and the id fro that is in a widget Im going to add,
so if for example I have this:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
kv = """
Screen:
cal:cal
side: side
GridLayout:
rows: 1
cols:2
spacing:0
GridLayout:
rows: 5
cols:1
Button:
text: "Cube"
# on_press: app.mode = self.text
on_press: app.setMode(self)
Button:
text: "Cuboid"
on_press: app.setMode(self)
Button:
text: "Cylinder"
on_press: app.setMode(self)
Button:
text: "Cone"
on_press: app.setMode(self)
Button:
text: "Sphere"
on_press: app.setMode(self)
FloatLayout:
Label:
text: "The Volume and surface area of a {}:".format(app.mode)
pos_hint: {"x":0.1, "y":0.8}
text_size: self.size
FloatLayout:
id:cal
Label:
text:"Side:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Volume:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
Label:
text:"Surface Area:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: side
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.65}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.6}
text_size: self.size
"""
cube = """
FloatLayout:
Label:
text:"Side:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Volume:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
Label:
text:"Surface Area:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: side
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.65}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.6}
text_size: self.size"""
cuboid = """
FloatLayout:
id:main
Label:
text:"Length:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Breadth:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
Label:
text:"Height:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: length
text: app.sideText
on_text_validate: app.Cuboid_on_side_change(self)
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.65}
id: breadth
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.6}
id: height
text: app.sideText
on_text_validate: app.Cuboid_on_side_change()
Label:
text: "Volume:"
pos_hint: {"x":1.1, "y":0.55}
text_size: self.size
Label:
text: "Surface Area:"
pos_hint: {"x":1.1, "y":0.5}
text_size: self.size
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.55}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.5}
text_size: self.size"""
cone = """
FloatLayout:
Label:
text:"Radius:"
pos_hint: {"x":1.1, "y":0.7}
text_size: self.size
Label:
text:"Height:"
pos_hint: {"x":1.1, "y":0.65}
text_size: self.size
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.7}
id: Radius
text: app.sideText
on_text_validate: app.Cuboid_on_side_change(self)
TextInput:
size_hint: (.4, None)
height: 26
multiline: False
pos_hint: {"x":1.24, "y":0.65}
id: height
text: app.sideText
on_text_validate: app.Cube_on_side_change(self)
Label:
text: "Volume:"
pos_hint: {"x":1.1, "y":0.6}
text_size: self.size
Label:
text: "Surface Area:"
pos_hint: {"x":1.1, "y":0.55}
text_size: self.size
Label:
text: app.volume
pos_hint: {"x":1.27, "y":0.6}
text_size: self.size
Label:
text: app.surface_area
pos_hint: {"x":1.355, "y":0.55}
text_size: self.size
"""
screens = {
"Cube": cube,
"Cuboid": cuboid,
"Cone": cone
}
class MyApp(App):
sideText = StringProperty("")
surface_area = StringProperty("0 cm²")
volume = StringProperty("0 cm³")
mode = StringProperty("Cube")
def build(self):
self.screen = Builder.load_string(kv)
return self.screen
def setMode(self, btn):
self.volume = "0 cm³"
self.surface_area = "0 cm³"
self.mode = btn.text
self.screen.cal.clear_widgets()
self.screen.cal.add_widget(Builder.load_string(screens[self.mode]))
def Cube_on_side_change(self, instance):
try:
value = float(instance.text)
num = True
except ValueError:
# failed to convert
num = False
print("Numbers only idiot.")
def cubeCalc(val):
return {
"volume": val * val * val,
"surface_area": (val * val) * 6
}
if num:
result = cubeCalc(value)
self.volume = "{:.2f} cm³".format(result["volume"])
self.surface_area = "{:.2f} cm²".format(result["surface_area"])
def Cuboid_on_side_change(self):
height = self.screen.cal.ids.main.height.text
try:
value = float(height)
num = True
except ValueError:
# failed to convert
num = False
print("Numbers only idiot.")
def cubeCalc(val):
return {
"volume": val * val * val,
"surface_area": (val * val) * 6
}
if num:
result = cubeCalc(value)
self.volume = "{:.2f} cm³".format(result["volume"])
self.surface_area = "{:.2f} cm²".format(result["surface_area"])
if __name__ == "__main__":
MyApp().run()
on_text_validate of the TextInput with id:height in the string cuboid, I want to get the text from the text input with something like: self.screen.main.height.text, however, to do that I would have to add main:main and height:height to Screen. How would I do this?
I suggest refactoring your code. Rather than re-inventing the capabilities of ScreenManager, just use ScreenManager. In your kv string, replace the FloatLayout with:
ScreenManager:
CubeScreen:
CuboidScreen:
ConeScreen:
and use your additional kv strings (like cube) as the basis for additional rules in your kv string. Something like:
<CubeScreen>:
Label:
text: "The Volume and surface area of a Cube:"
pos_hint: {"x":0.1, "y":0.8}
text_size: self.size
FloatLayout:
Label:
text:"Side:"
pos_hint: {"x":0.1, "y":0.7}
text_size: self.size
.
.
.
And define each Screen class in your py, like:
class CubeScreen(Screen):
def get_cube_area(self):
.
.
.
And in each of the new classes (like CubeScreen) you can define methods for calculating area, volume, etc, and you can access the TextInputs easily using their ids. And your on_text_validate in each Screen can just call the appropriate method from that Screen (like on_text_validate: root.get_cube_area()).
Not sure where I'm going wrong, When changing the value of MDSlider it should update a label but I receive the error
the kv is loaded as a string within my py file, if I test out the slider by simply printing the value to the console it works. but when I try to update a label get the following error??
AttributeError: 'Level' object has no attribute 'training_level'
here's my code
from kivy.lang import Builder
from kivymd.uix.screen import MDScreen
from kivymd.app import MDApp
KV = """
ScreenManager:
Profile:
Level:
Routine:
Start:
<Profile>:
name: "Profile"
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
source: "bg.jpg"
size: root.width, root.height
pos: self.pos
MDLabel:
text: "Select a Profile"
font_size: "32"
pos_hint: {"center_x": .5, "center_y": .95}
MDRectangleFlatButton:
text: "Guest"
font_size: "32"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.root.current = "Level"
MDBottomAppBar:
MDToolbar:
title: "HIIT"
icon: "account-cog"
type: "bottom"
left_action_items: [["menu", lambda x: x]]
mode: "center"
<Level>:
name: "Level"
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
source: "bg.jpg"
size: root.width, root.height
pos: self.pos
MDLabel:
text: "What is your Level of training?"
font_size: "32"
pos_hint: {"center_x": .5, "center_y": .95}
MDLabel:
id: "training_level"
theme_text_color: "Custom"
text_color: 1,1,1,1
halign: "center"
text: "2"
font_size: "128"
pos_hint: {"center_x": .5, "center_y": .65}
MDSlider:
min: 1
max: 3
value: 2
size: 500, 50
size_hint: None, None
hint: False
step: 1
orientation: "horizontal"
pos_hint: {"center_x": .5, "center_y": .40}
on_value: root.change_height(*args)
MDRectangleFlatButton:
text: "Next"
font_size: "32"
pos_hint: {"center_x": .92, "center_y": .18}
on_release: app.root.current = "Routine"
MDBottomAppBar:
MDToolbar:
title: "HIIT"
icon: "account-cog"
type: "bottom"
left_action_items: [["menu", lambda x: x]]
mode: "center"
<Routine>:
name: "Routine"
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
source: "bg.jpg"
size: root.width, root.height
pos: self.pos
MDLabel:
text: "Select a Routine"
font_size: "32"
pos_hint: {"center_x": .5, "center_y": .95}
MDRectangleFlatButton:
text: "10 Minute Beginner"
font_size: "32"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.root.current = "Start"
MDBottomAppBar:
MDToolbar:
title: "HIIT"
icon: "account-cog"
type: "bottom"
left_action_items: [["menu", lambda x: x]]
mode: "center"
<Start>:
name: "Start"
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
source: "bg.jpg"
size: root.width, root.height
pos: self.pos
MDRectangleFlatButton:
text: "Stop"
font_size: "32"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.root.current = "Profile"
MDBottomAppBar:
MDToolbar:
title: "HIIT"
icon: "account-cog"
type: "bottom"
left_action_items: [["menu", lambda x: x]]
mode: "center"
"""
class Profile(MDScreen):
pass
class Level(MDScreen):
def change_height(self, *args):
#print(str(round(args[1],1)))
self.training_level.text = str(round(args[1],1))
pass
class Routine(MDScreen):
pass
class Start(MDScreen):
pass
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Blue"
return Builder.load_string(KV)
MainApp().run()
I am a beginner and I am trying to make a personality test in kivymd. There are 24 questions where you can choose one of the 4 options (d, i, s, n).
Evaluating the test, I want to write out how many certain letters an user choose. I want to save it to a file. I already write a test name from textfield, but I want it as tuple or list.
I think something like this:
Test1[d=2,i=5,s=8,n=9]
Do you have any idea how can I do that? I tried it with functions d(),.. but it doesn't work
main.py
class ItemConfirm(OneLineAvatarIconListItem):
divider = None
def set_icon(self, choice):
choice.active = True
check_list = choice.get_widgets(choice.group)
for check in check_list:
if check != choice:
check.active = False
class HomeScreen(Screen):
choose_dialog= None
choice = None
help_dialog= None
def show_ChooseDialog(self):
self.choose_dialog = MDDialog(title="Aim:", type="confirmation",
size_hint=[0.9, 0.5], auto_dismiss=False,
items=[ItemConfirm(text="personaly",on_release= self.next_page_me,
on_press= self.close_choose_dialog,)],)
self.choose_dialog.open()
def close_choose_dialog(self, obj):
self.choose_dialog.dismiss()
print(self.choose_dialog.items)
def next_page_me (self,obj):
self.manager.current = "motivationme"
def show_HelpDialog(self):
ok_button = MDRectangleFlatButton (text= "ok",on_release=self.close_help_dialog)
self.help_dialog = MDDialog(title="info about test", text="bla bla",
size_hint=[0.8, 0.5], auto_dismiss=False,
buttons=[ok_button])
self.help_dialog.open()
def close_help_dialog(self,obj):
self.help_dialog.dismiss()
class MotivationScreenMe(Screen):
def add_test(self):
file = open("package.txt", "w")
file.write(self.ids.nazov_testu.text)
class TestConfirm(OneLineAvatarIconListItem):
divider = None
def set_icon(self, choice):
choice.active = True
check_list = choice.get_widgets(choice.group)
for check in check_list:
if check != choice:
check.active = False
class TestScreenV(Screen):
d= 0
i= 0
s=0
n=0
snackbar = None
p = 0
r = 0
def d(self,d):
self.d= d+1
print(d)
def i(self,i):
self.i=i+1
print(i)
def s(self,s):
self.s=s+1
print(s)
def n(self,n):
self.n=n+1
print(n)
def show_example_snackbar(self):
self.snackbar = Snackbar(text="finish?",
snackbar_x="10dp",
snackbar_y="10dp",
bg_color= (0.96,0.79,0.09, 1),)
self.snackbar.size_hint_x = ( Window.width -
(self.snackbar.snackbar_x * 2)) / Window.width
self.snackbar.buttons = [MDFlatButton(text="yes",text_color=(1, 1, 1, 1),
on_release=self.evaluate,
on_press= self.snackbar.dismiss),]
self.snackbar.open()
def evaluate (self,obj):
self.manager.current= "testm"
self.manager.transition.direction = 'left'
def plus(self):
self.p = self.p +4.16
self.ids.progress.value = self.p
class MainApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "Red"
self.theme_cls.primary_hue = "500"
self.theme_cls.theme_style = "Light"
screen = Builder.load_string(screen_helper)
return screen
MainApp().run()
.kv
screen_helper = """
ScreenManager:
HomeScreen:
MotivationScreenMe:
TestScreenV:
<HomeScreen>:
name: "home"
Image:
source: "all.png"
pos_hint: { "center_x" :0.5, "center_y":0.5}
size_hint: (1,1)
MDFloatingActionButton:
icon: "play-circle-outline"
size_hint: None, None
pos_hint: {"center_x" :0.5, "center_y":0.08}
md_bg_color: app.theme_cls.primary_color
on_release: root.show_ChooseDialog()
MDFloatingActionButton:
icon: "help-circle-outline"
md_bg_color: app.theme_cls.primary_color
pos_hint: { "center_x" :0.15, "center_y":0.08}
on_release: root.show_HelpDialog()
<ItemConfirm>
on_release: root.set_icon(check)
CheckboxLeftWidget:
id: check
group: "check"
<MotivationScreenMe>:
name: "motivationme"
nazov_testu: nazov_testu
MDCard:
orientation: "vertical"
pos_hint:{ "center_x" :0.5, "center_y": 0.6}
size_hint: 0.8, 0.7
padding: "8dp"
MDLabel:
text: "why.."
font_size: (root.width**2 + root.height**2) / 13**4
halign: "center"
pos_hint: { "center_x" :0.3, "center_y":0.95}
size_hint: 0.8, 0.1
theme_text_color: "Custom"
text_color: app.theme_cls.primary_color
MDSeparator:
height: "1dp"
MDLabel:
text: "bla bla bla bla bla "
font_size: (root.width**2 + root.height**2) / 13**4
halign: "center"
MDTextField:
id: nazov_testu
hint_text:"nazov_testu(it means) = test_name"
helper_text: "eg. Test 1"
helper_text_mode: "on_focus"
pos_hint: { "center_x" :0.5, "center_y":0.2}
size_hint: 0.8,0.1
MDFloatingActionButton:
icon: "play-circle-outline"
pos_hint: { "center_x" :0.5, "center_y":0.08}
md_bg_color: app.theme_cls.primary_color
on_release:
root.manager.current = "testv"
root.manager.transition.direction = 'up'
on_press: root.add_test()
<TestConfirm>
on_release: root.set_icon(check)
CheckboxLeftWidget:
id: check
<TestScreenV>:
name: "testv"
MDCard:
orientation: "vertical"
padding: "8dp"
size_hint: 0.9,0.7
pos_hint: {"center_x": .5, "center_y": .6}
OneLineListItem:
text: "chose option which fits on you the best"
theme_text_color: "Custom"
text_color: app.theme_cls.primary_color
font_size: (root.width**2 + root.height**2) / 13**4
ScrollView:
do_scroll_x: False
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: dp(350)
OneLineListItem:
text: "1/24 "
theme_text_color: "Custom"
text_color: app.theme_cls.primary_color
TestConfirm:
text: "option which means point s"
font_size: (root.width**2 + root.height**2) / 13**4
on_press:
root.plus()
root.s()
TestConfirm:
text: "option which means point n"
font_size: (root.width**2 + root.height**2) / 13**4
on_press:
root.plus()
root.n()
TestConfirm:
text: "option which means point d"
font_size: (root.width**2 + root.height**2) / 13**4
on_press:
root.plus()
root.d()
TestConfirm:
text: "option i"
font_size: (root.width**2 + root.height**2) / 13**4
on_press:
root.plus()
root.i()
MDFloatingActionButton:
icon: "check-circle-outline"
pos_hint: { "center_x" :0.5, "center_y":0.08}
md_bg_color: app.theme_cls.primary_color
on_release: root.show_example_snackbar()
MDProgressBar:
id: progress
size_hint_x: 0.8
size_hint_y: 0.08
color: app.theme_cls.accent_color
pos_hint: { "center_x" :0.5, "center_y":0.2}