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
Related
My app display file names with path in a Label and sometimes the file name is to big to fit in the screen so my first thought was to use a Marquee but couldn't find any widget with that functionality.
Any way to do it?
Interesting problem. Here is a first cut at a Marquee widget:
from kivy import Config
import os
from ast import literal_eval
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, BooleanProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
from kivy.core.text import Label as CoreLabel
if 'KIVY_DOC' not in os.environ:
_default_font_paths = literal_eval(Config.get('kivy', 'default_font'))
DEFAULT_FONT = _default_font_paths.pop(0)
else:
DEFAULT_FONT = None
Builder.load_string('''
<Marquee>:
StencilView:
id: sten
pos: root.pos
size_hint: None, None
size: root.size
Image:
id: label
texture: root.texture
pos: root.pos
size_hint: None, None
size: self.texture_size
''')
class Marquee(FloatLayout):
texture = ObjectProperty()
text = StringProperty()
duration = NumericProperty(2)
font_name = StringProperty(DEFAULT_FONT)
font_size = NumericProperty(12)
bold = BooleanProperty(False)
italic = BooleanProperty(False)
padding = NumericProperty(0)
def __init__(self, **kwargs):
super(Marquee, self).__init__(**kwargs)
self.anim = None
self.x_original = None
fbind = self.fbind
redraw = self.redraw
fbind('text', redraw)
fbind('duration', redraw)
fbind('font_name', redraw)
fbind('font_size', redraw)
fbind('bold', redraw)
fbind('italic', redraw)
fbind('padding', redraw)
def on_x(self, *args):
self.x_original = self.x
Clock.schedule_once(self.redraw)
def redraw(self, *args):
if self.x_original is None:
return
if self.text == '':
self.texture = None
return
label = CoreLabel(text=self.text, font_name=self.font_name, font_size=self.font_size,
bold=self.bold, italic=self.italic, padding=self.padding)
label.refresh()
self.texture = label.texture
Clock.schedule_once(self.do_anim)
def do_anim(self, *args):
if self.anim is not None:
self.anim.cancel(self.ids.label)
self.anim = None
self.ids.label.x = self.x_original
x_end = self.ids.label.x - self.ids.label.width
self.anim = Animation(x=x_end, duration=self.duration)
self.anim.bind(on_complete=self.do_anim)
self.anim.start(self.ids.label)
if __name__ == "__main__":
from kivy.app import App
class TestApp(App):
def build(self):
return Builder.load_string('''
FloatLayout:
Marquee:
text: 'This is a long text for testing the Marquee widget.'
font_name: 'DejaVuSans'
duration: 7
padding: 10
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
size_hint: None, None
size: 100, 50
''')
TestApp().run()
No guarantees.
I need to add a checkbox to this Kivy Canvas but it don"t know how to do it properly. I need the checkbox to display the name of all the file in the folder Data. Then the user check the file he wants and then by pressing a button (here the red one) it return a list of the file name and call some functions. Here is where i am right now.
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.metrics import dp
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.base import runTouchApp
from kivy.uix.recycleview import RecycleView
from kivy.uix.popup import Popup
from kivy.uix.progressbar import ProgressBar
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget.
from kivy.properties import ObjectProperty
import time
import os
Builder.load_string('''<Game>
ShootButton:
<ShootButton>
Image:
source: 'logo.jpg'
allow_stretch: True
size: 300,300
pos: 300, 400
Image:
source: 'livre.jpg'
allow_stretch: True
size: 350, 350
pos: 490,130
Button:
text: "Modifier Correspondance"
size: 240,50
font_size: 20
pos: 100,300
background_color :0, 1, 0, 1,
on_press: root.shoot()
Button:
text: "Liste Fichiers"
size: 240,50
font_size: 20
pos: 100,400
background_color :0, 1, 0, 1,
on_press: root.fire_popup()
Button:
text: "Ajouter Fichier"
size: 240,50
font_size: 20
pos: 100,200
background_color :0, 1, 0, 1,
on_press: root.shoot2()
Button:
text: "Generer PDF"
size: 180,50
font_size: 20
pos: 580,60
background_color :1, 0, 0, 1,
on_press: root.display()
''')
Window.size = (900, 600)
Window.clearcolor = (1, 1, 1, 1)
class Game(Widget):
pass
class SimplePopup(Popup):
pass
class SimplePopup2(Popup):
pass
class ShootButton(Widget):
def shoot(self):
shooting = Bullet()
shooting.bullet_fly()
def shoot2(self):
shooting = Bullet()
shooting.bullet_fly2()
class Bullet(Widget):
def bullet_fly(self):
print("test")
def bullet_fly2(self):
os.system("open .")
class MyApp(App):
def build(self):
return Game()
if __name__ == '__main__':
MyApp().run()
Ok, it's a lot of things you're asking for.
First we will need to create a layout with the labels as the files name and the checkbox to the corresponding file.
For this I'll use GridLayout, but you can do it as you want. In this layout we will need to get the files list, create the labels with the checkboxes, and, eventually, see what boxes are marked. So we will create a class with three functions and use a dict to link each box to its file:
class Grid(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2
self.files = self.get_files()
self.check_list = {}
self.create_checks()
def get_files(self):
# Get your files herre
return ['Hi', 'how', 'are', 'you?']
def create_checks(self):
# Create the checkboxes
for item in self.files:
self.add_widget(Label(text=item))
self.check_list[item] = CheckBox()
self.add_widget(self.check_list[item])
def get_actives(self):
# Check who is active (marked)
actives = []
for item in self.check_list:
if self.check_list[item].state == 'down':
actives.append(item)
return actives
Then we will ned to pass this class to our main content to display it for the user. For this I'll use a popup, but again, you can do as you please. So I'll start adding our content to a popup, and creating a function to call it.
class ShootButton(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Create popup with grid content
self.pop_content = Grid()
self.popup = Popup(title='', separator_height=0,
size_hint=(.8, .6),
content=self.pop_content)
def open_pop(self):
# You guessed! Opens the popup
self.popup.open()
Moslty done, now we just have to check which checkboxes are marked when the button is pressed. So I'll get your function display and use it to call our get_actives function:
def display(self):
actives = self.pop_content.get_actives()
print(actives)
And here is the full code:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
import os
Builder.load_string('''<Game>
ShootButton:
<ShootButton>
Image:
source: 'logo.jpg'
allow_stretch: True
size: 300,300
pos: 300, 400
Image:
source: 'livre.jpg'
allow_stretch: True
size: 350, 350
pos: 490,130
Button:
text: "Modifier Correspondance"
size: 240,50
font_size: 20
pos: 100,300
background_color :0, 1, 0, 1,
on_press: root.shoot()
Button:
text: "Liste Fichiers"
size: 240,50
font_size: 20
pos: 100,400
background_color :0, 1, 0, 1,
on_press: root.fire_popup()
Button:
text: "Ajouter Fichier"
size: 240,50
font_size: 20
pos: 100,200
background_color :0, 1, 0, 1,
on_press: root.shoot2()
Button:
text: "Generer PDF"
size: 180,50
font_size: 20
pos: 580,60
background_color :1, 0, 0, 1,
on_press: root.display()
''')
Window.size = (900, 600)
Window.clearcolor = (1, 1, 1, 1)
class Game(Widget):
pass
class SimplePopup(Popup):
pass
class SimplePopup2(Popup):
pass
class Grid(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2
self.files = self.get_files()
self.check_list = {}
self.create_checks()
def get_files(self):
# Get your files here
return ['Hi', 'how', 'are', 'you?']
def create_checks(self):
# Create the checkboxes
for item in self.files:
self.add_widget(Label(text=item))
self.check_list[item] = CheckBox()
self.add_widget(self.check_list[item])
def get_actives(self):
# Check who is active (marked)
actives = []
for item in self.check_list:
if self.check_list[item].state == 'down':
actives.append(item)
return actives
class ShootButton(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Create popup with grid content
self.pop_content = Grid()
self.popup = Popup(title='Choose files', separator_height=0,
size_hint=(.8, .6),
content=self.pop_content)
def shoot(self):
shooting = Bullet()
shooting.bullet_fly()
self.open_pop()
def shoot2(self):
shooting = Bullet()
shooting.bullet_fly2()
def fire_popup(self):
pass
def open_pop(self):
# You guessed! Opens the popup
self.popup.open()
def display(self):
actives = self.pop_content.get_actives()
print(actives)
class Bullet(Widget):
def bullet_fly(self):
print("test")
def bullet_fly2(self):
os.system("open .")
class MyApp(App):
def build(self):
return Game()
if __name__ == '__main__':
MyApp().run()
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()
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