I'm new to Kivy and having trouble specifying the background color of a Button. Here's my simple example:
# custombutton.py
from kivy.app import App
from kivy.uix.widget import Widget
class MyWidget(Widget):
pass
class CustomButtonApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
CustomButtonApp().run()
And the accompanying kv file custombutton.kv:
#:kivy 1.7.2
<MyWidget>:
canvas:
Color:
rgb: (0.93, 0.93, 0.93)
Rectangle:
pos: self.pos
size: self.size
Button:
center: self.parent.center
font_size: 14
height: 28
background_color: (1.0, 0.0, 0.0, 1.0)
text: "I'm a Button"
I'm sure I'm missing something obvious, but I've been messing with this for over an hour now and getting nowhere. The button seems to get colored a hint of very dark red:
Is this not the way to specify the background color for a Button in Kivy?
Thanks!
It's been a while since this was first posted so maybe with updates they came up with a better solution:
Button:
background_normal: ''
background_color: 1, .3, .4, .85
Since the Button has a default grey, adding background color will only tint the button. By setting background_normal to '' that resets the default to white. From the white canvas the background_color works as you would expect.
Documentation
1) https://kivy.org/docs/api-kivy.uix.button.html?highlight=button#module-kivy.uix.button
Ah, this is a common confusion. The problem is that Button.background_color really works as a kind of tint, not just a block colour. Since the default background is a grey image (the one you normally see if you make an unstyled button), what you end up seeing is a red tint to that grey image - which comes out as the dark red you observe.
You can get the behaviour you want by replacing the background image to just one that's plain white (it doesn't have to be more than a few pixels), or by otherwise playing with the background_normal and background_down properties. When your background_color tints the new pure white image, you get the pure red you're after.
I guess this isn't so clear in the docs, I'll try to improve it.
The problem with using background_normal = '' is that it blows away the kivy button image with raised edges/shadowing and setback. One way to get a raised button of a specific color would be to make your own atlas using gimp or other editors. However, by some trial and error I found that the Button background_color attribute can implement a tint as well as the documented shade. In other words, it can have 'RGB' values > 1. So to get an exact button color with the kivy button defaulttheme for raised edges, use:
import numpy as np
# the defaulttheme for kivy buttons is grey 88,88,88
kivy_defaulttheme_color = np.array([88,88,88,256])/256
desired_button_color = np.array([78,101,115,256])/256
tintshade_color = desired_button_color / kivy_defaulttheme_color
Button(background_color = tintshade_color)
which demonstrates both a tint and a shade.
Related
I was wondering if there is a way to get a static background in a Kivy application with a screen manager. With static, I mean that the background remains as it is, even when switching screens. I am using a .kv file for the layout. I'd guess it has something to do with the placement order within a .kv file.
Thanks!
You can use a float layout as the root widget in every screen and add to that float layout the image and the other layout in your screen, here is a code example in kv:
Screen: # Screen 1
id: Home
FloatLayout:
Image:
source: "path to the image"
BoxLayout: # Here you put your other layout
# And here the code you had
Screen: # Screen 2
id: Another Screen
FloatLayout:
Image:
source: "path to the image"
BoxLayout: # Here you put your other layout
# And here the code you had
This is the solution that I know, it might not be perfect for you, but I will leave the other options to others...
FloatLayout:
Image:
ScreenManager:
would be enough I think but be careful, if the transition of ScreenManager is ShaderTransition(or a sub-class thereof), it doesn't respect the pixels in the background, so the animation during the transition may not work properly.
I have a kivy program that has a ‘sqlite’ database containing details of a golf competition which displays information & warning messages via a standard Pop-up function - pop_mess()
For testing purposes I open an alternative ‘testing’ database in a function – set_test_db(). When this is done I would like to change the background colour of the pop-up to warn the user that the main database is not being used.
I have tried to do this (code at end of 'set_test_db'). However although the routine retrieves the current background colour correctly it will not change it.
Can someone point me in the direction of a solution. The coding method works fine for changing the text properties of a widget. (similar questions usually refer to text properties). I have used both list & tuple for colour values.
In .ky file
<CustomPopup>:
popup_message: popup_message
size_hint: .98, .75
id: popup_id
title: "Casual and Ancient"
title_align: 'center'
title_color: 1,.5,.3,1
BoxLayout:
id: contentbox
orientation: 'vertical'
TextInput:
id: popup_message
color: .3,.4,1.0,1
background_color: [.7,1.0,.2,1]
text: "text message goes here"
font_size: 16
font_name: 'RobotoMono-Regular'
…..
CaaRoot:
<CaaRoot>:
orientation: 'lr-tb'
padding: 10
etc
...
in main.py
(self = CaaRoot)
...
def pop_mess(self,message):
p_up=CustomPopup()
lab=p_up.ids['popup_message']
lab.text=message
p_up.open()
...
def set_test_db(self):
# on button in CaaRoot
# open test data base instead of real
if self.db != None:
print 'Cannot Open Test Data Base - already running'
else:
# open ‘test’ database
# set background colour of popup to warn user.
fn='/home/.... caatestdb.db
self.op_db(fn)
self.testing='TEST database'
p_up=CustomPopup()
lab=p_up.ids['popup_message']
x=lab.background_color
new_col=[.9,.3,.3,1]
lab.background_color=new_col
self.pop_mess('color set to : '+str(new_col)+ ' was : '+str(x))
the popup displays
color set to : [0.9, 0.3, 0.3, 1] was : [0.7, 1.0, 0.2, 1]
(with background still set to [0.7, 1.0, 0.2, 1])
Have a look at kivymd, which solves issues like that very well. It is basically a very elegant template for kivy based on Google's Material Design.
For me it makes all the coloring stuff and appearance in general much easier, especially as I am not a designer but a programmer.
The Demo has also a very complete sets of examples including popups.
On further investigation of my problem I came across the similar question (Changing Background of Kivy Popup )
The fact that the solution given to that was “non-intuitive” involving the properties of the ‘inherited’ Canvas element(?) made me realise (remember ?) than some widgets do not have the full range of modifiable properties.
The 'background_color' property that I was retrieving was a property inherited from the Canvas which cannot be easily changed.
I have avoided the problem by creating a ‘popup’ widget whenever I wish to use it rather than modifying an existing widget. I still cannot (simply) change the background_color of the popup but I can change the background color of the parent element so that the user’s eye immeditely sees something different. I can also change the text color when calling the popup message function.
def pop_mess(self,message,colour=(.9,.6,.9,1)):
#
# text color can ve overridden by the 'colour' parameter
# self.backc can be set as required to set the color behind the
# popup depending on circumstances
popup=Popup(title='Casual & Ancient', \
content=Label(text=message,color=colour,\
font_name = 'RobotoMono-Regular'),\
size_hint=(.98,.75),background_color=self.backc)
popup.open()
I'm not completely sure that the analysis is correct or that there may be some side-effects but it seems to work ok (and was somewhat simpler to code)
I'm using Kivy with Python 2.7. I am familiar with how to alter the color of the static button itself, but how do you change the color of the button when you press it? The default is blue.
Thanks for any help.
According to the reference for Button, the property background_down stores the path to an image used for the background while the Button is pressed. This is the default:
background_down = StringProperty(
'atlas://data/images/defaulttheme/button_pressed')
You can change that property to point to a different image oratlas.
The Kivy framework uses background images for button_normal and button_down, which the background_color only tints, so this in the kv language might not behave how you'd expect:
<Button>:
background_color: 1, 0, 0 # Tints the button red
background_normal: 'images/button_normal.png' # A clear image gives a bright red.
background_down: 'images/button_down.png' # A gray image gives a duller red.
border: (2, 2, 2, 2) # Don't stretch the outer two pixels on each edge when resizing.
This style lets you have say a dull border and bright inner and swap them round on the button press.If you use this system though, images will be imported with colours ignored. To fix this and solve your problem remove the background_color:
<Button>:
background_normal: 'images/button_normal.png' # Eg. A red button
background_down: 'images/button_down.png' # Eg. A green button
border: (2, 2, 2, 2) # Don't stretch the outer two pixels on each edge when resizing.
That'll change the colour of the buttons to whatever you've made in the image. It's worth noting that Kivy is excellent at stretching the images out, so if you have single colour buttons or tiny borders, you only need a tiny image, I use 8x8 pixels.
I am making a BoxLayout widget (orientation = 'horizontal') that contains three widgets inside of it, a label, a text box, and a check box.
thisRow = BoxLayout(orientation='horizontal')
l = Label(text='Enter plate 1:\n(Plate #)')
t = TextInput(text = 'this is a text box')
c = CheckBox()
thisRow.add_widget(l)
thisRow.add_widget(t)
thisRow.add_widget(c)
This produces the following widget (thisRow):
After the box is checked...
The rightmost black box is actually the checkbox, and works functionally, however there is no way for the user to know that it is in fact a checkbox. I would expect a smaller empty square in the middle, as is depicted in pictures here.
How do i get the traditional checkbox image (smaller empty square box)? Or generally, how can I make it more obvious that the box is a check box and not just an empty label?
Thank you
This is really interesting question and Malonge tried it in a good way. Right now(1.9.2-dev) there is still fixed size on CheckBox's well, call it a background. It's an image that Widget takes from atlas and changes if the state changes. Therefore until now there was no clear way how to do it. Here is an example. Soon on master there'll be CheckBox(color=[r,g,b,a]) option. Thanks ;)
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<CheckBoxBG>:
Label:
TextInput:
CheckBox:
canvas.before:
Color:
rgb: 1,0,0
Rectangle:
pos:self.center_x-8, self.center_y-8
size:[16,16]
Color:
rgb: 0,0,0
Rectangle:
pos:self.center_x-7, self.center_y-7
size:[14,14]
''')
class CheckBoxBG(BoxLayout):pass
runTouchApp(CheckBoxBG())
Looks like the smaller check box is hidden when the background color is black. Here is an example of a red background.
It's not ideal because I do like the black background, but I can run with it for now. If anyone knows how to do this with a black background that would be great. Thank you
Alternatively, to change your checkboxes background, you can use another image from the atlas or create images and then load them:
mycheckbox= CheckBox(
background_checkbox_normal ='tlas://data/images/defaulttheme/button_disabled'
background_checkbox_down = 'my_checkboxes_checked.png'
)
In Kivy 1.9.2.dev0 (and apparently since version 1.9.0) you can change the background image of checkboxes. By default, Kivy uses for these backgrounds from the atlas*.
background_checkbox_normal = StringProperty('atlas://data/images/defaulttheme/checkbox_off') #when the checkbox is not active.
background_checkbox_down = StringProperty('atlas://data/images/defaulttheme/checkbox_on') # when the checkbox is active.
background_checkbox_disabled_normal = StringProperty('atlas://data/images/defaulttheme/checkbox_disabled_off') #when the checkbox is disabled and not active.
background_checkbox_disabled_down = StringProperty('atlas://data/images/defaulttheme/checkbox_disabled_on') #when the checkbox is disabled and active.
You can have a look here at all the attributes :
*The atlas is a package of multiple textures that reduces the number of images loaded and speedup the application loading. You have see a preview of the atlas in Python Install Folder\Lib\site-packages\kivy\data\images\defaulttheme-0.png
I'm trying to use Kivy to display a background image, so I want the root widget to be the same size as the image. Currently, when I load the image from the kv file it appears as a small thumbnail in the bottom-left corner. The app window appears to be about the correct (full-scale) size, but hard to tell. Code below, any thoughts?
.kv file:
#:kivy 1.8.0
<BarBot_splash>:
BoxLayout:
size: image.size
Image:
id: image
source: 'MainMenu.png'
.py file:
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.widget import Widget
class BarBot_splash(Widget):
def on_touch_up(self, touch):
if touch.x < self.width/3:
#we touched the menu button
pass
elif touch.x > self.width/3*2:
#we touched the custom button
pass
else:
return False
class BarBot(App):
def build(self):
return BarBot_splash()
if __name__=='__main__':
BarBot().run()
In main.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class BarBot_splash(BoxLayout): # subclass BoxLayout.. now it's inherently a Boxlayout
kv:
#:kivy 1.8.0
<BarBot_splash>: # I'm a BoxLayout...
Image:
id: image
source: 'MainMenu.png'
That should do the trick. The BoxLayout should take up the window. It's one child, the Image, should in turn take up the full size of the BoxLayout. Why? Well, someone correct me if I'm wrong, but I think it's because the size_hint property of the BoxLayout and the Image both default to (1, 1), which translates to: "Take up as much space in your parent as you can" or (100% width, 100% height). Though it may not be possible for a child to take up all of it's parents area if there are also other children in the parent, like if you had a few Images in the BoxLayout, or more than one BoxLayout in your app etc.. Setting a size_hint to (.5, .3) would mean take up (50% the width, 30% the height) of your parent/container, or available space.
BarBot_splash is just a widget, so it doesn't apply any position or size to its children, therefore the boxlayout (and thus its child image) have only the default position of (0, 0) and size of (100, 100).
Change BarBot_splash to a BoxLayout or other resizing layout and this will propagate correctly. You also don't need the size: image.size line, this does nothing.
Obviously very old question but I'm new to Kivy and just had to work through a very similar problem and there was very little help on the topic, so this is for future people like me:
I had the same problem but the image was also in a scatter widget. Solution is really simple, just frustrating to find. Hierarchy has to be as follows:
BoxLayout:
Scatter:
size: image.size
Image:
id: image
size: root.size