I am having troubles getting my code to work. The progressbar should move on when a button is pressed and jump to 0 when it is released. With the kivy built in functions on_touch_down and on_touch_up it works but with my own check input funtion some arguments are missing. How do I pass them in correctly?
Thanks in advance!
import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.progressbar import ProgressBar
from kivy.clock import Clock
import RPi.GPIO as GPIO
buttonPin1 = 14
pbVal = 0
GPIO.setmode(GPIO.BCM)
GPIO.setup(buttonPin1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
Builder.load_string('''
<MainGrid>
GridLayout:
cols:1
size: root.width, root.height
GridLayout:
cols:2
Label:
text: "Tipp"
Label:
text: "Vid"
GridLayout:
cols:3
ProgressBar:
id: pb
min: 0
max: 100
''')
class MainGrid(GridLayout):
def __init__(self, **kwargs):
super(MainGrid, self).__init__(**kwargs)
def update_bar(self,*args):
global pbVal
pbVal = pbVal+1
self.ids.pb.value=pbVal
def on_touch_down(self, touch):
print('ButtonPressed')
self.event=Clock.schedule_interval(self.update_bar, 1.0/10.0)
def on_touch_up(self, touch):
global pbVal
print('ButtonReleased')
self.event.cancel()
pbVal = 0
self.ids.pb.value=pbVal
def checkInput(self,*args):
global pbVal
if GPIO.input(buttonPin1) == True:
print("not pressed")
self.event.cancel()
pbVal = 0
self.ids.pb.value=pbVal
else:
print("pressed")
self.event=Clock.schedule_interval(self.update_bar, 1.0/10.0)
Clock.schedule_interval(checkInput, 1.0/10.0)
class MyApp(App):
def build(self):
return MainGrid()
if __name__ == '__main__':
MyApp().run()
Someone found out the solution for my problem in the kivy forum already!
The clock command must be called from within the init section, the the checkInputs functions receives all the necessary attributes:
def __init__(self, **kwargs):
super(MainGrid, self).__init__(**kwargs)
Clock.schedule_interval(checkInput, 1.0/10.0)
Related
I want to simulate the user action and after looking in the doc, I saw the Clock.schedule_once(my_callback, 1).
.
Question: Is this the only way to do it ? I would have prefered something like my_button.press().
.
I want to press the button and then, it will call my_callback, I don't want to directly call my_callback.
(Because if I do this and my callback evolve, I lost the good reference)
PS: I saw that there was the possibility to use Clock.create_trigger(my_callback) but it didn't seems to be the good solution here.
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.clock import Clock
KV_APP = '''
BoxLayout:
Button:
id: my_button
text: "Click on me"
'''
class TestApp(MDApp):
def build(self):
self.screen = Builder.load_string(KV_APP)
self.screen.ids["my_button"].bind(on_press=self.on_button_click)
event = Clock.schedule_once(self.on_button_click, 1)
return self.screen
def on_button_click(self, instance):
print("hello there !")
if __name__ == '__main__':
TestApp().run()
You can create an Event and dispatch it. Here is an example:
from kivy.app import App
from kivy.clock import Clock
from kivy.input.providers.mouse import MouseMotionEvent
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
class MyBoxLayout(BoxLayout):
def mydispatchAnEvent(self, *args):
# create and dispatch a fake event
touch = MouseMotionEvent(None, 123, (123, 456)) # args are device, id, spos
touch.button = 'left'
touch.pos = (321, 654)
self.dispatch('on_touch_down', touch)
theRoot = Builder.load_string('''
MyBoxLayout:
orientation: 'vertical'
Label:
text: 'Button below should demonstrate receiving touch event'
Button:
text: 'Waiting for event'
on_press: print('touched')
''')
class EventDispatcherPlayApp(App):
def build(self):
Clock.schedule_once(theRoot.mydispatchAnEvent, 2)
return theRoot
EventDispatcherPlayApp().run()
I'm trying to build an app using kivy. I have added close button and then I added on_release. However, pressing the button does not work.
python code:
import kivy
kivy.require('1.11.0')
from kivy.lang import Builder
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.window import Window
Window.size = (350 * 1.5 , 600 * 1.5)
with open("./template.kv", encoding='utf8') as f:
Builder.load_string(f.read())
class CloseButton(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(CloseButton, self).__init__(**kwargs)
self.source = './close_btn#2x.png'
always_release = True
def on_press(self):
App.get_running_app().stop()
class Background(Screen):
def __init__(self, **kwargs):
super(Background, self).__init__(**kwargs)
class TemplateApp(App):
def build(self):
# title bar remove
# Window.borderless = True
sm = ScreenManager()
sm.add_widget(Background(name='back'))
return sm
if __name__ == '__main__':
TemplateApp().run()
kivy code:
<Background>:
canvas:
Rectangle:
pos: self.pos
size: self.size
source: "background.png"
Label:
font_size: 12 * 1.5
text: 'Template'
font_name: './NotoSans-hinted/NotoSans-Regular.ttf'
size_hint: (1.0, 1.0)
halign: "left"
valign: "top"
color: 0.43568, 0.43568, 0.43568, 1
text_size: root.width - (40 * 1.5), 583 * 1.5
BoxLayout:
size_hint: 1.9, 1.938
CloseButton:
id: close_btn
Instead of
def on_press(self):
App.get_running_app().stop()
try this
self.on_press = App.get_running_app().stop()
Ok, let's try this:
from kivy.clock import Clock
...
class CloseButton(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(CloseButton, self).__init__(**kwargs)
self.source = './close_btn#2x.png'
# no parentheses after method's name!
self.on_press = self.closeapp
def closeapp(self):
Clock.schedule_once(App.get_running_app().stop())
The following code permanently crashes with "Segmentation fault (core dumped)".
It seems that setting the text in the TextInput makes the application crash.
Can anyone confirm the error?
What does the error message mean?
I use threading, because I wanted the user to perform some actions on the screen and the application should wait for the result before going on.
Edit:
If there was something like a "goto" statement (o.k. sorry for that ;-)) I would like to jump to the line with comment # further commands and proceed there with the main flow.
import sys
import threading
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty
Builder.load_string("""
<MyWordRecorderScreen>:
id: TheWordRecorderScreen
my_text_input: TheTextInput
my_record_button: TheRecordButton
BoxLayout:
orientation: 'vertical'
spacing: 10
MyTextInput:
id: TheTextInput
my_screen: TheWordRecorderScreen
# removing the following statement makes the app work but useless
text: "Example"
RecordButton:
id: TheRecordButton
text: "Record"
my_screen: TheWordRecorderScreen
size_hint: (0.2, 0.15)
""")
class MyTextInput(TextInput):
pass
class RecordButton(Button):
my_screen = ObjectProperty(None)
class MyWordRecorderScreen(Screen):
my_record_button = ObjectProperty(None)
my_text_input = ObjectProperty(None)
class MyScreenSequence():
def __init__(self,my_screenmanager):
self.sm=my_screenmanager
def do_job(self):
self.CurrentScreen = MyWordRecorderScreen()
self.sm.switch_to(self.CurrentScreen)
def ApplicationFlow(MyScreenManager, *largs):
sm = MyScreenManager
screen_terminated=threading.Condition()
screen_terminated.acquire()
# subroutine will use screen_terminated.notify_all() once result is available
MSS=MyScreenSequence(my_screenmanager=sm)
t2 = threading.Thread(target=MSS.do_job)
t2.daemon = False
t2.start()
screen_terminated.wait()
screen_terminated.release()
# get result from subroutine
# futher commands
return
class TestApp(App):
def build(self):
self.sm = ScreenManager()
return self.sm
def on_start(self):
t1 = threading.Thread(target=ApplicationFlow, args=[self.sm])
t1.daemon = False
t1.start()
def main(args):
TestApp().run()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
I find it simpler to use Thread.Event(). Here is my version of your code that uses Kivy.clock:
import sys
import threading
import time
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty
from functools import partial
Builder.load_string("""
<MyWordRecorderScreen>:
id: TheWordRecorderScreen
my_text_input: TheTextInput
my_record_button: TheRecordButton
BoxLayout:
orientation: 'vertical'
spacing: 10
MyTextInput:
id: TheTextInput
my_screen: TheWordRecorderScreen
# removing the following statement makes the app work but useless
text: "Example"
RecordButton:
id: TheRecordButton
text: "Record"
my_screen: TheWordRecorderScreen
size_hint: (0.2, 0.15)
""")
class MyTextInput(TextInput):
pass
class RecordButton(Button):
my_screen = ObjectProperty(None)
class MyWordRecorderScreen(Screen):
my_record_button = ObjectProperty(None)
my_text_input = ObjectProperty(None)
class MyScreenSequence():
def __init__(self,my_screenmanager):
self.sm=my_screenmanager
def do_job(self, theEvent, dt):
self.CurrentScreen = MyWordRecorderScreen()
self.sm.switch_to(self.CurrentScreen)
theEvent.set()
def ApplicationFlow(MyScreenManager, *largs):
sm = MyScreenManager
screen_terminated=threading.Event()
# subroutine will use screen_terminated.set() once result is available
MSS=MyScreenSequence(my_screenmanager=sm)
Clock.schedule_once(partial(MSS.do_job, screen_terminated), 0)
screen_terminated.wait()
# get result from subroutine
# futher commands
return
class TestApp(App):
def build(self):
self.sm = ScreenManager()
return self.sm
def on_start(self):
t1 = threading.Thread(target=ApplicationFlow, args=[self.sm])
t1.daemon = False
t1.start()
def main(args):
TestApp().run()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
I want to print out the position of the pointer (mouse) everytime it passes over a widget. Actually to be more specific I'd like to print the current position of the mouse everytime it moves. Is that at all possible?
Right now all I've managed to do is:
Print the position of the mouse whenever the mouse is clicked
(in two different ways)
Print the position of the widget when it's clicked
I'm sure it's easier than I think, thanks in advance.
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.input.motionevent import MotionEvent
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
def on_mouse_pos(self, pos):
if Window.mouse_pos == self.ids.example_button:
print("You've made it")
# With out this if statement it does print the position every time
# That the mouse is moved. But can I print "You've made it" every time
# that the mouse is moved over the position of a widget?
print(pos)
def test_print(self):
print(str(self.ids.example_button.pos))
Window.bind(mouse_pos = on_mouse_pos)
class MyScreenManager(Screen):
pass
root_widget = Builder.load_string('''
MyScreenManager:
MainScreen:
<MainScreen>:
name: 'Example'
Button:
id: example_button
text: 'Print position of widget when mouse touches it'
size_hint: 1, .05
pos_hint: {'x': 0, 'y': .5}
on_release: root.test_print()
''')
class TestApp(App):
def build(self):
self.title = 'Example Application'
return root_widget
if __name__ == '__main__':
TestApp().run()
A possible solution is to use mouse_pos:
from kivy.core.window import Window
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MainScreen(Screen):
def on_mouse_pos(self, pos):
print(pos)
Window.bind(mouse_pos = on_mouse_pos)
class MyScreenManager(Screen):
pass
root_widget = Builder.load_string('''
MyScreenManager:
MainScreen:
<MainScreen>:
name: 'Example'
Button:
id: example_button
text: 'I am button'
size_hint: 1, .05
pos_hint: {'x': 0, 'y': .5}
''')
class TestApp(App):
def build(self):
self.title = 'Example Application'
return root_widget
if __name__ == '__main__':
TestApp().run()
Update:
If you want to verify that the mouse point is inside a widget you must use collide_point.
from kivy.core.window import Window
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
Window.bind(mouse_pos = self.on_mouse_pos)
def on_mouse_pos(self, instance, pos):
if self.ids.example_button.collide_point(*pos):
print("You've made it")
class MyScreenManager(Screen):
pass
root_widget = Builder.load_string('''
MyScreenManager:
MainScreen:
<MainScreen>:
name: 'Example'
Button:
id: example_button
text: 'I am button'
size_hint: 1, .05
pos_hint: {'x': 0, 'y': .5}
''')
class TestApp(App):
def build(self):
self.title = 'Example Application'
return root_widget
if __name__ == '__main__':
TestApp().run()
Im trying to make a multi screen app and I want a date/time label on all of them.
I made a clock event that update the text value each second.
The clock event is working because on python console I can see it updating, but the label is not refreshing, it just works the first time.
How can I refresh the screen?
The main.py file:
import kivy
import time
from kivy.app import App
from kivy.uix.label import Label
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.clock import Clock
kivy.require("1.9.1")
Window.size = (1280,1024)
Config.set('graphics', 'fullscreen', '0')
class TimeLabel(Label):
def __init__(self, **kwargs):
super(TimeLabel, self).__init__(**kwargs)
self.text= str(time.asctime())
def update(self, *args):
self.text = str(time.asctime())
print self.text
class LoginScreen(Screen):
pass
class MainScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class My1App(App):
def build(self):
my1sm = Builder.load_file("main.kv")
crudeclock = TimeLabel()
Clock.schedule_interval(crudeclock.update, 1)
return my1sm
if __name__ == '__main__':
My1App().run()
and the main.kv file:
#: kivy 1.9
#: import ScreenManager kivy.uix.screenmanager.ScreenManager
#: import Screen kivy.uix.screenmanager.ScreenManager
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
LoginScreen:
<MainScreen>:
name: 'main'
size_hint: (1, 1)
FloatLayout:
Image:
source: './background.png'
size: 1280,1024
TimeLabel:
<LoginScreen>:
name: 'loginS'
FloatLayout:
Image:
source: './Login.png'
size: 1280,1024
TimeLabel:
<TimeLabel>:
x:-545
y:-475
color: (0,0,0,1)
You need to set the schedule_interval when the label is instantiated.
import kivy
import time
from kivy.app import App
from kivy.uix.label import Label
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.clock import Clock
kivy.require("1.9.1")
Window.size = (600,600)
Config.set('graphics', 'fullscreen', '0')
class TimeLabel(Label):
def __init__(self, **kwargs):
super(TimeLabel, self).__init__(**kwargs)
self.text= str(time.asctime())
Clock.schedule_interval(self.update,1)
def update(self, *args):
self.text = str(time.asctime())
print self.text
class LoginScreen(Screen):
pass
class MainScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class My1App(App):
def build(self):
my1sm = Builder.load_file("main.kv")
crudeclock = TimeLabel()
return my1sm
if __name__ == '__main__':
My1App().run()