I am trying to build a kivy app and I need to put my .py file and .kv file in a file called main.py. How do I do this? Thank you.
You will need to use Builder for this. Docs
The below code illustrate it.
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
Builder.load_string("""
#:import hex kivy.utils.get_color_from_hex
<Root>:
cols: 2
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
Label:
canvas.before:
Color:
rgb: 39/255., 174/255., 96/255.
Rectangle:
pos: self.pos
size: self.size
text: "rgb: 39/255., 174/255., 96/255."
Label:
canvas.before:
Color:
rgba: 39/255., 174/255., 96/255., 1
Rectangle:
pos: self.pos
size: self.size
text: "rgba: 39/255., 174/255., 96/255., 1"
Label:
canvas.before:
Color:
hsv: 145/360., 77.6/100, 68.2/100
Rectangle:
pos: self.pos
size: self.size
text: "hsv: 145/360., 77.6/100, 68.2/100"
Label:
canvas.before:
Color:
rgba: hex('#27ae60')
Rectangle:
pos: self.pos
size: self.size
text: "rgba: hex('#27ae60')"
""")
class Root(GridLayout):
pass
class ColorusageApp(App):
def build(self):
return Root()
if __name__ == "__main__":
ColorusageApp().run()
You can embed your .kv file in python like this
Builder.load_string("""
<MyWidget>:
...
""")
class MyApp(App):
...
for more info click here
Related
I'm trying to get this kv. file to run, but it throws the error "Invalid indentation (too many levels)". For the life of me, I don't understand why. Im suspicious that its the way I am nesting the layouts within the kv. file, but I'm not sure. Any help/critique would be appreciated!
.py file:
from kivy.app import App
import tarot
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
class selectCard(BoxLayout):
def __init__(self, *args, **kwargs):
super(selectCard,self).__init__(*args,**kwargs)
self.my_text = "Background.png"
def on_click(self):
if self.my_text == "Background.png":
self.my_text = tarot.read().one()
self.ids.card_image.source = "Cards\\" + self.my_text + ".png"
print(self.my_text)
else:
self.my_text = "Background.png"
self.ids.card_image.source = "Background.png"
print(self.my_text)
class layout(FloatLayout):
pass
class TarotApp(App):
def build(self):
return selectCard()
TarotApp().run()
.kv file:
<layout>
canvas.before:
Color:
rgba: 0, 1, 0, 1
Rectangle:
pos: self.pos
size: self.size
<seletCard>
layout:
Button:
normal: root.my_text
on_release: root.on_click()
background_color: 1,1,1,1
size_hint: (1,1)
pos_hint: {'center_x':.5,'center_y':.5}
Image:
source: root.my_text
id: card_image
pos: self.parent.pos
size: self.parent.size
#background_color: self.parent.background_color
stretch: True
Button:
normal: root.my_text
on_release: root.on_click()
background_color: 1,1,1,1
#size_hint: (1,1)
pos_hint: {'center_x':.5,'center_y':.5}
Image:
source: root.my_text
id: card_image
pos: self.parent.pos
size: self.parent.size
background_color: self.parent.background_color
stretch: True
I don't think this is an indentation problem. Am I referencing something incorrectly?
Problem:
I have a dropdown button that produces a label. This label overlaps another button below it. Picture of what is going wrong.
What I Want:
I want the button that is being overlapped by the label from the dropdown to be moved downwards, preferably by same height as the label from the drop down. I then want the button to move back up when the drop down is "pulled up"
MRE
KV File:
#:import utils kivy.utils
#:import Factory kivy.factory.Factory
<CustomDropdown#DropDown>:
id: dropdown
on_select:
app.root.ids.btn.text = '{}'.format(args[1])
self.dismiss()
Label:
id: btn1
text: ' Information '
size_hint_y: None
height: 200
background_color: (1, 0, 0, .9)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
<HomeScreen>:
FloatLayout:
canvas:
Color:
rgb: utils.get_color_from_hex("#FFFFFF")
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 8
cols: 1
spacing: 10
size_hint_y: None
height: 1200
width: self.minimum_width
Button:
text:"stuff1"
color: "black"
size_hint: 1,.18
on_press: Factory.CustomDropdown().open(self)
Button:
text:"stuff2"
color: "black"
size_hint: 1,.18
Main.py
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
Window.size = (286.110236, 570.33070866)
class HomeScreen(Screen):
pass
GUI = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return GUI
MainApp().run()
My problem is that I want to add multiple labels without having to repeat so many lines of code. I have searched for solutions for a long time and all I see is simply writing a for loop in the python file instead of working on the .kv file. However, the location of the labels I want to add is inside a GridLayout inside a scrollLayout inside a BoxLayout and inside another BoxLayout. Is the only solution really to code all of that in my python file? Is there a better approach to this solution?
This is my first time asking a question on StackOverflow, I am very new to all of this, please correct me if I haven't asked the question in a conventional or clear format. Thank you very much.
python code
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.lang import Builder
Builder.load_file('widgetq.kv')
class Win(Widget):
pass
class WidgetApp(App):
def build(self):
return Win()
if __name__ == '__main__':
WidgetApp().run()
.kv file code
<Win>
box1:box1
BoxLayout:
size: root.size
orientation: "vertical"
BoxLayout:
size_hint: 1, 5
ScrollView:
GridLayout:
id:box1
orientation: 'tb-lr'
height: self.minimum_height
size_hint_y: None
row_default_height:180
spacing: 2
cols:1
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint: 1, 1
Label:
background_color:(94/255, 94/255, 94/255, 1)
text:"tab"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Yes, you can avoid writting the same code for every Label. As all your labels have the same style, you may create a custom Label class in your .py file:
from kivy.uix.label import Label # Don't forget to import Label class
class CustomLabel(Label):
pass
Then, in your .kv file customize that class:
<CustomLabel>:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Now, you're able to call CustomLabel in your .kv file, instead of the whole code for every label. The example below produces the same result you already have.
<Win>
box1:box1
BoxLayout:
size: root.size
orientation: "vertical"
BoxLayout:
size_hint: 1, 5
ScrollView:
GridLayout:
id:box1
orientation: 'tb-lr'
height: self.minimum_height
size_hint_y: None
row_default_height:180
spacing: 2
cols:1
CustomLabel:
CustomLabel:
CustomLabel:
CustomLabel:
As you can see you only have to call CustomLabel:.
However, if you pretend to add a lot of Labels, the best way is to use a for loop within your python file.
How to place the white square to the center? I tried a lot of variants, but nothing worked. It work for Label and Buttons, but not for canvas. Or maybe I'm doing everything in wrong way. maybe you suggest the best solution for this task. I need window with background, label in left corner, label in right corner and a square in center
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.config import Config
from kivy.animation import Animation
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.properties import NumericProperty, ReferenceListProperty,\
ObjectProperty
Config.set('graphics', 'resizable', 'true')
Config.set('graphics', 'width', '900')
Config.set('graphics', 'height', '450')
Config.write()
class Helicopter(Widget):
pass
class Background(Widget):
pass
class Root(FloatLayout):
#def on_touch_down(self, touch):
# Animation(center=touch.pos).start(self)
pass
class FriendsApp(App):
def build(self):
return Root()
if __name__ == '__main__':
FriendsApp().run()
.kv file
#: kivy 1.10.0
<Root>
AnchorLayout:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
source: 'background.jpg'
pos: self.pos
size: self.size
size: self.parent.size
anchor_x: 'center'
anchor_y: 'center'
AnchorLayout:
anchor_y:'top'
anchor_x:'left'
padding: 20
Label:
text: 'Lives: x2'
size: self.texture_size
size_hint: None, None
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
padding: 20
Label:
text: 'Score: 0000000'
size: self.texture_size
size_hint: None,None
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
canvas:
Rectangle:
size: 100, 100
pos: self.pos
The AnchorLayout has its own canvas and you cannot aligns itself. There are two solutions to this problem. In the example, colors were added for visualization.
The AnchorLayout aligns its children to a border (top, bottom,
left, right) or center.
Solution 1
Add a Widget as a children.
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
size: 100, 100
pos: self.pos
size_hint: None,None
Solution 2
Replace the last AnchorLaoyout with Widget.
Widget:
canvas:
Rectangle:
pos: self.center_x - 50, self.center_y - 50
size: 100, 100
Example - Solution 1
kv file
#: kivy 1.10.0
<Root>
AnchorLayout:
anchor_y:'top'
anchor_x:'left'
padding: 20
Label:
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
pos: self.pos
size: self.size
text: 'Lives: x2'
size: self.texture_size
size_hint: None, None
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
padding: 20
Label:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
pos: self.pos
size: self.size
text: 'Score: 0000000'
size: self.texture_size
size_hint: None,None
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
size: 100, 100
pos: self.pos
size_hint: None,None
Output
So my problem is that I want to have a button which uses an image from an URL. However the image doesn't show in the correct place but the button does. The image is not clickable but the button is. I want the image to be on the button and to be clickable and to send me to the following screen (ProfileScreen)
Kv file:
<Main_app>:
name: "Main_app"
canvas:
Color:
rgb: 0.216, 0.569, 0.639
Rectangle:
pos: self.pos
size: self.size
Label:
text: ""
color: 0,0,0,1
canvas.before:
Color:
rgba: 0.251, 0.655, 0.737,1
Rectangle:
pos: self.pos
size: self.size
pos_hint: {"left":1, "top":1}
size_hint: 1, 0.0995
Label:
text: ""
color: 0,0,0,1
canvas.before:
Color:
rgba: 0.173, 0.451, 0.51,1
Rectangle:
pos: self.pos
size: self.size
pos_hint: {"left":1, "top":0.9}
size_hint: 1, 0.01
Label:
text: ""
color: 0,0,0,1
canvas.before:
Color:
rgba: 0.251, 0.655, 0.737,1
Rectangle:
pos: self.pos
size: self.size
pos_hint: {"left":1, "top":0.12}
size_hint: 1, 0.25
Label:
text: ""
color: 0,0,0,1
canvas.before:
Color:
rgba: 0.173, 0.451, 0.51,1
Rectangle:
pos: self.pos
size: self.size
pos_hint: {"left":1, "top":0.13}
size_hint: 1, 0.01
Button:
size_hint: 0.1, 0.1
size: 100,100
pos_hint: {"x":0.90, "top":1.0}
on_press: app.root.current = "OpeningScreen"
AsyncImage:
source: 'https://cdn2.iconfinder.com/data/icons/flat-ui-icons-24-px/24/eye-24-256.png'
keep_ratio: True
pos_hint: {"x":0.90, "top":1.0}
<ProfileScreen>:
name: "ProfileScreen"
canvas:
Color:
rgb: 0.216, 0.569, 0.639
Rectangle:
pos: self.pos
size: self.size
Python file:
class ProfileScreen(Screen):
pass
class Main_app(Screen):
pass
AppKv = Builder.load_file("App.kv")
class MyApp(App):
def build(self):
return AppKv
if __name__ == '__main__':
MyApp().run()
Here are some pictures of how it looks like.
http://prntscr.com/iihmcc
You could create a new widget type which implements Image and ButtonBehavior. I had the same problem and found that somewhere. Here is the code I used to create that new widget. It is not for a .kv file though.
First you create a new class with extending the Image and ButtonBehavior class:
class ImageButton(ButtonBehavior, Image):
def on_press(self):
print("on_press")
Then you can create a new instance of the class you just created with a function like this:
#staticmethod
def create_image_button_widget(file_name):
"""
Function used to create an ImageButton widget.
:param file_name: Filename of the image to be used as source
:return: The ImageButton object.
"""
image_to_add = ImageButton()
image_to_add.source = "source_of_image.jpg"
image_to_add.name = file_name
return image_to_add