The problem is in the .kv file. My problem is that i would like my .kv to notice the object-property in my .py. My code works if change the color in .kv to color: 0,0,0 which gives me black text as intend.
.py
from kivy import utils
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.uix.button import ButtonBehavior
Builder.load_file("FirebaseLoginScreen/themedwidgets.kv")
class ThemedButton(ButtonBehavior,Label):
colorchanged = ObjectProperty()
color = ObjectProperty([0,0,0,1])
def __init__(self, **kwargs):
super(ThemedButton, self).__init__(**kwargs)
Clock.schedule_once(self.start_pulsing, 1)
def start_pulsing(self, *args):
anim = Animation(color=[0,1,0,1]) + Animation(color=[0,0,1,1]) + Animation(color=[1,0,0,1])
anim.repeat = True
anim.start(self)
.kv
<ThemedButton#ButtonBehavior+Label>:
colorchanged: colorchanged
id: colorchanged
markup: True
color: self.color #root.color doesn't work either but 0,0,0 does give me black.
opacity: 1 if self.state == 'normal' else .8
font_size: 38
<ThemedButton#ButtonBehavior+Label>:
This is the kv syntax to create a new widget class inheriting from ButtonBehavior and Label, so it doesn't have any of the behaviour of your Python-defined class that happens to have the same name.
You want to just do <ThemedButton>: instead.
Related
This question already has answers here:
What is the purpose of the `self` parameter? Why is it needed?
(26 answers)
Closed 3 years ago.
I would like to change a Label-text in Python/Kivy after a swipe event has been detected. Changing the text works basically via the following line
self.Translation.text = "test"
but I have to change the text after detecting a swipe event from another class, in which I call a function to change the label text:
MyWidget.ThisDoesntWork("self_dummy")
In this function the exact same line as above gives me an error.
How can I change the Label-text from class "Swiping_class" calling function "MyWidget.ThisDoesntWork("self_dummy")"?
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.base import EventLoop
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.uix.stacklayout import StackLayout
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import *
from kivy.properties import ListProperty
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from random import random
import pickle
import random
kv = '''
<ColoredLabel>:
size: (self.size_x,self.size_y)
pos: (0,0) # no effect
background_color:
canvas.before:
Color:
rgba: self.background_color
Rectangle:
pos: self.pos
size: (self.size_x,self.size_y)
'''
Builder.load_string(kv)
class ColoredLabel(Label):
background_color = ListProperty((0,0,0,1))
s_global = Window.size
size_x = s_global[0]
size_y = s_global[1]/3
class MyWidget(BoxLayout):
#init
def __init__(self, **kwargs):
super().__init__(**kwargs)
s_global = Window.size
size_x = s_global[0]
size_y = s_global[1]/3
self.ForeignLanguage = ColoredLabel(text="str_fl", size_hint=(None, None),size = (size_x,size_y), background_color=(0/255,171/255,169/255, 1))
self.Translation = ColoredLabel(text="str_tr", size_hint=(None, None),size = (size_x,size_y), background_color=(45/255,137/255,239/255, 1))
self.Example = ColoredLabel(text="str_ex", size_hint=(None, None),size = (size_x,size_y), background_color=(43/255,87/255,151/255, 1))
self.verticalBox = BoxLayout(orientation='vertical')
self.verticalBox.add_widget(self.ForeignLanguage)
self.verticalBox.add_widget(self.Translation)
self.verticalBox.add_widget(self.Example)
self.Translation.text = "test"
s=Swiping_class()
s.add_widget(self.verticalBox)
self.add_widget(s)
def ThisDoesntWork(self):
print("this is printed")
self.Translation.text = "I wanna change this via fucntion"
print("this is not printed anymore")
class Swiping_class(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.initial = 0
def on_touch_down(self, touch):
self.initial = touch.x
def on_touch_up(self, touch):
if touch.x < self.initial:
print("swiped left")
MyWidget.ThisDoesntWork("self_dummy")
else:
print("swiped right")
class BoxLayoutDemo(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
BoxLayoutDemo().run()
I think I found a solution. Within your Swiping_class, replace this line:
MyWidget.ThisDoesntWork("self_dummy")
with this line:
MyWidget.ThisDoesntWork(self.parent)
That way, instead of passing a string to your method, you pass the label object, which contains the text attribute you are trying to modify.
I'm trying to find a solution to embed a graph within a kivy widget. There seems to be only one example of using kivy garden graph (sin wave) and I'm having difficulty implementing this within my app.
Here is the code that I'm working with
#!/usr/bin/kivy
import kivy
from random import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.switch import Switch
from kivy.uix.label import Label
from kivy.garden.graph import Graph, MeshLinePlot
from math import sin
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from kivy.graphics import *
from kivy.config import Config
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '480')
Builder.load_string("""
<Menuscreen>:
#Handling the gesture event.
ScreenManager:
id: manager
Screen:
id: main_screen
name:'main_screen'
FloatLayout:
MyGraph:
size_hint: None, None
size: 800,600
pos: 25,25
""")
class MyGraph(Graph):
def __init__(self, **kwargs):
super(MyGraph, self).__init__(**kwargs)
self.xlabel = 'This is the X axis'
self.ylabel = 'This is the Y axis'
self.x_ticks_minor = 5
self.x_ticks_major = 25
self.y_ticks_major = 1
self.y_grid_label = True
self.x_grid_label = True
self.x_grid = True
self.y_grid = True
self.xmax = 100
self.xmin = -0
self.ymin = -1
self.ymax = 1
self.plot = MeshLinePlot(color=[1, 0, 0, 1])
self.plot.points = [(x, sin(x / 10.)) for x in range(0, 100)]
self.add_plot(self.plot)
class MenuScreen(Screen):
pass
sm = ScreenManager()
menu_screen = MenuScreen(name='menu')
sm.add_widget(menu_screen)
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
All of the axis labels seem to appear but the points on the graph do not appear. Is there something that I am missing to get this to appear? Thanks in advance for your advice.
Mostafar at Github asked this same question, and thanks to #Tshirtman, the following answer was provided:
mostafar commented on Apr 27, 2014 After a chat with #tshirtman, He found out the problem is with stencilbuffer and by changing line 139 of init.py of graph module to:
self._fbo = Fbo(size=self.size, with_stencilbuffer=False)
It will be visible in my example, but then there will be many problems with new features of graph (SmoothLinePlot).
Link: https://github.com/kivy-garden/garden.graph/issues/7
Everything seems to be ok (according to docs) (I know it isnt), but it's impossible to move my Image object.
Image object is visible on BrickCanvas but probably it is untouchable. I tried to print something after on_touch_down event on Image object and after touch down nothing happend.
memo.kv
<BrickCanvas>:
FloatLayout:
Brick
<Brick>:
drag_rectangle: 100 , 100 , 100 , 100
drag_timeout: 1000000000000000
drag_distance: 0
Image:
size: (150,150)
source: '/home/prezes/Desktop/KO.jpg'
main.py
#!/usr/bin/kivy
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.behaviors import DragBehavior
class BrickCanvas(Widget):
pass
class Brick(DragBehavior,Widget):
pass
class MemoApp(App):
def build(self):
return BrickCanvas()
if __name__ == '__main__':
MemoApp().run()
Apparently DragBehavior works but only for selected widget and not its children (in this case it's a Image) as you can test with this code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.behaviors import DragBehavior
from kivy.lang import Builder
Builder.load_string('''
<BrickCanvas>:
FloatLayout:
Brick
<Brick>:
canvas:
Color:
rgb: 0.5, 0.5, 0.5
Rectangle:
size: self.size
pos: self.pos
Image:
size: 50, 50
source: 'test.png' # change to your path
''')
class BrickCanvas(Widget):
pass
class Brick(DragBehavior,Widget):
pass
class MemoApp(App):
def build(self):
return BrickCanvas()
if __name__ == '__main__':
MemoApp().run()
You can use Image class directly to avoid this problem:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.behaviors import DragBehavior
from kivy.lang import Builder
Builder.load_string('''
<BrickCanvas>:
Brick
<Brick>:
source: 'test.png' # change to your path
''')
class BrickCanvas(Widget):
pass
class Brick(DragBehavior, Image):
pass
class MemoApp(App):
def build(self):
return BrickCanvas()
if __name__ == '__main__':
MemoApp().run()
Still I'd say that for simple drag and drop functionality for an image it's better to just use Scatter widget:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.lang import Builder
Builder.load_string('''
<BrickCanvas>:
Brick
<Brick>:
do_scale: False
do_rotation: False
Image
source: 'test.png' # change to your path
''')
class BrickCanvas(Widget):
pass
class Brick(Scatter):
pass
class MemoApp(App):
def build(self):
return BrickCanvas()
if __name__ == '__main__':
MemoApp().run()
I wanted to make a kivy game with an stickman running around the screen, and as soon as you click on it, the stickman is removed.
I tried to remove the enemy widget by using Place.remove_widget(Enemy), but the Program crashed an I got this error message:
TypeError: unbound method remove_widget() must be called with Place instance as first argument (got WidgetMetaclass instance instead)
Here is my source code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.clock import Clock
from kivy.animation import Animation
class Place(FloatLayout):
pass
class Enemy(Widget):
velocity = NumericProperty(1)
def __init__(self, **kwargs):
super(Enemy, self).__init__(**kwargs)
Clock.schedule_interval(self.Update, 1/60.)
def Update(self, *args):
self.x -= self.velocity
if self.x < 1:
self.velocity = 0
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
print 'es geht'
self.velocity = 0
Place.remove_widget(Enemy)
ROOT = Builder.load_string('''
Place:
Button:
text: 'Go Back'
size_hint: 0.3, 0.1
pos_hint: {"x": 0, 'y':0}
Enemy:
pos: 400, 100
<Enemy>:
Image:
pos: root.pos
id: myimage
source: 'enemy.png'
''')
class Caption(App):
def build(self):
return ROOT
if __name__ == '__main__':
Caption().run()
Place.remove_widget(Enemy)
This is the problem - you aren't trying to remove an instance of the Enemy class from an instance of the Place class, but instead trying to remove the actual class itself from the other. This is the difference between a = Place and a = Place() - the former is the instructions for how to make a Place, the latter is an actual individual Place instance.
In this case you could probably do self.parent.remove_widget(self); self.parent is the Place instance containing the Enemy instance.
import os,sys,random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Rectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen , SlideTransition
from kivy.animation import Animation
from kivy.properties import StringProperty
class Page(Screen):
source = StringProperty()
class Imglayout(FloatLayout):
def __init__(self,**args):
super(Imglayout,self).__init__(**args)
with self.canvas.before:
Color(0,0,0,0)
self.rect=Rectangle(size=self.size,pos=self.pos)
self.rootpath = os.path.dirname(os.path.realpath(sys.argv[0]))
self.images=[]
for img in os.listdir(self.rootpath+'/images'):
self.images.append(self.rootpath+'/images/'+img)
self.index=random.randint(0,len(self.images)-1)
self.im=Image(source=self.images[self.index])
self.im.keep_ratio= False
self.im.allow_stretch = True
#self.add_widget(self.im)
self.sm = ScreenManager(transition=SlideTransition())
self.page1=Page(name='page1', source = self.images[self.index])
self.page2=Page(name='page2', source = self.images[self.index+1])
self.sm.add_widget(self.page1)
self.sm.add_widget(self.page2)
self.bind(size=self.updates,pos=self.updates)
def updates(self,instance,value):
self.rect.size=instance.size
self.rect.pos=instance.pos
def on_touch_down(self,touch):
if self.collide_point(*touch.pos):
if(self.sm.current == 'page1'):
next='page2'
page=self.page2
else:
next='page1'
page=self.page1
self.index=(self.index+1)%len(self.images)
page.source = self.images[self.index]
page.background.scale = 1.0
self.sm.transition=SlideTransition()
self.sm.current = next
anim = Animation(
scale=page.background.scale*1.3,
duration=15.0
)
anim.start(page.background)
return True
return False
class MainTApp(App):
def build(self):
root = BoxLayout(orientation='vertical',spacing=10)
c = Imglayout()
root.add_widget(c)
cat=Button(text="Categories",size_hint=(1,.05))
cat.bind(on_press=self.callback)
root.add_widget(cat);
return root
def callback(self,value):
print "CALLBACK CAT"
if __name__ == '__main__':
MainTApp().run()
Taking some hints from here i made the above program. It says that Page does not have a background attribute in both my and the referenced code. Its kind of obvious since there is no background attribute. I thought it inherited that from Screen. I am trying to make a slideshow kind of thing. But i cant find any information on how to set the background of a screen.
And if i comment out everything with .background and run the app. click on the black space, then i start getting this error continuously on the terminal
[ERROR ] [OSC ] Address 127.0.0.1:3333 already in use, retry
in 2 second
And i still dont get any background on the app.(its all black.)
and if i print self.sm.current on the touich function. Then i find that its always page1, it never changes.
The Kivy Guide explains how to add a background to a Widget. Briefly, you can do it in Python using the following code which binds to the position and size of the widget to make sure the background moves with the widget.
with widget_instance.canvas.before:
Color(0, 1, 0, 1) # green; colors range from 0-1 instead of 0-255
self.rect = Rectangle(size=layout_instance.size,
pos=layout_instance.pos)
widget_instance.bind(size=self._update_rect, pos=self._update_rect)
...
def _update_rect(self, instance, value):
self.rect.pos = instance.pos
self.rect.size = instance.size
Or you can do it more naturally with the kv language e.g.
MyWidget:
canvas.before:
Color:
rgba: 0, 1, 0, 1
Rectangle:
# self here refers to the widget i.e screen
pos: self.pos
size: self.size