#python #arduino #kivy
#python #arduino #kivy
Вопрос:
Итак, я хотел прочитать данные из моего Arduino
через serial port
и обновить данные, которые я прочитал, до текста метки для отображения. Он работает, когда у меня есть только простой код для чтения и обновления, но когда я добавляю ScreenManager
и Screen
, он перестает обновлять текст.
В конечном итоге мне понадобится другая анимация в соответствии с полученными данными, это больше для тестирования, работает ли эта функция
Заранее спасибо!
Вот весь мой код
import os
os.environ['KIVY_GL_BACKEND'] ='gl'
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import (NumericProperty, StringProperty, ReferenceListProperty, ObjectProperty, ListProperty)
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.core.text import LabelBase
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
LabelBase.register(name='Sans',fn_regular="Sansation-Regular.ttf")
import serial
kivy = Builder.load_string("""
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<MyManager>:
transition: FadeTransition()
MainScreen:
OperationScreen:
<MainScreen>:
name: 'main'
Label:
text: 'Welcome'
font_size: 40
on_touch_up : app.root.current = 'operation'
Label:
text: 'dafault'
font_size: 20
pos: -200,-100
id: data_label
<OperationScreen>:
name: 'operation'
Label:
text: 'Youre in'
font_size: 40
""")
class OperationScreen(Screen):
pass
class MainScreen(Screen):
def __init__(self,**kwargs):
super(MainScreen,self).__init__(**kwargs)
def Read(self,dt):
Clock.unschedule(self.Read)
data = arduino.readline()
if data != '':
self.ids.data_label.text = data
Clock.schedule_once(self.Read)
pass
class MyManager(ScreenManager):
pass
class mainApp(App):
Main = MainScreen()
def build(self):
Clock.schedule_once(self.Main.Read)
return MyManager()
if __name__ == '__main__':
try:
arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
except:
print("failed to connect")
mainApp().run()
Я ожидаю, что метка с текстом «по умолчанию» будет изменяться соответствующим образом, но она просто замерла с значением «по умолчанию»
Ответ №1:
Проблема
При запуске вашего приложения есть два экземпляра class MainScreen
. Один из них был создан в файле kv. Другой экземпляр был создан вручную, Main = MainScreen()
в class mainApp
.
Планирование метода Read()
выполняется в экземпляре, созданном вручную, Main = MainScreen()
и с этим не связано модальное представление.
Решение
- В файле kv добавьте
id: main_screen
дляMainScreen:
- Удалить
Main = MainScreen()
вclass mainApp
- Реализовать конструктор для
class MyManager()
- Переместите планирование из
class mainApp
в конструкторclass MyManager()
- В вашем случае лучше использовать
Clock.create_trigger()
вместоClock.schedule_once()
- Правильный способ отменить событие синхронизации — это либо
event.cancel()
, либоClock.unschedule(event)
Пример
main.py
import os
os.environ['KIVY_GL_BACKEND'] = 'gl'
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import (NumericProperty, StringProperty, ReferenceListProperty, ObjectProperty, ListProperty)
from kivy.clock import Clock
from kivy.vector import Vector
from kivy.core.text import LabelBase
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
# LabelBase.register(name='Sans', fn_regular="Sansation-Regular.ttf")
import serial
kivy = Builder.load_string("""
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
<MyManager>:
transition: FadeTransition()
MainScreen:
id: main_screen
OperationScreen:
<MainScreen>:
name: 'main'
Label:
text: 'Welcome'
font_size: 40
on_touch_up : app.root.current = 'operation'
Label:
text: 'dafault'
font_size: 20
pos: -200,-100
id: data_label
<OperationScreen>:
name: 'operation'
Label:
text: 'Youre in'
font_size: 40
""")
class OperationScreen(Screen):
pass
class MainScreen(Screen):
def Read(self, dt):
data = str(dt)
# data = arduino.readline()
if data != '':
self.ids.data_label.text = data
self.manager.event_trigger()
else:
self.manager.event_trigger.cancel()
class MyManager(ScreenManager):
event_trigger = ObjectProperty(None)
def __init__(self, **kwargs):
super(MyManager, self).__init__(**kwargs)
self.event_trigger = Clock.create_trigger(self.ids.main_screen.Read)
self.event_trigger()
class mainApp(App):
def build(self):
return MyManager()
if __name__ == '__main__':
# try:
# arduino = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
# except:
# print("failed to connect")
mainApp().run()
Вывод
Комментарии:
1. Спасибо за ответ! Не могли бы вы рассказать мне немного о том, когда мы будем использовать
def __init__(self, **kwargs):
иsuper(MyManager, self).__init__(**kwargs)
2. Внедряйте конструктор
__init__()
всякий раз, когда вы хотите, чтобы что-то было сделано один раз во время создания экземпляра. Например, инициализировать атрибуты класса, получать аргументы, переданные от вызывающего объекта, создавать триггер события и т.д.3. Пожалуйста, не забудьте принять ответ и / или проголосовать за него. Спасибо.