Just started getting into Kivy, facing some alignment issue.
Please have a look on the image below, I am trying to adjust button weather icon marked in red circle at the location where it is marked with blue circle.
Here is the *.kv file code :
BoxLayout:
orientation:'horizontal'
BoxLayout:
orientation:'horizontal'
StackLayout:
orientation:'tb-rl'
canvas:
Color:
rgb: [.3, .320, .380]
Rectangle:
pos: self.pos
size: self.size
Button:
id:current_temperature
text: root.display_current_temperature()
font_size:40
size_hint: [None, None]
size:[200,50]
Button:
id:current_location
text: root.display_location()
font_size:15
size_hint: [None, None]
size:[200,50]
Button:
id:test
text: 'weather icon'
size_hint: [None, None]
size:[100,100]
One way is making use of the kivy.uix.AnchorLayout
Docs: AnchorLayout
BoxLayout:
orientation:'horizontal'
BoxLayout:
size_hint: [.8, 1]
orientation:'horizontal'
StackLayout:
orientation:'tb-rl'
canvas:
Color:
rgb: [.3, .320, .380]
Rectangle:
pos: self.pos
size: self.size
Button:
id:current_temperature
text: root.display_current_temperature()
font_size:40
size_hint: [None, None]
size:[200,50]
Button:
id:current_location
text: root.display_location()
font_size:15
size_hint: [None, None]
size:[200,50]
BoxLayout:
size_hint:[.2, 1]
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Button:
id:test
text: 'weather icon'
size_hint: [1, None]
Please note that i have changed the size of the last Button Widget from a absolute one to a relative one. This will prevent unexpected behavior on rendering the app on different screen sizes.
Also changed the sizes of the main 2 BoxLayout Widgets to a relative one also, for the same reason as above.
Another way is adding a position hint to the Button Widget
Docs: pos_hint
Button:
pos_hint: {'y': 1-1/(self.parent.height/self.height)}
id:test
text: 'weather icon'
size_hint: [None, None]
size:[100,100]
Related
When I double click on the video, it goes full screen, but if I double click on it again, it doesn't go back to normal. However, the rest of the window elements are partially visible. The part of my .kv code responsible for the VideoPlayer is given below:
<VideosWindow>:
name: 'vids'
FloatLayout:
FileChooserListView:
id:chooser
path: root.get_files_list()
canvas.before:
Color:
rgb: .4, .5, .5
Rectangle:
pos: self.pos
size: self.size
on_selection: root.select(chooser.selection)
size_hint: (.9, .15)
pos_hint: {'x':.05, 'y':.8}
VideoPlayer:
id:vid
options: {'eos':'loop'}
size_hint: (.9, .7)
pos_hint: {'x':.05, 'y':.05}
Button:
size_hint_y: 0.3
height: 48
text: "open"
disabled: not chooser.selection
on_release: root.select(chooser.selection)
size_hint: (.45, .05)
pos_hint: {'x':.05, 'y':.00}
Button:
text: 'Go Back'
color: (1,1,1,1)
background_normal:''
background_color: (0.3,0.6,0.7,1)
on_release:
vid.state = 'pause'
app.root.current = 'saved_files'
size_hint: (.45, .05)
pos_hint: {'x':.50, 'y':.00}
VideosWindow class code:
class VideosWindow(Screen):
def get_files_list(self):
files = os.sep.join([my_folder,'mp4'])
return files
def select(self, filename):
self.ids.vid.source = filename[0]
self.ids.vid.state = 'play'
The screenshots of my program before and after I go fullscreen mode:
before
after
Solved this issue by adding VideoPlayer widget to the GridLayout. Now .kv code looks like this:
<VideosWindow>:
name: 'vids'
FloatLayout:
FileChooserListView:
id:chooser
path: root.get_files_list()
canvas.before:
Color:
rgb: .4, .5, .5
Rectangle:
pos: self.pos
size: self.size
on_selection: root.select(chooser.selection)
size_hint: (.9, .15)
pos_hint: {'x':.05, 'y':.8}
GridLayout:
cols:1
size_hint: (.9, .7)
pos_hint: {'x':.05, 'y':.05}
VideoPlayer:
id:vid
options: {'eos':'loop'}
Button:
size_hint_y: 0.3
height: 48
text: "open"
disabled: not chooser.selection
on_release: root.select(chooser.selection)
size_hint: (.45, .05)
pos_hint: {'x':.05, 'y':.00}
Button:
text: 'Go Back'
color: (1,1,1,1)
background_normal:''
background_color: (0.3,0.6,0.7,1)
on_release:
vid.state = 'pause'
app.root.current = 'saved_files'
size_hint: (.45, .05)
pos_hint: {'x':.50, 'y':.00}
Don't know if it is good decision but it works.
I'm creating a kivy app right now. I'm quite new to Kivy and kv lang and there doesn't seam to be much rumour about it although i find it great to seperate code logic and layout, especially after some pygame development.
So to my actuall problem: I have a wiki-style screen for screenmanager, consisting out of a BoxLayout:
Title as Label
Scrollable Label for the Text (later , there shall be displayed a nested kv file)
Buttons for Navigation (scroll up and go back to main screen)
Now I'm recreating the Navigation buttons to be floating type as known from many webpages and apps. Problem is, I suddendly cant reference my ScrollView anymore. Any help or suggestions?
<Wiki>:
name: "wiki"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "picture.jpg"
BoxLayout:
id: box
orientation: "vertical"
padding: 10
spacing: 10
Label:
font_size: 20
size_hint_y: .1
text: root.country_text
ScrollView:
id: scrlvw
BackgroundLabel:
background_color: 220,220,220, 0.5
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
halign: "left"
valign: "top"
text: root.wiki_text
FloatLayout:
size_hint_y: .1
Button:
size_hint_x: .2
pos_hint: {"center_x": .25, "center_y": .5}
text: "Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
FloatButton:
size_hint_x: .2
pos_hint: {"center_x": .75, "center_y": .5}
text: "Up"
on_release:
widget = BoxLayout()
widget.ids.scrlvw.scroll_y = 0
Before, when it worked, it was:
BoxLayout:
FloatLayout:
size_hint_y: .1
Button:
size_hint_x: .2
pos_hint: {"center_x": .25, "center_y": .5}
text: "Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
Button:
size_hint_x: .2
pos_hint: {"center_x": .75, "center_y": .5}
text: "Up"
on_release:
scrlvw.scroll_y = 0
Well as its just a design question, I guess i temporary have to dismiss the floating design. But I would be so pleased if you could help me understand this language better.
As long as the 'kv' code described as "when it worked" is still in the same <Wiki> rule, it should still work. The newer kv code will never work as you are trying to create a new BoxLayout and reference an id in it. That has two problems:
The newly created BoxLayout is not the BoxLayout instance that appears in your GUI, so any changes to it will have no effect on what appears in the display.
Unless you have a <BoxLayout> rule in your kv, the newly created BoxLayout will not have a scrlvw id.
The ids defined within a kv rule are available for use only within that rule. See the documntation.
I am working with a FileChooser module in Kivy which is black by default.
But for the rest of my app I used this to define Labels and Buttons style :
<Label>
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
and
<Button>
font_size:20
color: 1,1,1,1
background_color: (0.55,0.55,0.47,1.0)
size_hint:0.9,0.2
This is efficient and time saver BUT it breaks the FileChooserIconView I use :
The filechooser contains Labels and buttons. They are all in the same class, so do you know how to NOT affect this button and label stuyle to one class ?
I already tried to change the filechooser style instead but it's not working
The filechooser class
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserIconView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
I try to make a simple ToDoList program.There are add, remove and do it buttons. But I have some bugs about labels color. When I click "DO IT" button label color change in scrollview but when I click remove button when some of them done, colored labels change. I did using canvas. How can I fix this problem?
class Home(Screen):
def __init__(self,**kwargs):
super(Home,self).__init__(**kwargs)
def addWidget(self):
task_input = self.ids.task_input.text
newListItem = EachTask(text=task_input ,
id=str((len(self.ids.add_field.children))) )
print(newListItem.id)
self.ids.add_field.add_widget(newListItem)
class EachTask(BoxLayout):
def __init__(self, text= "", **kwargs):
super(EachTask,self).__init__(**kwargs)
self.ids.label.text = text
def Do_Task(self,instance):
child = instance.parent.parent
with self.canvas.before:
Color(.5,1,.2,1, mode='rgba')
Rectangle(pos=child.ids.label.pos, size=child.ids.label.size)
kv_file
<FlatButton#ButtonBehavior+Label>:
font_size: 15
<Home>:
BoxLayout:
id: home
orientation: "vertical"
spacing: 5
#space_x: self.size[0]/2
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
##########HEADER#######
BoxLayout:
id: header
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (.85,.7,.2,1)
Rectangle:
size: self.size
pos: self.pos
Label:
text: "TO DO LIST"
font_size: "20sp"
bold: True
size_hint_x: .9
FlatButton:
text: "Back"
size_hint_x: .1
####################################
ScrollView:
canvas.before:
Color:
rgba: (1,1,.2,.2)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
id: add_field
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: 2 #Spaces between childs
#####################################################
BoxLayout:
id: input_field
size_hint_y: None
height: 80
TextInput:
id: task_input
focus: True
size_hint_x: .9
multiline: False
Button:
font_size: "40sp"
size_hint_x: .1
text: "+"
on_release: root.addWidget()
id: button1
color: 1,0.5,0.5,1
#######################################################
<EachTask>:
size_hint_y: None
height: 50
id: each_task
BoxLayout:
Label:
size_hint_x: .8
id: label
canvas.before:
Color:
rgba: (1,.2,.2,.2)
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint_x: .1
text: "X"
on_release: app.root.ids.add_field.remove_widget(root)
Button:
size_hint_x: .1
text: "DO IT"
on_release: root.Do_Task(self)
The following enhancements are required to the kv and py files to solve the problem.
Method 1 - Kivy automatically created & added an ObjectProperty, rgba
Kivy automatically created & added an ObjectProperty
If the widget doesn’t have a property with the given name, an
ObjectProperty will be automatically created and added to the widget.
kv file
Add a class attribute, rgba and initialize it to default colour, (1, .2, .2, .2) to class rule, <EachTask>:
Replace label's colour to root.rgba
Snippets - kv file
<EachTask>:
rgba: (1,.2,.2,.2) # Kivy auto created & added ObjectProperty, "rgba"
...
BoxLayout:
Label:
size_hint_x: .8
id: label
canvas.before:
Color:
rgba: root.rgba
...
py file
Remove all the codes in method Do_Task()
Add self.rgba = [.5, 1, .2, 1] whereby self refers to the current widget i.e. EachTask object.
Snippets - py file
def Do_Task(self, instance):
self.rgba = [.5, 1, .2, 1]
Method 2 - Explicitly declaring rgba
kv file
Replace rgba: (1,.2,.2,.2) with root.rgba
Snippets - kv file
<EachTask>:
...
BoxLayout:
Label:
size_hint_x: .8
id: label
canvas.before:
Color:
rgba: root.rgba
...
py file
Add import statement, from kivy.properties import ListProperty
Declare class attribute, rgba of ListProperty type and initilaize it to default colour, [1, .2, .2, .2] in class EachTask()
Remove all the codes in method Do_Task()
Add self.rgba = [.5, 1, .2, 1] whereby self refers to the current widget i.e. EachTask object.
Snippets - py file
from kivy.properties import ListProperty
...
class EachTask(BoxLayout):
rgba = ListProperty([1, .2, .2, .2])
...
def Do_Task(self, instance):
self.rgba = [.5, 1, .2, 1]
I am new to Python UI programming, and I am trying out Kivy. I want to center some buttons on my screen, but the buttons do not move from the bottom right of the window. I was wondering if anyone could point out what I am doing wrong or am missing?
vgx.kv:
#:kivy 1.9.1
<VgxMainScreen>:
BoxLayout:
size_hint: 0.2,0.2
size: 200, 100
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
<VgxUI>:
AnchorLayout:
anchor_x: 'center'
VgxMainScreen:
size_hint: 0.2,0.2
<VgxApp>:
FloatLayout:
VgxUI:
center: 0.5, 0.5
VgxApp.py:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
kivy.require('1.9.1')
class VgxMainScreen(Widget):
pass
class VgxUI(Widget):
pass
class VgxApp(App):
def build(self):
return VgxUI()
if __name__ == '__main__':
VgxApp().run()
Edit: Best way to debug what's going on with you widgets is to change their background colors :).
canvas.before:
Color:
rgba: X, X, X, 1
Rectangle:
pos: self.pos
size: self.size
The problem was that your BoxLayout wasn't positioned relatively to its parent even though it was inside it.
What I did here is that I positioned the BoxLayout to its parent's size and position using:
size: self.parent.size
pos: self.parent.pos
I also moved the size property from VgxMainScreen to VgxUI because I assume this is more common use-case (you can have multiple VgxMainScreens each with different size). Full code with background colors:
#:kivy 1.9.1
<VgxMainScreen>:
size_hint: None, None
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
pos: self.pos
size: self.size
size: self.parent.size # important!
pos: self.parent.pos # important!
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
<VgxUI>:
AnchorLayout:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
pos: self.pos
size: self.size
size: self.parent.size
anchor_x: 'center'
anchor_y: 'center'
VgxMainScreen:
size: 200, 100
<VgxApp>:
FloatLayout:
VgxUI:
center: 0.5, 0.5
There's yet another solution to this.
You can use RelativeLayout and all widgets inside it will position relatively to this layout.
<VgxMainScreen>:
size_hint: None, None
RelativeLayout:
pos: self.parent.pos
size: self.parent.size
BoxLayout:
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
I've personally scratched my head many times when using Kivy and wondered why my widgets aren't positioned as I think they should :).
VgxMainScreen is a Widget, so it doesn't apply any positioning or sizing to its children (only Layouts do that), so the BoxLayout has the default position of (0, 0) and size of (100, 100).
Make VgxMainScreen inherit from something else, like a FloatLayout.