I'm currently doing a school project and I can't use .kv files; so I have to do it through normal python. So, I'm converting my previous .kv file, but I'm unsure on how to create multiple screens and add buttons in normal python. Any help is greatly appreciated.
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
#App windows
class MainMenu(Screen, Button, BoxLayout):
# def __init__(self, **kwargs):
# super(MainMenu, self).__init__(**kwargs)
menu_s = Screen(name = 'main')
layout = BoxLayout(orientaion = 'vertical')
slider_mode = Button(text = 'Slider Mode')
code_mode = Button(text = 'Code Mode')
settings = Button(text = 'Settings')
menu_s.add_widget(slider_mode)
menu_s.add_widget(code_mode)
menu_s.add_widget(settings)
class SliderMode(Screen):
slider_s = Screen(name = 'slider_m')
layout = BoxLayout(orientaion = 'vertical')
menu = Button(text = 'Menu')
slider_s.add_widget(menu)
WindowManager = ScreenManager()
WindowManager.add_widget(MainMenu())
WindowManager.add_widget(SliderMode())
#The app class
class MyMain(App):
def build(self):
return WindowManager
#Runs the App
if __name__ == '__main__':
MyMain().run()
The above code is what I've done so far; but when it's run, it gives this error:
TypeError: object.__init__() takes exactly one argument (the instance to initialize)
This is the .kv file below I'm trying to convert:
WindowManager:
MainMenu:
SliderMode:
<MainMenu>:
name: 'main'
BoxLayout:
orientation: 'vertical'
cols: 1
Button:
text: 'Slider Mode'
size_hint: 0.3, 0.3
pos_hint: {'x':0.35}
on_release:
app.root.current = 'slider_m'
Button:
text: 'Code Mode'
size_hint: 0.3, 0.3
pos_hint: {'x':0.35}
on_release:
app.root.current = 'code_m'
Button:
text: 'Settings'
size_hint: 0.3, 0.3
pos_hint: {'x':0.35}
on_release:
app.root.current = 'setting_m'
<SliderMode>:
name: 'slider_m'
FloatLayout:
Button:
text: 'Menu'
size_hint: 0.15, 0.15
pos_hint: {'x':0.0, 'y': 0.0}
on_release:
app.root.current = 'main'
It seems that you do not have basic knowledge of OOP since for example you are implementing the inheritance instead of the composition so I recommend you check Difference between Inheritance and Composition, in your case for example MainMenu has a BoxLayout, it is not a BoxLayout.
On the other hand the kv language seems to tolerate errors, which for me is a bug, since BoxLayout does not have a property called cols, instead python is more restrictive so you should not use that variable.
Considering the above, the solution is:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
class MainMenu(Screen):
def __init__(self):
super(MainMenu, self).__init__(name="main")
box_lay = BoxLayout(orientation="vertical")
self.add_widget(box_lay)
button_1 = Button(
text="Slider Mode",
size_hint=(0.3, 0.3),
pos_hint={"x": 0.35},
on_release=self.on_released_1,
)
button_2 = Button(
text="Code Mode",
size_hint=(0.3, 0.3),
pos_hint={"x": 0.35},
on_release=self.on_released_2,
)
button_3 = Button(
text="Code Mode",
size_hint=(0.3, 0.3),
pos_hint={"x": 0.35},
on_release=self.on_released_3,
)
box_lay.add_widget(button_1)
box_lay.add_widget(button_2)
box_lay.add_widget(button_3)
def on_released_1(self, *args):
App.get_running_app().root.current = "slider_m"
# or
# self.manager.current = "slider_m"
def on_released_2(self, *args):
App.get_running_app().root.current = "code_m"
# or
# self.manager.current = "code_m"
def on_released_3(self, *args):
App.get_running_app().root.current = "setting_m"
# or
# self.manager.current = "setting_m"
class SliderMode(Screen):
def __init__(self):
super(SliderMode, self).__init__(name="slider_m")
float_lay = FloatLayout()
self.add_widget(float_lay)
button = Button(
text="Menu",
size_hint=(0.15, 0.15),
pos_hint={"x": 0.0, "y": 0.0},
on_release=self.on_released,
)
float_lay.add_widget(button)
def on_released(self, *args):
App.get_running_app().root.current = "main"
# or
# self.manager.current = "main"
manager = ScreenManager()
manager.add_widget(MainMenu())
manager.add_widget(SliderMode())
# The app class
class MyMain(App):
def build(self):
return manager
# Runs the App
if __name__ == "__main__":
MyMain().run()
Related
I am creating myself a GPA calculator using python kivy and I am trying to switch the text of a label but it is not working. I could use some help. I am only going to show the code that I require to change the text, but if you need it all, I am happy to send it through.
.py file:
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.popup import Popup
class main(Screen):
def add_class(self):
sm.current = 'add'
sm.transition.direction = 'left'
def remove_class(self):
sm.current = 'remove'
sm.transition.direction = 'right'
def update(self):
#from the screen that adds the courses
courses = AddClass.courses
marks = []
for key in courses:
marks.append(courses[key])
total = 0.0
for i in marks:
total += i
total /= len(marks)
#print(total)
self.ids.gpa.text = f'{total}/4.0'
class MyApp(App):
def build(self):
#main screen
sm.add_widget(main(name='main'))
#screen that adds the marks
sm.add_widget(AddClass(name='add'))
#screen that removes a certain mark
sm.add_widget(RemoveClass(name='remove'))
sm.current = 'main'
return sm
if __name__ == '__main__':
MyApp().run()
.kv file:
<main>
FloatLayout:
Button:
text: 'Your GPA'
font_size: 50
size_hint: 0.4, 0.4
pos_hint: {'x': 0.3, 'y': 0.6}
id: gpa
background_color: 0, 0, 0
on_release: print(self.text)
Button:
text: 'Remove Class/Course'
font_size: 28
id: remove_class
size_hint: 0.4, 0.4
pos_hint: {'y': 0.1, 'x': 0.05}
on_release: root.remove_class()
Button:
text: 'Add Class/Course'
font_size: 30
id: add_class
size_hint: 0.4, 0.4
pos_hint: {'y': 0.1, 'x': 0.55}
on_release: root.add_class()
Help is much appreciated!
Text of a label can be a kivy property, which can be later changed and since it is a kivy property it will automatically update everywhere. Here is an example of .py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
import random
class YourWidget(Widget):
random_number = StringProperty()
def __init__(self, **kwargs):
super(YourWidget, self).__init__(**kwargs)
self.random_number = str(random.randint(1, 100))
def change_text(self):
self.random_number = str(random.randint(1, 100))
class YourApp(App):
def build(self):
return YourWidget()
if __name__ == '__main__':
YourApp().run()
and .kv example
<YourWidget>:
BoxLayout:
size: root.size
Button:
id: button1
text: "Change text"
on_release: root.change_text()
Label:
id: label1
text: root.random_number
When you click the button, it will call the change_text() function, which will randomly change the text of the label to a random integer between 1 and 100.
I'm new here, I have a small problem in kivymd. Is there anyone here who would be able to help me?
this is my main.py file
from kivymd.app import MDApp
from kivymd.theming import ThemeManager
from kivymd.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.label import MDLabel
from kivymd.uix.toolbar import MDToolbar
from kivymd.uix.textfield import MDTextField
class rendertime(BoxLayout):
def init(self, kwargs):
super().init(kwargs)
self.padding = "30dp"
self.orientation = 'vertical'
self.spacing = "10dp"
self.top_name = MDToolbar(title = "my app")
self.how_many_text = MDLabel(text = "my label")
self.how_many = MDTextField(text = "1")
self.add_widget(self.top_name)
self.add_widget(self.how_many_text)
self.add_widget(self.how_many)
self.hour_value = MDLabel(text = "0")
self.add_widget(self.hour_value)
self.hours_slider = Slider(min = 0, max = 24)
self.add_widget(self.hours_slider)
self.hours_slider.bind(value = self.on_value_hours)
def on_value_hours(self, instance, slider):
self.hour_value.text = "%d"%slider
class myapp(MDApp):
title = "my app v"
def build(self):
self.theme_cls = ThemeManager()
self.theme_cls.primary_palette = 'Orange'
self.theme_cls.theme_style = 'Dark'
return rendertime()
if name== "main":
myapp().run()
Now I would like to switch screens for this. Add 2 buttons at the very bottom and they are to switch to the next screen. I don't want to use the .kv file I wanted to do everything in class.
I don't want to use
kv = """
MDTextField:
id: frame
hint_text: "text"
"""
Please, if anyone can explain it to me, I would be very grateful. Thank you and have a nice day. Good luck everyone
this is a screenmanager file transition.kv
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.lang import Builder
Builder.load_file("transition.kv")
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class Screen3(Screen):
pass
class Screen4(Screen):
pass
class MainApp(MDApp):
def build(self):
self.sm = ScreenManager(transition = NoTransition())
self.sm.add_widget(Screen1(name = "Screen1"))
self.sm.add_widget(Screen2(name = "Screen2"))
self.sm.add_widget(Screen3(name = "Screen3"))
return self.sm
def change_screen(self, screen):
self.sm.current = screen
if __name__ == "__main__":
MainApp().run()
and kv file
<Screen1>:
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "My App"
MDRoundFlatButton:
text: "Go to Screen 2"
on_release: app.root.current = "Screen2"
MDRoundFlatButton:
text: "Go to Screen 3"
on_release: app.root.current = "Screen3"
MDLabel:
text: "Screen 1"
<Screen2>:
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "Screen 2"
left_action_items: [["arrow-left", lambda x: app.change_screen("Screen1")]]
MDLabel:
text: "Screen 2"
<Screen3>:
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "Screen 3"
left_action_items: [["arrow-left", lambda x: app.change_screen("Screen1")]]
MDLabel:
text: "Screen 3
Just don't know how to connect these code
This is a solution only one python file
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.core.window import Window
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.uix.scrollview import ScrollView
from kivymd.uix.list import MDList, OneLineListItem
class Screen1(Screen):
def __init__(self, **kwargs):
super(Screen1, self).__init__(**kwargs)
layout = FloatLayout()
btn = Button(text = "screen 2", size_hint = (None,None), size = (100,100), pos_hint = {'x':0,'y':0}, on_release = self.screen_switch)
layout.add_widget(btn)
self.add_widget(layout)
def screen_switch(self, instance):
self.manager.current = 's2'
self.manager.transition.direction = 'left'
class Screen2(Screen):
def __init__(self, **kwargs):
super(Screen2, self).__init__(**kwargs)
layout = FloatLayout()
btn = Button(text = "screen 1", size_hint = (None,None), size = (100,100), pos_hint = {'x':0,'y':0}, on_release = self.screen_switch)
layout.add_widget(btn)
self.add_widget(layout)
myb = MDBoxLayout(padding = 50, orientation = 'vertical')
mys = ScrollView()
myl = MDList()
myb.add_widget(mys)
mys.add_widget(myl)
contacts = ["c1", "c2", "c3"]
for c in contacts:
myl.add_widget(
OneLineListItem(
text = c
)
)
self.add_widget(myb)
def screen_switch(self, instance):
self.manager.current = 's1'
self.manager.transition.direction = 'right'
class myapp(MDApp):
def build(self):
self.theme_cls.theme_style = 'Dark'
sm = ScreenManager()
sm.add_widget(Screen1(name = 's1'))
sm.add_widget(Screen2(name = 's2'))
return sm
if __name__ == "__main__":
The issue is a simple one, getting Kivy to integrate the Timer1 code as a label in FloatLayout.
I have this .py file:
import kivy
kivy.require('1.10.0')
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.stacklayout import StackLayout
from kivy.clock import Clock
from kivy.properties import StringProperty, NumericProperty, ObjectProperty
from digitalclock import DigitalClock
from kivy.animation import Animation
import time
class IntroScreen(Screen):
pass
class ContScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
backbone = Builder.load_file("main.kv")
class Status(FloatLayout):
_change = StringProperty()
_tnd = ObjectProperty(None)
def update(self, *args):
self.time = time.asctime()
self._change = str(self.time)
self._tnd.text = str(self.time)
print (self._change)
class Timer1(Label):
a = NumericProperty(10) # seconds
color = 1, 1, 1, 1
font_size = 50
def start(self):
Animation.cancel_all(self) # stop any current animations
self.anim = Animation(a=0, duration=self.a)
def finish_callback(animation, incr_crude_clock):
incr_crude_clock.text = "COOL"
self.anim.bind(on_complete=finish_callback)
self.anim.start(self)
def on_a(self, instance, value):
self.text = str(round(value, 1))
class XGApp(App):
time = StringProperty()
def update(self, *args):
self.time = str(time.asctime())
def build (self):
Clock.schedule_interval(self.update, 1)
t1 = Timer1()
return backbone
xApp = XGApp()
if __name__ == "__main__":
xApp.run()
and the .kv:
<ContScreen>:
DigitalClock:
pos_hint: {'center_x': 0.1, 'center_y': 0.9}
size_hint: (0.075, 0.075)
StackLayout
orientation: "tb-rl"
spacing: 15
Button:
text: "1"
size_hint: None, .16
width: 225
on_press:
self.background_color = (1.7, 0, 1.7, 1)
t1.start()
I am trying to get the Timer1 aspect as a label in FloatLayout on the .kv, which appears as the button is triggered. At the moment, what I've been getting is the Timer1 as a full-screen label.
Please help!
Solution
Move the design view of Timer's Label from Python code into kv file.
Add constructor for class Timer and accepts arguments, root, instance, duration, bg_colour
In kv file, pass arguments root (screen 'cont'), instance of button, duration, background colour when instantiating Timer
In build method, remove t1 = Timer1()
Example
main.py
import kivy
kivy.require('1.11.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
from kivy.properties import StringProperty, NumericProperty, ObjectProperty
from kivy.animation import Animation
import time
class IntroScreen(Screen):
pass
class ContScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class Status(FloatLayout):
_change = StringProperty()
_tnd = ObjectProperty(None)
def update(self, *args):
self.time = time.asctime()
self._change = str(self.time)
self._tnd.text = str(self.time)
print (self._change)
class Timer(Label):
a = NumericProperty() # seconds
def __init__(self, root, instance, duration, bg_colour, **kwargs):
super(Timer, self).__init__(**kwargs)
self.obj = instance
self.a = duration
self.root = root
self.obj.disabled = True # disable widget/button
self.obj.background_color = bg_colour
self.root.add_widget(self) # add Timer/Label widget to screen, 'cont'
def animation_complete(self, animation, widget):
self.root.remove_widget(widget) # remove Timer/Label widget to screen, 'cont'
self.obj.background_color = [1, 1, 1, 1] # reset to default colour
self.obj.disabled = False # enable widget/button
def start(self):
Animation.cancel_all(self) # stop any current animations
self.anim = Animation(a=0, duration=self.a)
self.anim.bind(on_complete=self.animation_complete)
self.anim.start(self)
def on_a(self, instance, value):
self.text = str(round(value, 1))
class XGApp(App):
time = StringProperty()
def update(self, *args):
self.time = str(time.asctime())
def build (self):
Clock.schedule_interval(self.update, 1)
return Builder.load_file("main.kv")
if __name__ == "__main__":
XGApp().run()
kv file
#:import DigitalClock digitalclock
#:import Timer main.Timer
<ContScreen>:
DigitalClock:
pos_hint: {'center_x': 0.1, 'center_y': 0.9}
size_hint: (0.075, 0.075)
StackLayout
orientation: "tb-rl"
spacing: 15
Button:
text: "1"
size_hint: None, .16
width: 225
on_press:
Timer(root, self, 5, [0.17, 1.7, 0, 1]).start()
Button:
text: "2"
size_hint: None, .16
width: 225
on_press:
Timer(root, self, 10, [1.7, 0, 1.7, 1]).start()
<Timer>:
canvas.before:
Color:
rgba: 0, 0, 0.5, 1 # 50% blue
Rectangle:
size: self.size
pos: self.pos
size_hint: 0.3, .1
font_size: 50
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
Output
One way to make it work is to have the Button create the timer. Start by adding a start_timer() method to the ContScreen class:
class ContScreen(Screen):
def start_timer(self, *args):
timer = Timer1(size_hint=(0.2, 0.2))
self.add_widget(timer)
timer.start()
For this to work, make three other changes:
Change your main.kv file to make a root widget (eliminate the <> surrounding ContScreen).
Change the on_press for the button in the .kv file by replacing t1.start() with root.start_timer().
Eliminate the t1 = Timer1() statement from your build method in the XGApp class.
Another approach would be to create the Timer1 in the .kv file, and just start it running when the Button is pressed. To do this, change your .kv file to include a Timer:
ContScreen:
DigitalClock:
pos_hint: {'center_x': 0.1, 'center_y': 0.9}
size_hint: (0.075, 0.075)
StackLayout
orientation: "tb-rl"
spacing: 15
Button:
text: "1"
size_hint: None, .16
width: 225
on_press:
self.background_color = (1.7, 0, 1.7, 1)
timer.start()
Timer1:
id: timer
text: '0.0'
size_hint: (0.2, 0.2)
Move your backbone = Builder.load_file("main.kv") to after the definition of the Timer1 class. And change the ContScreen class back to:
class ContScreen(Screen):
pass
I am trying to make a screen view with buttons. The problem is that the amount of buttons needed each time will change, therefore I am not able to use the kv file to make theses buttons. I am having trouble adding buttons through the normal python code. Any help is appreciated.
import kivy
import webbrowser
import MSQLHandler
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Label
from kivy.uix.widget import Widget
from kivy.uix.listview import ListItemButton
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition, CardTransition, SwapTransition, FadeTransition, WipeTransition, FallOutTransition, RiseInTransition, NoTransition
from kivy.lang import Builder
from kivy.uix.button import Button
class Login_Failed(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Loged_In(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Registers(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Login_Screen(Screen):
teacher_connect_image = ObjectProperty()
username_text_input = ObjectProperty()
password_text_input = ObjectProperty()
teacherid_text_input = ObjectProperty()
def LoginButton(self):
if self.teacherid_text_input.text == "":
Number = 0
else:
Number = int(self.teacherid_text_input.text)
MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number)
def changeScreen(self, next_screen):
self.manager.current = next_screen
if MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number) is True:
print("Returns True")
changeScreen(self, "Loged_In")
elif MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number) is False:
print("Returns False")
changeScreen(self, "Login_Failed")
else:
print("Null")
class ScreenManagerr(ScreenManager):
pass
class MainKivyFrameApp(App):
def build(self):
Registers().add_widget(Button(text="Helpp"))
return ScreenManagerr()
mainFrame = MainKivyFrameApp()
mainFrame.run()
If you look to where the app is being built, you will see: Registers().add_widget(Button(text="Helpp"))
This is where I have tried to add a Button to the screen of Registers. This doesn't give me any errors, but it still does not show the button.
Solution
In the kv file, add an event (on_enter or on_pre_enter) in each screen and bind it to a callback method as shown in the following snippets and example. Remember to remove the widgets that were added dynamically before leaving the current screen, by adding an event (on_leave or on_pre_leave).
Snippets
<Registers>:
on_pre_enter: self.add_buttons(n)
on_leave: self.remove_buttons()
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.properties import ObjectProperty, NumericProperty
class MyScreenManager(ScreenManager):
total_button = NumericProperty(2)
class Login(Screen):
login = ObjectProperty(None)
def on_pre_enter(self):
Window.size = (400, 300)
def check_password(self, instance, password):
if password == "pwd":
instance.current = "registers"
class Registers(Screen):
container = ObjectProperty(None)
def on_pre_enter(self):
Window.size = (800, 600)
def add_buttons(self, n):
print("Registers: n={}".format(n))
for i in range(n):
self.container.add_widget(Button(text="Button #{}".format(i), id=str(i)))
def remove_buttons(self, *args):
for child in [child for child in self.container.children]:
self.container.remove_widget(child)
class Welcome(Screen):
pass
class TestApp(App):
title = "ScreenManager - Add Widgets Dynamically"
def build(self):
return MyScreenManager()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
#:import SwapTransition kivy.uix.screenmanager.SwapTransition
<MyScreenManager>:
transition: SwapTransition()
Login:
Registers:
on_pre_enter:
self.add_buttons(app.root.total_button)
on_leave:
self.remove_buttons()
Welcome:
<Login>:
id: login
name: "login"
login: login
GridLayout:
size_hint: (0.5, 0.5)
pos_hint: {"center_x": 0.5, "center_y": 0.6}
rows: 3
padding: 20
Label:
size_hint: (0.2, 0.2)
text:"Password:"
font_size: 30
halign: "center"
valign: "middle"
TextInput:
id: password
size_hint: (0.2, 0.06)
cursor_blink: True
font_size: 20
multiline: False
password: True
Button:
text: "Continue"
size_hint: (0.2, 0.08)
on_release:
root.login.check_password(root.manager, password.text)
<Registers>:
name:'registers'
container: container
BoxLayout:
orientation: 'vertical'
Button:
text: 'Return to Login'
on_press: root.manager.current = 'login'
Button:
text: 'Next Screen'
on_press: root.manager.current = 'welcome'
BoxLayout:
id: container
orientation: 'vertical'
<Welcome>:
name:'welcome'
BoxLayout:
Label:
text: 'Welcome!'
Button:
text: 'Return to Registers'
on_press:
app.root.total_button = 5
root.manager.current = 'registers'
Output
This is mostly me not grasping object oriented programming, but involving the clock function
I want my GUI to have a button that starts a constantly updating function (scheduled using the clock function). And also want that GUI to have a button that ends the constantly updating function. (or is there a better way to accomplish this? put it in an if statement? boolean that changes when I press that button, would that value update on the python side?)
import kivy
import sqlite3
import sched, time
import smbus
import time
from Naked.toolshed.shell import execute_js, muterun_js
import os
import signal
import multiprocessing, signal
from kivy.uix.behaviors.button import ButtonBehavior
from kivy.uix.button import Button
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.base import runTouchApp
from kivy.clock import Clock
from kivy.properties import ListProperty
from kivy.properties import ObjectProperty
from kivy.vector import Vector
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.event import EventDispatcher
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.stacklayout import StackLayout
from kivy.core.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition, WipeTransition, SwapTransition
bus = smbus.SMBus(1)
address = 0x04
p = multiprocessing.Process(target = muterun_js,args=('iss_telemetry.js',)) #might delete this
conn = sqlite3.connect('iss_telemetry.db') #sqlite database call change to include directory
c = conn.cursor()
val = ""
def StringToBytes(val):
retVal = []
for c in val:
retVal.append(ord(c))
return retVal
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
class CalibrateScreen(Screen):
pass
class ManualControlScreen(Screen):
def __init__(self, **kwargs):
super(ManualControlScreen, self).__init__(**kwargs)
def i2cWrite(self, *args):
bus.write_i2c_block_data(address, 0, StringToBytes(*args))
class MimicScreen(Screen, EventDispatcher):
def __init__(self, **kwargs):
super(MimicScreen, self).__init__(**kwargs)
class MainScreenManager(ScreenManager):
pass
class MyButton(Button):
pass
def point_inside_polygon(x, y, poly):
...
class TriangleButton(ButtonBehavior, Widget):
...
class MainApp(App):
event = Clock.schedule_interval(self.update_labels, 1)
event()
event.cancel()
def build(self):
self.mimic_screen = MimicScreen(name = 'mimic')
root = ScreenManager(transition=WipeTransition())
root.add_widget(MainScreen(name = 'main'))
root.add_widget(CalibrateScreen(name = 'calibrate'))
root.add_widget(self.mimic_screen)
root.add_widget(ManualControlScreen(name = 'manualcontrol'))
root.current= 'main'
# Clock.schedule_interval(self.update_labels, 1)
return root
def clockStart(self):
event()
def clockEnd(self):
event.cancel()
def i2cWrite(self, *args):
bus.write_i2c_block_data(address, 0, StringToBytes(*args))
def update_labels(self, dt):
c.execute('select two from telemetry')
values = c.fetchall()
psarj = values[0]
ssarj = values[1]
ptrrj = values[2]
strrj = values[3]
beta1b = values[4]
beta1a = values[5]
beta2b = values[6]
beta2a = values[7]
beta3b = values[8]
beta3a = values[9]
beta4b = values[10]
beta4a = values[11]
aos = values[12]
self.mimic_screen.ids.psarjvalue.text = str(psarj[0])[:-5]
self.mimic_screen.ids.ssarjvalue.text = str(ssarj[0])[:-5]
self.mimic_screen.ids.ptrrjvalue.text = str(ptrrj[0])[:-5]
self.mimic_screen.ids.strrjvalue.text = str(strrj[0])[:-5]
self.mimic_screen.ids.beta1bvalue.text = str(beta1b[0])[:-5]
self.mimic_screen.ids.beta1avalue.text = str(beta1a[0])[:-5]
self.mimic_screen.ids.beta2bvalue.text = str(beta2b[0])[:-5]
self.mimic_screen.ids.beta2avalue.text = str(beta2a[0])[:-5]
self.mimic_screen.ids.beta3bvalue.text = str(beta3b[0])[:-5]
self.mimic_screen.ids.beta3avalue.text = str(beta3a[0])[:-5]
self.mimic_screen.ids.beta4bvalue.text = str(beta4b[0])[:-5]
self.mimic_screen.ids.beta4avalue.text = str(beta4a[0])[:-5]
Builder.load_string('''
#:kivy 1.8
#:import kivy kivy
#:import win kivy.core.window
<MainScreen>:
...
<ManualControlScreen>:
...
<CalibrateScreen>:
...
<MimicScreen>:
name: 'mimic'
FloatLayout:
psarjvalue: psarjvalue
id: mimicscreenlayout
Image:
source: 'iss1.png'
allow_stretch: True
keep_ratio: False
...
Button:
id: mimicstartbutton
size_hint: 0.25,0.1
pos_hint: {"x": 0.07, "y": 0.6}
text: 'MIMIC'
disabled: False
font_size: 30
on_release: telemetrystatus.text = 'Sending Telemetry...'
on_release: app.clockStart()
on_release: mimicstopbutton.disabled = False
on_release: mimicstartbutton.disabled = True
Button:
id: mimicstopbutton
size_hint: 0.25,0.1
pos_hint: {"x": 0.07, "y": 0.4}
text: 'Stop'
disabled: True
font_size: 30
on_release: telemetrystatus.text = 'I2C Stopped'
on_release: app.clockStop()
on_release: mimicstopbutton.disabled = True
on_release: mimicstartbutton.disabled = False
Button:
size_hint: 0.3,0.1
pos_hint: {"Left": 1, "Bottom": 1}
text: 'Return'
font_size: 30
on_release: app.clockStop()
on_release: root.manager.current = 'main'
<TriangleButton>:
...
''')
if __name__ == '__main__':
MainApp().run()
Here's the relevant class:
class MainApp(App):
event = Clock.schedule_interval(self.update_labels, 1)
event()
event.cancel()
def build(self):
self.mimic_screen = MimicScreen(name = 'mimic')
root = ScreenManager(transition=WipeTransition())
root.add_widget(MainScreen(name = 'main'))
root.add_widget(CalibrateScreen(name = 'calibrate'))
root.add_widget(self.mimic_screen)
root.add_widget(ManualControlScreen(name = 'manualcontrol'))
root.current= 'main'
# Clock.schedule_interval(self.update_labels, 1)
return root
def clockStart(root):
event()
def clockEnd(root):
event.cancel()
def i2cWrite(self, *args):
bus.write_i2c_block_data(address, 0, StringToBytes(*args))
def update_labels(self, dt):
...
And here's the relevant part of the kv code (reduced)
<MimicScreen>:
name: 'mimic'
FloatLayout:
...
Button:
...
on_release: app.clockStart()
Button:
...
on_release: app.clockStop()
Button:
...
on_release: app.clockStop()
So when I try to run it like this it complains about not knowing what event is. I was under the impressing that declaring it outside the class functions would make it available to the whole class.
Suggestions? Advice? Thanks for any help
It's complaining because you need to define a variable as global to use it inside a function you haven't passed it into or attach it to the object with self.varname. Moreover, you're creating the event and then cancelling it right away before build has been called.
You should have a button that has a method on_release that starts a schedule_interval functional call with Clock. This button should become disabled after being pressed. Your second button will then unschedule using cancel.
Here's a basic working example:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.clock import Clock
class MyLayout(BoxLayout):
pass
class StartButton(Button):
def on_release(self):
self.event_handle = Clock.schedule_interval(self.clocks_are_fun,0.5)
self.disabled = True
def clocks_are_fun(self,dt):
self.parent.parent.ids.mylabel.text = 'Frames: ' + str(Clock.frames)
def closing_time(self):
self.event_handle.cancel()
class StopButton(Button):
def on_release(self):
self.parent.parent.ids.button1.closing_time()
self.parent.parent.ids.button1.disabled = False
class MyApp(App):
def build(self):
boxyFunTime = MyLayout()
return boxyFunTime
if __name__ == '__main__':
MyApp().run()
And the .kv file:
<MyLayout>:
id: mylayoutid
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
StartButton:
text: 'start'
id: button1
StopButton:
text: 'stop'
id: button2
Label:
id: mylabel