This question already has an answer here:
How to have an updating time in Kivy
(1 answer)
Closed 3 years ago.
New to python and kivy. Working on a dashboard to display time and other parameters. Dashboard is currently set and displays all values perfectly. But still can't figure out how to update the time dynamically in those labels used for time. Found similar posts but still struggling. Posting below the summarised portion of my codes.
Worked with the Clock object to trigger a method every one sec which need to update the label text in the kv file. But unable to put this logic into working.
sample.py
import time
import datetime
import kivy
kivy.require('1.11.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.core.text import LabelBase
from kivy.clock import Clock
class MySec(BoxLayout):
seconds_string = time.strftime("%S")
class MyApp(App):
def build(self):
#Clock.schedule_interval('periodic_method', 1)
return MySec()
if __name__ == '__main__':
MyApp().run()
my.kv file
<mysec>:
orientation: 'vertical'
Label:
id: kv_sec
text: root.seconds_string
font_size: 200
In short, how should I modify the .py file so that so that my .kv label text gets updated every second with the updated value. Thanks a lot in advance.
Use a Kivy StringProperty to automatically update the Label's text, and use Kivy Clock object e.g. Clock.schedule_interval() to update the StringProperty at every time interval.
Replace seconds_string = time.strftime("%S") with class attribute of type StringProperty, seconds_string = StringProperty('')
Implement a method, update_time() to update class attribute, seconds_string
Use Kivy Clock.schedule_interval() to invoke method update_time()
Kivy ยป Introduction to Properties
Properties are an awesome way to define events and bind to them.
Essentially, they produce events such that when an attribute of your
object changes, all properties that reference that attribute are
automatically updated.
Example
The following example uses time() function to extract time. It can be replaced with datetime.now() e.g. replace time.strftime("%S") with datetime.now().strftime("%S"), and add import statement, from datetime import datetime
main.py
import time
import kivy
kivy.require('1.11.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string("""
<MySec>:
orientation: 'vertical'
Label:
id: kv_sec
text: root.seconds_string
font_size: 200
""")
class MySec(BoxLayout):
seconds_string = StringProperty('')
class MyApp(App):
def build(self):
Clock.schedule_interval(lambda dt: self.update_time(), 1)
return MySec()
def update_time(self):
self.root.seconds_string = time.strftime("%S")
if __name__ == '__main__':
MyApp().run()
Output
Related
import kivy
from kivy.lang.builder import Builder
from kivy.app import App
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.widget import Widget
from kivy.clock import Clock
Builder.load_string('''
<apper>
input_val : input_t
BoxLayout:
size: root.size
Label:
id: label_t
text: root.texter
TextInput:
id: input_t
Button:
on_press : root.doer()
''')
class apper(Widget):
texter = StringProperty()
input_val = ObjectProperty(None)
run = 0
def doer(self, dt):
self.run+=1 # keep track of number of times this function ran
#self.texter = self.ids.input_t.text
print(self.ids.input_t.text, self.run) #prints an empty string for self.ids.input_t.text
self.texter = self.input_val.text
class runs(App):
def build(self):
Clock.schedule_interval(apper().doer, 1.0/2.0)
return apper()
runs().run()
#the code works when you remove the Clock statement and the second argument or apper.doer() and you have to press the button
#to rename the label
#how comes it doesnt work when you introduce the clock statement
#Note that I am new to kivy but not new to programming
When I use a button to run the function on press the correct values from text input are returned but using a clock it doesn't work, can anyone help.
Also when the program should be running properly with the Clock then the button is unnecessary since it updates the label with the text of the TextInput every 0.5 seconds.
Is there any way the code can be rewritten or mended such that the TextInput returns a value and not an empty string.
move the clock to ur apper class: and put it like this
Clock.schedule_interval(self.doer, 1/2)
and declare doer like this:
def doer(self, *args):
and feel free to check this tuto i uploaded recently
https://www.youtube.com/watch?v=DbX-CdVob6E&t=57s
I'm a learning kivy on my own and am trying to create a sublcass of TextInput with the custom behavior that, when selected, the contents of the text box are highlighted (so that a user can then begin typing in a new value). I have two questions, one for each attempt.
My first attempt was this:
from datetime import date
# kivy imports
from typing import Text
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
from kivy.properties import (StringProperty)
class MedAssignApp(App):
def build(self):
return MainWindow()
class MainWindow(AnchorLayout):
pass
class TextEntry(TextInput):
def on_touch_down(self, touch):
super().on_touch_down(touch)
Clock.schedule_once(lambda dt: self.select_all())
I then have several instances of TextEntry in the medassign.kv file:
.. other stuff above
GridLayout:
cols: 4
rows: 3
Label:
text: 'Date'
DateEntry:
Label:
text: 'Shift'
TextEntry:
text: 'THIS WILL BE A DROPDOWN'
Label:
text: 'ST1'
TextEntry:
text: 'Enter name..'
Label:
text: 'ST2'
TextEntry:
text: 'Enter name..'
Label:
text: 'ST3'
TextEntry:
text: 'Enter name..'
Label:
text: 'ST4'
TextEntry:
text: 'Enter name..'
<TextEntry>:
However, when I test the application and I click on one of the text fields, all texts in all instances are highlighted. So my first question is: Does anyone understand why?
My second attempt:
Then I attempted to do it this way (below), which works, but again, I don't know why it works.
# built-in imports
from datetime import date
# kivy imports
from typing import Text
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
from kivy.properties import (StringProperty)
class MedAssignApp(App):
def build(self):
return MainWindow()
class MainWindow(AnchorLayout):
pass
class TextEntry(TextInput):
pass
and medassign.kv
<TextEntry>:
TextInput:
on_touch_down: Clock.schedule_once(lambda dt: root.select_all())
Note: In this second case, if I use root it works as I would like. But if I use self, it does not work as I would like (it behaves like the first attempt).
My second question: Can anyone explain why this works with root?
Thank you!
The first version fails because you have not taken into account that all the widgets get the on_touch_down() call on every touch down event. It is the responsibility of the instances on_touch_down() method to determine if the touch is relevant to that instance. The on_touch_down() method returns a bool:
If True, the dispatching of the touch event will stop. If False,
the event will continue to be dispatched to the rest of the widget
tree.
So your on_touch_down() for every instance applies the select_all(). Here is a modified version of on_touch_down():
def on_touch_down(self, touch):
if self.collide_point(*touch.pos): # check if touch is on this instance
Clock.schedule_once(lambda dt: self.select_all())
return super().on_touch_down(touch) # Let the TextInput handle this touch as normal.
OK, so i'm trying to make an app using python and kivy.From tutorials and from search on google i've seen people using kivy language to simplify their code but when i try to create a kv file for my program i get an "Invalid property name" ERROR and i dont know what to do.I did everything the guy on the tutorial did and followd every instruction on google but still i get this error.Did anyone had the same problem before and how did you solve it? Thanks in advance!
This is my python file:
import kivy
#kivy.require('1.0.6') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.scatter import Scatter
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.lang import Builder
from kivy.properties import NumericProperty
class QuizWidget(BoxLayout):
pass
class MyQuizApp(App):
def build(self):
return QuizWidget()
if __name__ == '__main__':
MyQuizApp().run()
This is my kivy file:
<QuizWidget>:
orientation = 'vertical'
TextInput:
id: Start_text
font_size: 100
size_hint_y: None
height: 200
text: 'Wellcome to my quiz.Press START to continue'
Button:
text:'START'
font_size: 150
orientation = 'vertical'
This should be orientation: 'vertical'. Kivy is trying to parse the whole thing as a property name since you didn't have a :. The error should probably point to this line, but you didn't give enough info to check.
I am having problems understanding the usage of custom Properities and ways of binding methods to events.
Here's my code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import StringProperty
kivy_lang = '''
<MainWidget>:
on_my_property: my_label.text = 'from button bind method via StringProperty' + my_property
Label:
id: my_label
text: root.my_property
Button:
id: my_button
text: 'intro button'
'''
class MainWidget(BoxLayout):
# bind some properties
my_property = StringProperty('0')
def __init__(self, **kwargs):
super(MainWidget, self).__init__(**kwargs)
# if needed to do sth on widget construction
self.ids.my_button.bind(on_press=self.my_method)
def my_method(self,*args,**kwargs):
self.my_property = str(int(self.my_property)+1)
self.ids.my_button.text = 'new'
class MyApp(App):
def build(self):
Builder.load_string(kivy_lang)
return MainWidget()
if __name__ == '__main__':
MyApp().run()
When I run it it renders OK, but when I click a button, as a result I get
NameError: name 'my_property' is not defined
I tried binding method for Button in kv lang with (and removing whole 'init()' on python side):
on_press: root.my_method
and then when I press button the app doesn't crash but nothing happens
Can someone explain me how to adjust this code to work?
I understand the code is a little 'mixed techniques' but I did it that way to get to know different approaches, so I would appreciate if You don't turn it all around :)
1/ you are missing 'self' before 'my_property' in 'on_my_property' bindind, hence the crash
2/ in kv bindings. the python code is called as written, so you need '()' after 'root.my_method', or the statement has no effect.
I don't have any idea to find a solution of my problem.
I have make an application with Carousel Widget. In this Carousel I have 4 slides.
welcomeSlide -> DVDSlide -> DVDPretSlide --> CategorySlide
I have make a class for each slides.
I use a ListAdpter to display the data extracted from an Sqlite3 Database.
My pblem is about the refresh of the list, when I modify a DVD (add name to pret) in the DVDSlide, when I slide to the DVDPret, the DVD do not appears because the List is not refresh.
Like the doccumentation for the carousel I don't find the event when slide change. It will be the best if an event exist to get the current slide index.
Have you got any Idea ?
Thanks,
You can observe index property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
Label:
text: str(id(root))
<Carousel>
on_index: print("slide #{}".format(args[1]))
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
Or you can observe current_slide property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
label_id: label_id
Label:
id: label_id
text: str(id(root))
<Carousel>
on_current_slide: print(args[1].label_id.text)
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
If you want a pure python solution rather than a Kivy Language solution you can create your own carousel that inherits from the Kivy carousel as follows.
import kivy
from kivy.uix.carousel import Carousel
class MyCarousel(Carousel):
# This class is a carousel that runs script
# when a slide gets focus (except first load).
def on_index(self, *args):
print('the slide is', self.index)
# YOUR CODE GOES HERE
Carousel.on_index(self, *args)