I'm trying to periodically run the animation of canvas circle line by changing its angle using a numeric property called "level" so it refreshes every second by creating a Clock object but the animation simply won't run. In the other hand I also have a different method been called from the .kv file when user inputs 'r' in a text input that animates that "level" numeric property and the animation runs perfectly.
I've noticed that in both cases the value of "level" is different as if there were 2 different instances of level. I do not understand what is going on, can some one shed some light on what I'm doing wrong?
Notice that the animation is affecting the widgets with id "gauge and needle" on my .kv file under the "tachometer" commented section
import kivy
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.properties import *
from kivy.animation import Animation
import kivy.graphics
from kivy.clock import Clock
from math import cos, sin, pi
from functools import partial
import random
def rpm_conversion(rpm):
return (rpm * (180.5/8000) -135.5)
####################################################
#---------------------- GUI -----------------------#
class DataWindow(GridLayout):
def rpmupdate(self,dt):
rand = random.randint(0,8000)
gaugranim = Animation(level = rpm_conversion(float(rand)))
print("Timer triggered: " + str(self.level))
self.rpm = int(rand)
gaugranim.start(self)
def on_enter(self, value):
print(value[5:] )
self.display.text = "ecu> "
rand = random.randint(0,8000)
if(value[5:] == "r"):
anim = Animation(level = rpm_conversion(float(rand)) )
print("User triggered: " + str(self.level))
self.rpm = int(rand)
anim.start(self)
#Keeps user from deleting name in console
def bashlook(self,value, crs):
if(value[:5] != 'ecu> '):
self.display.text = "ecu> "
class OpensecuApp(App):
def build(self):
clock = DataWindow()
Clock.schedule_interval(clock.rpmupdate, 2)
return DataWindow()
if __name__ == '__main__':
OpensecuApp().run()
.kv:
#:import math math
[GaugeNumber#Label]:
text: str(ctx.i)
pos_hint: {"center_x": 0.5+0.42*math.sin(math.pi/8*(ctx.i-6)), "center_y": 0.5+0.42*math.cos(math.pi/8*(ctx.i-6))}
font_size: self.height/24
<DataWindow>:
id: opensecu
display: cmd
level: -135
rpm: 0
# Main window
rows:2
spacing: 10
padding: 10
canvas:
Color:
rgba: 0.1,0.1,0.1,1
Rectangle:
pos: self.pos
size: self.size
##########################################################
GridLayout:
size_hint: 1,1
cols: 3
#-------------------------- Data -----------------------------#
#Data
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 1"
#---------------------- Tachometer RPM ------------------------#
BoxLayout:
size_hint: 1.5,1
canvas.before:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
FloatLayout: #gauges numers
size_hint:None,None
size: (min(self.parent.size) * 0.95 ) , (min(self.parent.size) * 0.95 )
GaugeNumber:
i: 0
GaugeNumber:
i: 1
GaugeNumber:
i: 2
GaugeNumber:
i: 3
GaugeNumber:
i: 4
GaugeNumber:
i: 5
GaugeNumber:
i: 6
GaugeNumber:
i: 7
GaugeNumber:
i: 8
AnchorLayout: #gauges dots
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.68 ) , (min(self.parent.size) * 0.68 )
Image:
source: "resources/gauge.png"
size: self.texture_size
AnchorLayout: #gauges level rail
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0.1,0.1,0.1,1
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135.5, 45, 500)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
AnchorLayout: #gauge's levels
id: gauge
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135, root.level , 50)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
AnchorLayout: #blue line in gauge
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.width, self.height) / 100
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, 0, 360 , 50)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , (min(self.parent.size) * 0.38 )
BoxLayout: #gauge real time RPMS
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: str(int(root.rpm))
pos_hint: {"center_x": 0.5, "center_y": 0.65}
font_size: self.height / 6
BoxLayout:#gauges RPM note
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "RMP"
pos_hint: {"center_x": 0.5, "center_y": 0.35}
font_size: self.height / 12
BoxLayout:#gauges x1000
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "x1000"
pos_hint: {"center_x": 0.5, "center_y": 0.25}
font_size: self.height / 10
FloatLayout: #gauges needle
id: needle
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.60 ) , (min(self.parent.size) * 0.60 )
Image:
source: "resources/needle.png"
size: self.texture_size
pos_hint: {'center_x': .5, 'center_y': .5}
canvas.before:
PushMatrix
Rotate:
angle: (root.level)* (-1)
origin: self.center
canvas.after:
PopMatrix
#------------------------ Volumetric Efficiency Table -------------------------#
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 3"
###################################################################
#------------------------ Console -------------------------#
BoxLayout:
size_hint: 1,0.3
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
TextInput:
id: cmd
text: "ecu> "
background_color: 0.12,0.1195,0.122,1
foreground_color: 1,1,1,1
boold: 1
padding: 15
multiline: False
on_text: opensecu.bashlook(self.text, self.cursor)
on_text_validate: opensecu.on_enter(self.text)
# on_key_down:opensecu.on_enter(self.text)
The solution I found was creating object properties so I could have specific custom properties for each widget I needed to add animation.
python:
import kivy
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.uix.textinput import TextInput
from kivy.properties import *
from kivy.animation import *
import kivy.graphics
from kivy.clock import Clock
from math import cos, sin, pi
from functools import partial
import random
def rpm_conversion(rpm):
return (rpm * (180.5/8000) -135.5)
####################################################
#---------------------- GUI -----------------------#
class Gaugenumber(Label)
class OpensecuGauge(AnchorLayout):
gauge_level = NumericProperty(-135)
def gauge_anim(self,dt):
anim = Animation(gauge_level = rpm_conversion(float(readings[0])), d=0.5 )
anim.start(self)
class OpensecuNeedle(Image):
needle_level = NumericProperty(-135)
def needle_anim(self,dt):
# print(level)
anim = Animation(needle_level = rpm_conversion(float(readings[0])) , d=0.5)
anim.start(self)
class OpensecuWindow(GridLayout):
gauge = ObjectProperty(None)
needle = ObjectProperty(None)
def start(self):
Clock.schedule_interval(self.gauge.gauge_anim, 0.5)
Clock.schedule_interval(self.needle.needle_anim, 0.5)
Clock.schedule_interval(self.rpm_update, 0.5)
def rpm_update(self,dt):
anim = Animation(rpm = float(readings[0]), d=0.5)
anim.start(self)
def on_enter(self, value):
print(value[5:] )
self.display.text = "ecu> "
rand = random.randint(0,8000)
# print(self.gauge.level)
if(value[5:] == "r"):
pass
elif(value[5:]=="connect"):
cnnct()
self.start()
elif(value[5:]=="exit"):
stp()
else:
pass
#Keeps user from deleting name in console
def bashlook(self,value, crs):
if(value[:5] != 'ecu> '):
self.display.text = "ecu> "
class OpensecuApp(App):
def build(self):
# clock = OpensecuWindow()
# Clock.schedule_interval(clock.gauge.rpmupdate, 2)
connection = OpensecuWindow()
connection.start()
return OpensecuWindow()
if __name__ == '__main__':
OpensecuApp().run()
exit()
.kv:
#:import math math
[GaugeNumber#Label]:
text: str(ctx.i)
pos_hint: {"center_x": 0.5+0.42*math.sin(math.pi/8*(ctx.i-6)), "center_y": 0.5+0.42*math.cos(math.pi/8*(ctx.i-6))}
font_size: self.height/24
<OpensecuGauge>:
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
<OpensecuNeedle>:
source: "resources/needle.png"
size: self.texture_size
pos_hint: {'center_x': .5, 'center_y': .5}
canvas.after:
PopMatrix
<OpensecuWindow>:
id: opensecu
display: cmd
needle: needle
gauge: gauge
# level: -135
# needle_level: -135
rpm: 0
# Main windows
rows:2
spacing: 10
padding: 10
canvas:
Color:
rgba: 0.1,0.1,0.1,1
Rectangle:
pos: self.pos
size: self.size
##########################################################
GridLayout:
size_hint: 1,1
cols: 3
#-------------------------- Data -----------------------------#
#Data
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 1"
#---------------------- Tachometer RPM ------------------------#
BoxLayout:
size_hint: 1.5,1
canvas.before:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
FloatLayout: #gauges numers
size_hint:None,None
size: (min(self.parent.size) * 0.95 ) , (min(self.parent.size) * 0.95 )
GaugeNumber:
i: 0
GaugeNumber:
i: 1
GaugeNumber:
i: 2
GaugeNumber:
i: 3
GaugeNumber:
i: 4
GaugeNumber:
i: 5
GaugeNumber:
i: 6
GaugeNumber:
i: 7
GaugeNumber:
i: 8
AnchorLayout: #gauges dots
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.68 ) , (min(self.parent.size) * 0.68 )
Image:
source: "resources/gauge.png"
size: self.texture_size
OpensecuGauge: #gauges level rail
canvas.before:
Color:
rgba: 0.1,0.1,0.1,1
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135.5, 45, 500)
cap: 'none'
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
OpensecuGauge: #gauges levels
id: gauge
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.size)/15
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, -135, self.gauge_level , 50)
cap: 'none'
size: (min(self.parent.size) * 0.5 ) , (min(self.parent.size) * 0.5 )
AnchorLayout: #blue line in gauge
anchor_x: 'center'
anchor_y: 'center'
canvas.before:
Color:
rgba: 0,0.93,1,0.5
Line:
width: min(self.width, self.height) / 100
circle:
(self.center_x, self.center_y, min(self.width, self.height)
/ 2, 0, 360 , 50)
cap: 'none'
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , (min(self.parent.size) * 0.38 )
BoxLayout: #gauge real time RPMS
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: str(int(root.rpm))
pos_hint: {"center_x": 0.5, "center_y": 0.65}
font_size: self.height / 6
BoxLayout:#gauges RPM note
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "RMP"
pos_hint: {"center_x": 0.5, "center_y": 0.35}
font_size: self.height / 12
BoxLayout:#gauges x1000
size_hint:None,None
size: (min(self.parent.size) * 0.38 ) , ((min(self.parent.size) * 0.38) )
Label:
text: "x1000"
pos_hint: {"center_x": 0.5, "center_y": 0.25}
font_size: self.height / 10
FloatLayout: #gauges needle
anchor_x: 'center'
anchor_y: 'center'
size_hint:None,None
size: (min(self.parent.size) * 0.60 ) , (min(self.parent.size) * 0.60 )
OpensecuNeedle:
id: needle
canvas.before:
PushMatrix
Rotate:
angle: (self.needle_level)* (-1)
origin: self.center
#------------------------ Volumetric Efficiency Table -------------------------#
BoxLayout:
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: "I'm label 3"
###################################################################
#------------------------ Console -------------------------#
BoxLayout:
size_hint: 1,0.3
canvas:
Color:
rgba: 0.12,0.1195,0.122,1
Rectangle:
pos: self.pos
size: self.size
TextInput:
id: cmd
text: "ecu> "
background_color: 0.12,0.1195,0.122,1
foreground_color: 1,1,1,1
boold: 1
padding: 15
multiline: False
on_text: opensecu.bashlook(self.text, self.cursor)
on_text_validate: opensecu.on_enter(self.text)
# on_key_down:opensecu.on_enter(self.text)
Related
I'm trying to change the background color of the Recycleview table based on the data value of the cells. So, I'would like to change the color only the in the cells containing a specific string of text.
The Goal is to change the color when text is = '1'
Somebody could help?
Here is my code, a simple working app.
.py file:
from kivy.core.window import Window
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
class ScreenManagement(ScreenManager):
pass
class Sfondo_tabella(RecycleDataViewBehavior, Label):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(False)
class RecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout):
pass
class Schermo_1(Screen):
data_list = ['1', '2', '3', '2', '1', '3', '3', '2', '1']
class Temp_kvApp(App):
Window.size = (1182, 739)
if __name__ == "__main__":
Temp_kvApp().run()
.kv file:
ScreenManager:
id: screen_manager
name: "screen_manager"
Schermo_1:
id: schermo_1
name: "Schermo_1"
manager: screen_manager
<Sfondo_tabella>:
color: 0,0,0,1
font_size: self.height * 0.5
text_size: self.width, None
valign: 'top'
halign: 'center'
canvas.before:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba:0,0,0,1
Line:
width:0.5
rectangle:(self.x,self.y,self.width,self.height)
<Schermo_1>
BoxLayout:
orientation: "vertical"
GridLayout:
size_hint: 1, 0.1
height: 50
cols: 1
Label:
font_size: self.height / 1.75
text_size: self.width, None
valign: 'top'
halign: 'left'
color: 1, 1, 1 ,1
text: ""
canvas.before:
Color:
rgb: 0.803, 0.486, 0.176
Rectangle:
pos: self.pos
size: self.size
GridLayout:
id: tasti
size_hint: 1, 0.075
cols: 3
#COL_1
Button:
id: col_1
text: "COL_1"
size_hint_x: 0.33
font_size: self.height / 2.5
text_size: self.width, None
valign: 'top'
halign: 'center'
background_color: 1.22, 1.22, 1.22, 1
#COL_2
Button:
id: col_2
text: "COL_2"
size_hint_x: 0.33
font_size: self.height / 2.5
text_size: self.width, None
valign: 'top'
halign: 'center'
background_color: 1.22, 1.22, 1.22, 1
#COL_3
Button:
id: col_3
text: "COL_3"
size_hint_x: 0.33
font_size: self.height / 2.5
text_size: self.width, None
valign: 'top'
halign: 'center'
background_color: 1.22, 1.22, 1.22, 1
BoxLayout:
RecycleView:
id: tabella_lista_costi_aggiuntivi
viewclass: 'Sfondo_tabella'
data: [{'text': str(x)} for x in root.data_list]
scroll_y: 1
effect_cls: "ScrollEffect" # prevents overscrolling
RecycleGridLayout:
cols: 3
cols_minimum: {0: col_1.width, 1: col_2.width, 2: col_3.width}
size_hint: 1, None
default_size: None, dp(col_1.height/1.75)
default_size_hint: 1, None
height: self.minimum_height
width: self.minimum_width
This can be done in the canvas.before instruction under <Sfondo_tabella> section like below:
<Sfondo_tabella>:
color: 0,0,0,1
font_size: self.height * 0.5
text_size: self.width, None
valign: 'top'
halign: 'center'
canvas.before:
Color:
rgba: (0, 1, 0, 1) if root.text == '1' else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba:0,0,0,1
Line:
width:0.5
rectangle:(self.x,self.y,self.width,self.height)
Here the background of the cell would be green if the cell text is '1' otherwise it would be white.
the two windows in the picture are exact copies(same line of code), only difference being that the right window is a screen inside a screen manager, but somehow the window on the right does not show the texts.
i'm not sure what the problem is and can't find anything related to it while doing research.
RIGHT WINDOW PYTHON FILE:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.config import Config
space = ""
x = [(a * 9), (a*16)]
Config.set('graphics', 'width', x[0])
Config.set('graphics', 'height', x[1])
class MainScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ThirdScreen(Screen):
pass
kv = Builder.load_file("main2.kv")
class ComplimentUI(App):
def build(self):
return kv
def change_screen(self, x):
scrnmanager = self.root.ids['sm']
scrnmanager.current = x
if __name__ == "__main__":
ComplimentUI().run()
RIGHT WINDOW BUILDER FILE:(main2.kv)
#:include secondscreen.kv
#:include thirdscreen.kv
<MainScreen>:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
FloatLayout:
TextInput:
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1,.1
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 0,0,0,0
Button:
text: "PLAY!"
pos_hint: {'center_x':.5, 'center_y':.3}
size_hint: .8, .17
font_name: "Splatch"
color: 0.15, .5, 0.2, 1
font_size: 0.14 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
ScreenManager:
GridLayout:
cols: 1
ScreenManager:
id: sm
MainScreen:
name: "screenone"
id: screenone
SecondScreen:
name: "screentwo"
id: screentwo
ThirdScreen:
name: "thirdscreen"
id: thirdscreen[enter image description here][1]
LEFT WINDOW PYTHON FILE:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
space = "";
x = [(a * 9), (a*16)]
Config.set('graphics', 'width', x[0])
Config.set('graphics', 'height', x[1])
kv = Builder.load_file("main.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyMainApp().run()
LEFT WINDOW BUILDER FILE:(main.kv)
FloatLayout:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
TextInput:
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1,.1
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 0,0,0,0
Button:
text: "PLAY!"
pos_hint: {'center_x':.5, 'center_y':.3}
size_hint: .8, .17
font_name: "Splatch"
color: 0.15, .5, 0.2, 1
font_size: 0.14 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
NEW EDIT:
as i pointed out in the comment below, the same problem happens with the FloatLayout of secondscreen.kv and thirdscreen.kv, if i put it inside the builder file of the left window, its normal. But when i put it inside a screen inside a screen manager(like the right window) it's gone. the same problem happens to all my screens. the reason i only put the mainscreen.kv is because its the shortest out of all the screens, but nonetheless i will still provide the files, but only 1 version of it (the one used for the right window) since they're basically the same lines. (only difference being the added first line for its class name and a slight indetation change to fit the levels)
SECONDSCREEN BUILDER FILE:
<SecondScreen>:
FloatLayout:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
TextInput:
pos_hint: {'center_x':.5, 'center_y':.56}
size_hint: .8, .3
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 1, 1, .8, 1
Label:
pos_hint: {'center_x':.5, 'center_y':.76}
size_hint: .8, .07
text: "NAME!"
font_size: 0.8 * self.height
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
background_color: 0,0,0,0
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
Button:
text: "<<<"
size_hint: .28, .07
pos_hint: {'center_x':.24, 'center_y':.1}
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
font_size: 0.35 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screenone")
root.manager.transition.direction = "right"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
Button:
pos_hint: {'center_x':.8, 'center_y':.35}
size_hint: .2, .07
background_normal: ''
background_color: 0,0,0,0
color: 0.15, .5, 0.2, 1
text: "ENTER"
font_name: "kidsrock"
font_size: 0.25 * self.width
on_press:
print("pressed, navigating to next screen")
app.change_screen("thirdscreen")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
THIRDSCREEN BUILDER FILE:
<ThirdScreen>:
FloatLayout:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
TextInput:
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1, .1
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 0, 0, 0, 0
Label:
pos_hint: {'center_x':.5, 'center_y':.71}
size_hint: .8, .17
text: "COMPLIMENT!"
font_size: 20
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
background_color: 0,0,0,0
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
Button:
pos_hint: {'center_x':.24, 'center_y':.1}
size_hint: .28, .07
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
font_size: 0.35 * self.width
text: "<<<"
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "right"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
NEW- NEW EDIT!:
UPDATE
after restarting my computer, it now looks like this.
Root Cause - Button & Label text not showing
The most probable cause is that the default color for text is white ([1, 1, 1, 1]), and the background color for both widgets are also white. You need to set the text color to non-white e.g. black ([0, 0, 0, 1]).
TextInput Box - not showing
The TexInput box is not visible in both windows (left & right) because of background_normal: '' and background_color: 0,0,0,0.
Comment them off and the TextInput box will be visible.
Button's text, 'PLAY' - not showing in right window
It could be something in the include kv files e.g. secondscreen.kv, and/or thirdscreen.kv that are/is causing the visibility. Comment off both kv files to trouble shoot the problem.
Example
The following example of the right window i.e. using ScreenManager is able to display the Button's text, "PLAY" and also the TextInput box.
main-right.py
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
class MainScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ThirdScreen(Screen):
pass
kv = Builder.load_string("""
# :include secondscreen.kv
# :include thirdscreen.kv
<MainScreen>:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
FloatLayout:
TextInput:
hint_text: 'Type here'
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1,.1
multiline: False
font_size: 20
# font_name: "Dimbo Regular"
# background_normal: ''
# background_color: 0,0,0,0
Button:
text: "PLAY!"
pos_hint: {'center_x':.5, 'center_y':.3}
size_hint: .8, .17
#font_name: "Splatch"
color: 0.15, .5, 0.2, 1
font_size: 0.14 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgba: 1, 1, .8, 1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
GridLayout:
cols: 1
ScreenManager:
id: sm
MainScreen:
name: "screenone"
id: screenone
SecondScreen:
name: "screentwo"
id: screentwo
ThirdScreen:
name: "thirdscreen"
id: thirdscreen
""")
class RightWindow(App):
title = "ComplimentUI"
def build(self):
return kv
if __name__ == "__main__":
RightWindow().run()
Output
I was facing a similar problem and the bug for me turned out to be a declaration of size_hint_x for the button. Once I removed that, the text was visible.
I want my CustomLabels and CustomToggleButtons, which I have created, to change their sizes according to different Window sizes. So this was what I did.
lbl = CustomLabel(text=text, width=self.grid_layout.width, >height=self.grid_layout.height*.5)
btn = CustomToggleButton(group=text, text=config_type[i], width=40 + >len(config_type[i]) * 20, height=self.grid_layout.height * .5)
What I did was set the above widgets' heights and widths above proportionate to a GridLayout containing them. The GridLayout's size is relative to the MainScreen. So if I change the Window size, the GridLayout would follow, followed by the widgets.
However, it did not work. Whenever I change the Window size, the CustomLabels and ToggleButtons would remain the same in size. Would appreciate some help, thanks!
This is the full code:
Builder.load_string('''
#:import hex kivy.utils.get_color_from_hex
<CustomButton>
font_size: self.width * .1
background_color: hex('#669999')
<CustomToggleButton>:
background_color: hex('#669999')
font_size: self.height*.5
size_hint: None, None
# height: self.parent.parent.height * .1
<CustomLabel>:
font_size: self.height * .5
size_hint: None, None
text_size: self.size
halign: 'left'
# width: self.parent.parent.width
# height: self.parent.parent.height * .1
<CustomBoxLayout>:
orientation: 'vertical'
<CustomStackLayout>:
size_hint_y: None
height: self.minimum_height
spacing: 10
<TempBoxLayout>:
spacing: 10
CustomBoxLayout:
spacing: 10
CustomButton:
text: 'Temp Up'
CustomButton:
text: 'Temp Down'
Label:
text: '20'
font_size: self.width * .1
canvas.before:
Color:
rgba: hex('#000000')
Rectangle:
pos: self.pos
size: self.size
<MainScreen>:
grid_layout: grid_layout
CustomBoxLayout:
padding: 10
spacing: 10
canvas.before:
Color:
rgba: hex('#669999')
Rectangle:
size: self.size
pos: self.pos
GridLayout:
id: grid_layout
canvas.before:
Color:
rgba: hex('#000000')
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_y: .4
BoxLayout:
size_hint_x: .25
TempBoxLayout:
BoxLayout:
size_hint_x: .25
''')
class CustomButton(Button):
pass
class CustomToggleButton(ToggleButton):
pass
class CustomLabel(Label):
pass
class CustomBoxLayout(BoxLayout):
pass
class CustomStackLayout(StackLayout):
pass
class TempBoxLayout(BoxLayout):
pass
class MainScreen(Screen):
store = JsonStore('remote_config.json')
power = str(store['power'][0])
mode = str(store['modes'][0])
fan_speed = str(store['fan_speed'][0])
swing = str(store['swing'][0])
louver = str(store['louver'][0])
min_temp = store['min_temp']
max_temp = store['max_temp']
curr_temp = min_temp
temp_interval = store['interval']
config = [store['power'], store['modes'], store['fan_speed'], store['swing'], store['louver']]
titles = ['Power', 'Mode', 'Fan', 'Swing', 'Louver']
grid_layout = ObjectProperty()
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.grid_layout.rows = 0
print(self.power, self.mode, self.fan_speed, self.swing, self.louver)
for i in range(len(self.config)):
self.populate_controls(self.config[i], self.titles[i])
def populate_controls(self, config_type, text):
if len(config_type) is not 1:
if config_type != 'not available':
stack_layout = CustomStackLayout()
self.grid_layout.rows += 1
lbl = CustomLabel(text=text, width=self.grid_layout.width, height=self.grid_layout.height*.5)
stack_layout.add_widget(lbl)
for i in range(len(config_type)):
btn = CustomToggleButton(group=text, text=config_type[i], width=40 + len(config_type[i]) * 20,
height=self.grid_layout.height * .5)
if i is 0:
btn.state = 'down'
stack_layout.add_widget(btn)
self.grid_layout.add_widget(stack_layout)
class TestApp(App):
def build(self):
return MainScreen()
if __name__ == '__main__':
TestApp().run()
This is the JSON file:
{
"power": ["off", "on"],
"min_temp": 18,
"max_temp": 32,
"interval": 1,
"modes": ["cool", "fan", "dry"],
"fan_speed": ["auto", "low", "med-low", "med", "med-high", "high"],
"swing": ["off", "auto"],
"louver": ["off", "auto"]
}
I think the easiest fix is to use size_hint. Try changing your CustomLabel and CustomTogglebutton definitions in your kv to:
<CustomToggleButton>:
background_color: hex('#669999')
font_size: self.height*.5
size_hint: 0.1, 0.5
<CustomLabel>:
font_size: self.height * .5
size_hint: 0.1, 0.5
text_size: self.size
halign: 'left'
And you no longer need width and heightspeifications in your Python code for these objects. Also, change CustomStackLayout to:
<CustomStackLayout>:
size_hint_y: 1.0
spacing: 10
I have two file test.py and test.kv .
i run test.py then shows show button.
When i click on show button then def abc call.Can someone tell me how to show array in dynamic label and value(Item1=5000.Item2=1000).
Item1 5000
Item2 1000
I am using array
arr = ({'Item1': 5000},{'Item2': 1000})
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (600, 600)
class Invoice(Screen):
def __init__(self, **kwargs):
super(Invoice, self).__init__(**kwargs)
def abc(self):
#fetching from database
arr = ({'Item1': 5000},{'Item2': 1000})
print(arr)
class Test(App):
def build(self):
self.root = Builder.load_file('test.kv')
return self.root
if __name__ == '__main__':
Test().run()
test.kv
<Button#Button>:
font_size: 15
font_name: 'Verdana'
size_hint_y:None
height: 30
<Label#Label>:
font_size: 15
font_name: 'Verdana'
size_hint_y:None
height: 30
Invoice:
BoxLayout:
orientation: "vertical"
padding : 15, 15
BoxLayout:
orientation: "vertical"
padding : 5, 5
size_hint: .6, None
pos_hint: {'x': .18,}
BoxLayout:
orientation: "horizontal"
padding : 5, 5
spacing: 10, 10
size: 800, 40
size_hint: 1, None
Button:
text: "Show"
size_hint_x: .05
spacing_x: 30
on_press:root.abc()
BoxLayout:
orientation: "horizontal"
size_hint: 1, 1
BoxLayout:
orientation: "vertical"
size_hint: .5, 1
padding : 0, 15
spacing: 10, 10
size: 500, 30
Button:
text: "Invoice"
text_size: self.size
halign: 'center'
valign: 'middle'
GridLayout:
cols: 2
#orientation: "horizontal"
padding : 5, 0
spacing: 10, 0
#size: 500, 30
size_hint: 1, 1
pos: self.pos
size: self.size
Label:
size_hint_x: .35
text: "Item1"
text_size: self.size
halign: 'left'
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint_x: .15
text: "5000"
text_size: self.size
halign: 'right'
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
In your abc() method you can create labels and add them to your layout. In order to do that, I made a few change to your code. I added an id to your GridLayout and changed your custom label class to MyLabel and added it to the py file, so that I could create them in Python. Here is the modified Python file:
from kivy.uix.label import Label
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (600, 600)
class MyLabel(Label):
pass
class Invoice(Screen):
def __init__(self, **kwargs):
super(Invoice, self).__init__(**kwargs)
def abc(self):
#fetching from database
arr = ({'Item1': 5000},{'Item2': 1000})
layout = self.ids['invoices']
for invoice in arr:
for key,val in invoice.items():
lab1 = MyLabel(text=str(key),size_hint_x=.35, halign='left' )
lab2 = MyLabel(text=str(val),size_hint_x=.15, halign='right' )
layout.add_widget(lab1)
layout.add_widget(lab2)
class Test(App):
def build(self):
self.root = Builder.load_file('test.kv')
return self.root
And changes to the kv file included changing Label to MyLabel, moving as much as possible to the MyLabel class, and removing your example labels:
<Button#Button>:
font_size: 15
font_name: 'Verdana'
size_hint_y:None
height: 30
<MyLabel>:
font_size: 15
font_name: 'Verdana'
size_hint_y:None
height: 30
text_size: self.size
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Invoice:
BoxLayout:
orientation: "vertical"
padding : 15, 15
BoxLayout:
orientation: "vertical"
padding : 5, 5
size_hint: .6, None
pos_hint: {'x': .18,}
BoxLayout:
orientation: "horizontal"
padding : 5, 5
spacing: 10, 10
size: 800, 40
size_hint: 1, None
Button:
text: "Show"
size_hint_x: .05
spacing_x: 30
on_press:root.abc()
BoxLayout:
orientation: "horizontal"
size_hint: 1, 1
BoxLayout:
orientation: "vertical"
size_hint: .5, 1
padding : 0, 15
spacing: 10, 10
size: 500, 30
Button:
text: "Invoice"
text_size: self.size
halign: 'center'
valign: 'middle'
GridLayout:
id: invoices
cols: 2
#orientation: "horizontal"
padding : 5, 0
spacing: 10, 0
#size: 500, 30
size_hint: 1, 1
pos: self.pos
size: self.size
Although the option to iterate over the data and generate the widget dynamically is an option, the truth is that it is unbeatable in the long term. If you have structured information it is appropriate to use a design pattern and kivy offers to use a RecycleView for these cases, this implements the MVC pattern, so we just need to pass the data and establish a view where an appropriate adapter can be provided.
In your case it is enough to design a widget that is what is shown in each row:
<Item#GridLayout>:
cols: 2
text: "" # new property
value: 0 # new property
padding : 5, 0
spacing: 10, 0
Label:
size_hint_x: .35
text: root.text
halign: 'left'
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint_x: .15
text: str(root.value)
halign: 'right'
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
And then replace the GridLayout with the RecycleView:
RecycleView:
id: rv
viewclass: 'Item'
RecycleBoxLayout:
default_size: None, dp(30)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
And in the event of the button assign the data, in this case you must convert your data to a list of dictionaries where the fields will be the text and value attribute of Item:
def convert_data(data):
l = []
for item in data:
for key, value in item.items():
l.append({'text': key, 'value': value})
return l
class Invoice(Screen):
def abc(self):
#fetching from database
arr = ({'Item1': 5000},{'Item2': 1000})
# convert to [{'text': 'Item1', 'value': 5000}, {'text': 'Item2', 'value': 1000}]
self.rv.data = convert_data(arr)
Complete Code:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
def convert_data(data):
l = []
for item in data:
for key, value in item.items():
l.append({'text': key, 'value': value})
return l
class Invoice(Screen):
def abc(self):
#fetching from database
arr = ({'Item1': 5000},{'Item2': 1000})
# convert to [{'text': 'Item1', 'value': 5000}, {'text': 'Item2', 'value': 1000}]
self.rv.data = convert_data(arr)
class MyApp(App):
def build(self):
return Builder.load_file('test.kv')
if __name__ == '__main__':
MyApp().run()
test.kv
<Button#Button>:
font_size: 15
size_hint_y:None
height: 30
<Label#Label>:
font_size: 15
size_hint_y:None
height: 30
<Item#GridLayout>:
cols: 2
text: ""
value: 0
padding : 5, 0
spacing: 10, 0
Label:
size_hint_x: .35
text: root.text
halign: 'left'
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint_x: .15
text: str(root.value)
halign: 'right'
valign: 'middle'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
Invoice:
rv: rv
BoxLayout:
orientation: "vertical"
padding : 15, 15
BoxLayout:
orientation: "vertical"
padding : 5, 5
size_hint: .6, None
pos_hint: {'x': .18,}
BoxLayout:
orientation: "horizontal"
padding : 5, 5
spacing: 10, 10
size: 800, 40
size_hint: 1, None
Button:
text: "Show"
size_hint_x: .05
spacing_x: 30
on_press:root.abc()
BoxLayout:
orientation: "horizontal"
size_hint: 1, 1
BoxLayout:
orientation: "vertical"
size_hint: .5, 1
padding : 0, 15
spacing: 10, 10
size: 500, 30
Button:
text: "Invoice"
text_size: self.size
halign: 'center'
valign: 'middle'
BoxLayout:
RecycleView:
id: rv
viewclass: 'Item'
RecycleBoxLayout:
default_size: None, dp(30)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
I'm struggling for hours now, just to be able to customize the style of my TabbedPanel in Kivy. Here is my code:
#: import Utils kivy.utils
BoxLayout:
spacing: 0
padding: 0
canvas:
Color:
rgb: Utils.get_color_from_hex("#1b262d")[:3]
Rectangle:
size: self.size
TabbedPanel:
do_default_tab: False
tab_width: self.size[0] / 2
canvas:
Color:
rgb: Utils.get_color_from_hex("#00ff00")[:3]
Rectangle:
size: self.size
TabbedPanelItem:
background_color: Utils.get_color_from_hex("#1b262d")
text: "PAST"
background_down: ""
background_normal: ""
BoxLayout:
orientation: "vertical"
canvas:
Color:
rgb: Utils.get_color_from_hex("#1b262d")[:3]
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
padding: [10, 12, 10, 12]
spacing: 5
size_hint_y: 0.1
TextInput:
background_color: Utils.get_color_from_hex("#303E46")
foreground_color: [1, 1, 1, 1]
size_hint_x: 0.2
padding: [10, ( self.height - self.line_height ) / 2]
text: "DATES"
TextInput:
size_hint_x: 0.15
padding: [10, ( self.height - self.line_height ) / 2]
text: "TEST"
TextInput:
size_hint_x: 0.2
padding: [10, ( self.height - self.line_height ) / 2]
text: "CAT"
TextInput:
size_hint_x: 0.15
padding: [10, ( self.height - self.line_height ) / 2]
text: "SORT BY"
TextInput:
size_hint_x: 0.15
padding: [10, ( self.height - self.line_height ) / 2]
text: "SHOW ONLY"
TextInput:
size_hint_x: 0.15
padding: [10, ( self.height - self.line_height ) / 2]
text: "SEARCH"
BoxLayout:
size_hint_y: 0.8
spacing: 10
padding: 10
orientation: "horizontal"
canvas:
Color:
rgb: Utils.get_color_from_hex("#303E46")[:3]
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint_x: 0.7
text: "TEST"
Button:
size_hint_x: 0.3
text: "TESTS"
TabbedPanelItem:
background_color: Utils.get_color_from_hex("#303E46")
text: "UPCOMING"
background_down: ""
background_normal: ""
here is the resulting window:
I actually highlighted in green the part I want to remove. I don't want this green part in the picture, that is to say I want my tab to be next to my content without this weird border.
Obviously If I don't force the canvas to be green I'll see something like this:
And so I see there is a gap between my TabbedPanelItem and my content and I don't know how to delete it. I've tried to force border to 0, strip_border to 0, change the height of my widget, force the background_image to "", etc but I am not able to achieve why I want.
Can an expert of Kivy help me out ?
Thank you in advance
It's more tricky that I suspected...
Buttons are stored inside _tab_layout property of TabbedPanel. It's a GridLayout subclass and you can alter its padding property. Here's an example:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
Builder.load_string('''
<StripLayoust>:
canvas:
Color:
rgba: (0, 1, 0, 1) # green
Rectangle:
size: self.size
pos: self.pos
<MainClass>:
TabbedPanel:
id: panel
do_default_tab: False
TabbedPanelItem:
text: "1"
Widget:
canvas:
Color:
rgb: 0.1, 0.3, .02
Rectangle:
size: self.size
pos: self.pos
TabbedPanelItem:
text: "2"
Widget:
canvas:
Color:
rgb: 0.7, 0.6, .02
Rectangle:
size: self.size
pos: self.pos
''')
class MainClass(FloatLayout):
def __init__(self, *args):
super(MainClass, self).__init__(*args)
self.ids["panel"]._tab_layout.padding = '2dp', '2dp', '2dp', '-2dp'
class TestApp(App):
def build(self):
return MainClass()
if __name__ == '__main__':
TestApp().run()
Note that to remove this border I had to set bottom padding to -2dp and not simply 0dp. Why? Well, as it turned out, every time the panel changes its update_tabs method is called and inside of it there's this cute line:
tab_layout.height = (tab_height + tab_layout.padding[1] +
tab_layout.padding[3] + dp(2))
Adding dp(2) is hard-coded there so I need to use a negative value to counter that.
I use underscore attribute here which is not a part of established public API so this behaviour might change in the future.