I just wanted to ask, is it possible to set transitions for attributes changes in kivy? Let's say my widget with id toolbar has opacity 0:
self.root.ids.toolbar.opacity = 0
Is it possible to set a transition if I plan to change it into opacity 1?
self.root.ids.toolbar.opacity = 1
Answers, suggestions, and corrections are appreciated. Thanks!
I have used kivy for some time and ran into similar problem, but I'm not an expert! So there might be better ways to do this.
That being said, here's a small example introducing fading effect. I believe, you should be able to implement a version for your own problem based on this.
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<Screen1>:
test_widget : ID1
BoxLayout:
padding : (50, 50)
Button:
text: 'Trigger'
on_release:
root.trigger()
Label:
id : ID1
text: "Your Fading Text"
font_size : 30
bold : True
""")
class Screen1(Screen):
# Loading object properties based on the id
test_widget = ObjectProperty()
# Variables for the fading effect
event = None
trans_type = "fade_out"
# The trigger function schedules a task using Clock
def trigger(self):
if self.event != None:
# See below
self.event.cancel()
# The clock calls the given function every X seconds
self.event = Clock.schedule_interval(lambda _:self.transition(self.test_widget), 0.03)
def transition(self, widget):
# Changing the opacity of the widget, pretty self explanatory I think
if self.trans_type == "fade_out":
if (widget.opacity > 0.5):
widget.opacity -= 0.05
else:
self.trans_type = "fade_in"
# We need to make sure to cancel events, otherwise they would not stop
self.event.cancel()
elif self.trans_type == "fade_in":
if (widget.opacity < 1):
widget.opacity += 0.05
else:
self.trans_type = "fade_out"
self.event.cancel()
class TestApp(App):
def build(self):
# Creating a simple screen using ScreenManager and Screen
sm = ScreenManager()
sm.add_widget(Screen1(name='screen1'))
return sm
if __name__ == '__main__':
# Starting the app
TestApp().run()
Also, you might be interested in:
https://kivy.org/doc/stable/api-kivy.animation.html
This might simplify your solution, however I'm not familiar with it, so you have to figure that out for yourself :)
Related
I was making a program similiar to exel.
And then I ran into a issue.
StackLayout stacks good, but because the size of inputs is static it leave a blank space in some cases.
I try to do like size=(self.width/5, self.height/5).
If someone saw how exel look now that there are more inputs of the screen this is why I use ScrollLayout and I want only 5 inputs in one row(user can change it in display settings(I will do it then creating rest of UI))
Here is what I had tried for now.
main.py:
from kivy.metrics import dp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.textinput import TextInput
class EditorGrid(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
size = dp(self.width / 5)
print(size)
for i in range(0, 100):
b = TextInput(text=str(i + 1), size_hint=(None, None), size=(dp(size), dp(size)))
self.add_widget(b)
def on_size(self, *args):
self.size = dp(self.width/5)
print(self.size)
pass
class pxApp(App):
pass
if __name__ == "__main__":
pxApp().run()
kivy file:
Scrolling:
<Scrolling#ScrollView>
do_scroll_x: True
do_scroll_y: True
EditorGrid:
size_hint: 1, None
height: self.minimum_height
<EditorGrid>:
There is next problem that in init window size is 100x100.
I recommend using setters in binding under kv script. If you want to apply it in python, you could use a binding function for each button.
b = TextInput(.......) #omit size_hint and size attributes
#the following function is called every time EditorGrid(self) size_hint changes when the function is bind
#The function could be defined in a outer scope.
#Look at kivy callback functions to better understand the syntax
binding_function = lambda ins, *a: setattr(ins, 'size_hint', tuple((dim/5 for dim in self.size_hint))
b.bind(size_hint=binding_function)
I am trying to create some themes in kivy. My program currently has 4 classes/screens. I have manged to be able to change the background colour of all the screens if a condition is met. I have tried to change the colour of all the text input's so intead of white, they are black. This is my code so far
Python:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import *
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
class WeatherRoot(ScreenManager, BoxLayout):
pass
class RegisterPage(Screen, BoxLayout):
pass
class WeatherApp(App):
pass
def iii(time):
print("h")
x = 1
if x == 1:
Window.clearcolor = (1, 1, 1, 0)
TextInput.background_color = (1,1,1,0)
pass
if __name__ == "__main__":
Clock.schedule_once(iii)
WeatherApp().run()
Kivy:
WeatherRoot:
<WeatherRoot>:
RegisterPage:
<RegisterPage>:
BoxLayout:
padding: [100, 50, 100, 50]
TextInput:
font_size: 30
TextInput:
font_size: 30
The code to change the TextInput colour isn't working.
The background is white but the text-input isn't black as you can see
How would I be able to change the colour of the TextInput and properties widgets in general (e.g. the text colour of all labels), if a condition is met, with python code?
Thanks in advance
Note - It doesn't work with foreground_color or any of the colour settings like that.
It seems that the concept of object/instance and classes does not differ. By using TextInput.background_color = (1,1,1,0) you add or modify the "background_color" property of the TextInput class, not of the objects/instances created based on the TextInput class.
If you want to modify the property of the TextInputs (a.k.a instances/objects created based on the TextInput class) you must access those objects using the kivy methods through the parents:
def iii(time):
x = 1
if x == 1:
Window.clearcolor = (1, 1, 1, 0)
root = App.get_running_app().root # WeatherRoot instance
screen = root.screens[0] # RegisterPage instance
box_layout = screen.children[0] # BoxLayout instance
for child in box_layout.children: # childs of box_layout
if isinstance(child, TextInput): # verify that the child is a TextInput
child.background_color = (1,1,1,0)
I think you have extrapolated that in the case of Window it behaves similar to TextInput, but they are not the same since the first one is an instance of the WindowBase class, it is not a class unlike the second.
I'm making a label that should update every second or so. I tried making it with the clock schedule but it doesn't seem to work. The weird is if I use a button to call the same function it works fine.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
class FirstLayout(BoxLayout):
r = 0
def __init__(self, **kwargs):
super(FirstLayout, self).__init__(**kwargs)
self.change = self.ids.temp_label
def my_callback(self, *args):
self.r += 1
print self.r
t = str(self.r)
self.change.text = t
class TryApp(App):
def build(self):
Clock.schedule_interval(FirstLayout().my_callback, 1)
return FirstLayout()
app = TryApp()
app.run()
the .kv file:
<FirstLayout>:
orientation: 'vertical'
Label:
id: temp_label
text: 'something'
Button:
on_press: root.my_callback()
When I run the code I get the prints showing that the function is running but the label doesn't update. Anything wrong with my logic there?
Thank you in advance.
PS: I know there are several questions about this here, sadly those I found were replied with answers about using the Clock which I already do
The problem is that the callback is for an instance that you don't use:
def build(self):
Clock.schedule_interval(FirstLayout().my_callback, 1) #<--- FirstLayout created and never used
return FirstLayout() #this one will be used :(
Instead, You need to call the method of the FirstLayout that you are using
def build(self):
first_layout = FirstLayout() # "There should be one ..." :)
Clock.schedule_interval(first_layout.my_callback, 1)
return first_layout
I have a class that changes the background color constantly with a Clock.schedule_interval in init. I would like to create multiple instances of this class simultaneous; however, I think this means creating multiple threads which isn't allowed? What I would like is the top half to be changing colors while the bottom half is changing colors differently. What is happening is only the bottom half is changing colors while the top half is black. So here is the code.
The /teacher/main.py file is
from kivy.app import App
from kivy.clock import Clock
from kivy.graphics import Color
from kivy.properties import NumericProperty, ReferenceListProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from random import randint
class ChangingBackgroundColor(Widget):
r = NumericProperty(.5)
g = NumericProperty(.5)
b = NumericProperty(.5)
a = NumericProperty(1)
color = ReferenceListProperty(r, g, b, a)
def __init__(self,**kwargs):
super(ChangingBackgroundColor, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .2)
def update(self, dt):
position = randint(0,2) # change to randint(0,3) to change a as well
direction = randint(0,1)
if direction == 0:
if self.color[position] == 0:
self.color[position] += .1
else:
self.color[position] -= .1
elif direction == 1:
if self.color[position] == 1:
self.color[position] -= .1
else:
self.color[position] += .1
self.color[position] = round(self.color[position], 2)
self.canvas.add(Color(self.color))
class TeachingApp(App):
def build(self):
grid = GridLayout(rows=2)
a = ChangingBackgroundColor()
b = ChangingBackgroundColor()
grid.add_widget(a)
grid.add_widget(b)
return grid
if __name__ == '__main__':
TeachingApp().run()
and the /teacher/teaching.kv file is
#:kivy 1.0.9
<ChangingBackgroundColor>:
canvas:
Color:
rgba: self.color
Rectangle:
size: self.width, self.height
I looked here and and still fuzzy on the threading issue. Clock documentation.
This is my first question I have submitted so if I did anything wrong regarding question submission please let me know.
Your code is fine, using Clock.schedule_interval doesn't use threads (it's all in the main thread), and can be used from other threads even if you did have them, although callbacks would still happen in the main thread.
The problem is that your Rectangle entry in the kv needs to have:
pos: self.pos
Without this, both rectangles have the default pos of (0, 0), so the second one is on top of the first one and the top half of the screen is black.
I know this might be a very basic question, but after spending hours wrapping my head around it I still can't figure it out.
I basically just want to bind the text of a label to a variable in the python code. lets call it value. however it should get updated everytime I run a loop Clock.schedule_interval(RootWidget.update, 1.0/1.0)
here is the python, simplified so its basically just the time, which is also printed just to see if it is actually working.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.core.window import Window
import time
class RootWidget(FloatLayout):
def update(self, *args):
value = time.time()
print value
self.ids.value_label.text = str(value)
class MainApp(App):
def build(self):
Window.size = (800, 480)
r = RootWidget()
Clock.schedule_interval(r.update, 1)
print 'build running'
return r
def on_pause(self):
return True
if __name__ == '__main__':
MainApp().run()
the kv file looks as such:
<RootWidget>:
Label:
id: value_label
text:
y: 20.0
x: 0.0
width: 100.0
italic: False
height: 50.0
Clock.schedule_interval(RootWidget.update, 1.0/1.0)
You need to schedule the update method of an instance, not the class itself.
For instance:
r = RootWidget()
Clock.schedule_interval(r.update, 1)
return r
The clock will pass some arguments by default, so you should also declare the update method to accept these. If you don't want to use them then you can just do:
def update(self, *args):
...