Kivy: Don't know how to update "on_size: root.center = win.Window.center" in ScreenManager - kivy

I added the Kivy scatter example to a kivy screen. But it didn´t work properly. I have to reconfigure the center on the window. It's done in the kv-file. But I don´t know how to do it on a screen. See the code below.
python
class Picture(Scatter):
source = StringProperty(None)
class ScreenThree(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
root = BoxLayout() # instantiate BoxLayout
self.add_widget(root) # add BoxLayout to screen
curdir = dirname(__file__)
for filename in glob(join(curdir, 'images', '*')):
print(filename)
try:
picture = Picture(source=filename, rotation=randint(-30, 25))
root.add_widget(picture)
except Exception as e:
Logger.exception('Pictures: Unable to load <%s>' % filename)
def on_pause(self):
return True
class TestApp(App):
def build(self):
sm = ScreenManager()
sc1 = ScreenOne(name='screen1')
sc2 = ScreenTwo(name='screen2')
sc3 = ScreenThree(name='screen3')
sm.add_widget(sc1)
sm.add_widget(sc2)
sm.add_widget(sc3)
print (sm.screen_names)
return sm
if __name__ == '__main__':
TestApp().run()
kivy
#:kivy 1.0
#:import kivy kivy
#:import win kivy.core.window
FloatLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
source: 'data/images/background.jpg'
size: root.size
BoxLayout:
padding: 10
spacing: 10
size_hint: 1, None
pos_hint: {'top': 1}
height: 44
Image:
size_hint: None, None
size: 24, 24
source: 'data/logo/kivy-icon-24.png'
Label:
height: 24
text_size: self.width, None
color: (1, 1, 1, .8)
text: 'Kivy %s - Pictures' % kivy.__version__
<Picture>:
on_size: root.center = win.Window.center <-- this is the question i guess
size: image.size
size_hint: None, None
Image:
id: image
source: root.source
# create initial image to be 400 pixels width
size: 400, 400 / self.image_ratio
# add shadow background
canvas.before:
Color:
rgba: 1,1,1,1
BorderImage:
source: 'shadow32.png'
border: (36,36,36,36)
size:(self.width+72, self.height+72)
pos: (-36,-36)
See the example here, Kivy Gallery of Examples » Basic Picture Viewer

In the kv file, on_size: root.center = win.Window.center will work fine, when you make the instantiated object, FloatLayout: as child of class rule, <ScreenThree>: plus some enhancements in Python script.
kv file
Replace #:kivy 1.0 with the Kivy version installed e.g. #:kivy 1.11.1
Add class rule, <ScreenThree>: and make FloatLayout: object as child of <ScreenThree>:
Snippets - kv file
<ScreenThree>:
FloatLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
source: 'data/images/background.jpg'
size: root.size
BoxLayout:
padding: 10
spacing: 10
size_hint: 1, None
pos_hint: {'top': 1}
height: 44
Image:
size_hint: None, None
size: 24, 24
source: 'data/logo/kivy-icon-24.png'
Label:
height: 24
text_size: self.width, None
color: (1, 1, 1, .8)
text: 'Kivy %s - Pictures' % kivy.__version__
py file
Remove root = BoxLayout() and self.add_widget(root)
Replace root.add_widget(picture) with self.add_widget(picture)
Snippets - py file
class ScreenThree(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
curdir = dirname(__file__)
for filename in glob(join(curdir, 'images', '*')):
print(filename)
try:
picture = Picture(source=filename, rotation=randint(-30, 25))
self.add_widget(picture)
except Exception as e:
Logger.exception('Pictures: Unable to load <%s>' % filename)
Output

Related

Kivy AnchorPoint is not in the right place

I am trying to just put a piece of text centred in the top on the window but it ends up truncated in the bottom left.
I have the following python code:
# anchortest.py
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.widget import Widget
class Root(Widget):
pass
class TextTitle(AnchorLayout):
pass
class AnchorTestApp(App):
def build(self):
return Root()
AnchorTestApp().run()
and it's associated kv file.
# anchortest.kv
<Root>
TextTitle:
<TextTitle>
anchor_x: 'center'
anchor_y: 'top'
Label:
id: score
text: 'Hello World'
font_name: 'Courier New'
font_size: 40
pad_x: 10
pad_y: 10
When I run the app I get this:
Don't use AnchorLayout for this case, just use BoxLayout with
pos_hint: {'top': 1}
size_hint_y: None
from kivy.app import App
from kivy.lang.builder import Builder
KV = """
Screen:
BoxLayout:
orientation: 'vertical'
BoxLayout:
pos_hint: {'top': 1}
size_hint_y: None
canvas.before:
Color:
rgba: [0.5, 0, 1, 1]
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Hello World'
font_size: sp(60)
BoxLayout:
Label:
text: 'Screen text'
"""
class TestApp(App):
def build(self):
return Builder.load_string(KV)
TestApp().run()
You also can use Label parametrs valign and halign:
KV = """
Screen:
Label:
text: 'Hello World'
font_size: sp(60)
text_size: self.size
halign: 'center'
valign: 'top'
"""
In order to control sizing, you must specify text_size to constrain
the text and/or bind size to texture_size to grow with the text.
If you really want to use AnchorLayout for some reason, it's done this way. Following the kivy documentation, in order for the AnchorLayout rules to apply, the Label must be set with
size_hint_y: None
height: self.height
The size_hint is a tuple of values used by layouts to manage the sizes
of their children. It indicates the size relative to the layout’s size
instead of an absolute size (in pixels/points/cm/etc)
KV = """
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Label:
text: 'Hello World'
font_size: sp(60)
size_hint_y: None
height: self.height
"""

I want to call a Kivy popup window in specific condition in python file

I have a function that will display a main popup, and when the user close the popup by tapping any where another popup will appear depending on the passed value as a parameter for the function, the problem is the style of popup content, when I use .kv file is looks perfect but, when I try to create the same style using .py file there is so many problems appear to me, so there is any way to call the popup window from .kv file and use it in .py file ?
My function in .py file:
def show_popup(result):
def show_second_popup(self, *args):
if result == True:
# Show popup 1
elif result == False:
# Show popup 2
# Show the main popup
str = Label(markup= True, text_size=(190, 160), text= "This is the main popup" ,
halign="center", valign="center", color= (0,0,0,1),font_size= 24)
popupWindow = Popup(
auto_dismiss= True,
content= str,
size_hint= (0.8,0.4),
pos_hint= {'x': 0.15,'y': 0.3},
title= "", separator_height= 0
)
popupWindow.open()
popupWindow.bind(on_dismiss= show_second_popup)
The popup style in .kv file:
<PopupTrue#Popup>
auto_dismiss: False
title: ""
separator_height: 0
size_hint: 0.8, 0.6
background_color: (0,0,0,0)
background_normal: ''
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 0, 10, 10, 10
border: 50
border_color: (1,1,1,1)
canvas.before:
Color:
rgba:(255/255,255/255,255/255,1)
RoundedRectangle:
pos: self.x - 20, self.y - 10
size: self.width + 40, self.height - 60
radius: [40]
Image:
source: 'icon.png'
Label:
text: "This popup appear if the condition was TRUE"
color: 0,0,0,1
font_size: 25
CloseButton:
text: "Close"
color: 0,0,0,1
size_hint: (None , None)
width: 105
height: 40
pos_hint: {'center_x':0.5}
on_release: root.dismiss()
<PopupFalse#Popup>
auto_dismiss: False
title: ""
separator_height: 0
size_hint: 0.8, 0.6
background_color: (0,0,0,0)
background_normal: ''
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 0, 10, 10, 10
border: 50
border_color: (1,1,1,1)
canvas.before:
Color:
rgba:(255/255,255/255,255/255,1)
RoundedRectangle:
pos: self.x - 20, self.y - 10
size: self.width + 40, self.height - 60
radius: [40]
Image:
source: 'icon.png'
Label:
text: "This popup appear if the condition was False"
color: 0,0,0,1
font_size: 25
CloseButton:
text: "Close"
color: 0,0,0,1
size_hint: (None , None)
width: 105
height: 40
pos_hint: {'center_x':0.5}
on_release: root.dismiss()
I want the main popup appear from python file, and call another popup from .kv file, because my .kv file popup has canvas for the button and popup layout, and I faced a problem with writing the canvas part.
Ok I find the answer, I tried to create a two classes with a Popup parameter, and I named the classes as the name in the .kv file, finally I just call the class with open() function. :)
class PopupTrue(Popup):
pass
class PopupFalse(Popup):
pass
def show_popup(result):
def show_second_popup(self, *args):
if result == True:
# Show popup 1
PopupTrue().open()
elif result == False:
# Show popup 2
PopupFalse().open()
# Show the main popup
str = Label(markup= True, text_size=(190, 160), text= "This is the main popup" ,
halign="center", valign="center", color= (0,0,0,1),font_size= 24)
popupWindow = Popup(
auto_dismiss= True,
content= str,
size_hint= (0.8,0.4),
pos_hint= {'x': 0.15,'y': 0.3},
title= "", separator_height= 0
)
popupWindow.open()
popupWindow.bind(on_dismiss= show_second_popup)

Positioning a text field inside a toolbar in Kivy

I'm trying to put a textfield inside a toolbar with KivyMD, but the textfield is always directly against the right side of the window. I tried to adjust it with pos_hint, but none of the values I put for the x-coordinates moved it.
Screen:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'assets/bg.png'
BoxLayout:
orientation: 'vertical'
MDToolbar:
id: toolbar
title: 'Placeholder'
elevation: 10
pos_hint: {"top": 1}
left_action_items: [['menu', lambda x: app.menu.open()]]
MDTextFieldRound:
id: textinput
icon_left: 'magnify'
pos_hint: {'x': 0.1 ,'center_y': 0.5, 'right': 0.3}
size_hint: {.6, .4}
text_color: 'white'
hint_text: 'Search'**strong text**
MDLabel:
text: 'Placeholder'
color: 'white'
halign: 'center'
Screenshot of toolbar
Any help is appreciated, thanks.
You can insert your widgets wherever you want, for this you can specify a position in the widget tree - add_widget(widget, index). I wrote a special get_widgets function for your solution, which goes through all the widgets in the class. In the example below, you can place the text field on the left, right, and center. Also examine the MDToolbar source code
from kivy.lang.builder import Builder
from kivy.metrics import dp
from kivy.clock import Clock
from kivy.weakproxy import WeakProxy
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.textfield import MDTextField
KV = """
MDScreen:
MDBoxLayout:
orientation: 'vertical'
MDToolbar:
id: toolbar
title: 'Placeholder'
pos_hint: {"top": 1}
MDLabel:
text: 'Placeholder'
color: 'white'
halign: 'center'
"""
class TestApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.search_content = None
def build(self):
return Builder.load_string(KV)
def on_start(self):
Clock.schedule_once(lambda dt: self.add_search('left'))
#staticmethod
def get_widgets(root: WeakProxy, class_: str):
"""
:param root: root widget
:param class_: which subclass are we looking for
:return:
"""
widgets = []
for widget in root.walk():
if widget.__class__.__name__ == class_:
widgets.append(widget)
print(widget)
return widgets
def add_search(self, side: str):
"""
:param side: left/right/center
:return:
"""
box = self.get_widgets(self.root.ids.toolbar, 'MDBoxLayout')[0] # get root `MDBoxLayout`
if side == 'left':
index = 2
elif side == 'right':
index = 1
else:
index = 0
self.root.ids.toolbar.ids.label_title.size_hint = None, None
self.root.ids.toolbar.ids.label_title.opacity = 0
# NOTE: If you remove this `MDLabel`, you cant change `self.theme_cls.material_style`
# box.remove_widget(self.root.ids.toolbar.ids.label_title)
boxlayout = MDBoxLayout(padding=[dp(18), dp(0), dp(18), dp(18)])
self.search_content = MDTextField(icon_left='magnify',
mode='round',
color_mode="custom",
line_color_normal=(1, 0, 1, 1),
line_color_focus=(0, 0, 1, 1),
text_color_focus=self.theme_cls.text_color,
text_color_normal=self.theme_cls.text_color[0:3] + [0.7],
hint_text='Empty field',
)
boxlayout.add_widget(self.search_content)
box.add_widget(boxlayout, index)
TestApp().run()

Invalid indentation, must be a multiple of 8 spaces, rounded button kivy .kv file

so yeah I was learning kivy - "rounded buttons" and when I ran the tutorial's program ---------------
ERROR:
https://i.stack.imgur.com/rGhSa.png
python:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.core.window import Window
Builder.load_file("my.kv")
class MyLayout(Widget,App):
def __init__(self,*args,**kwargs):
super(MyLayout, self).__init__(**kwargs)
class AwesomeApp(App):
def build(self):
Window.clearcolor = (1,1,1,1)
return MyLayout()
if __name__ == '__main__':
AwesomeApp().run()
.kv
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Button:
text: "Hello World!"
RoundedButton:
text: "Goodbye World!"
pos_hint: {'center_x': 0.5}
size_hint: (1, .3)
#background_color: (0/255,255/255,203/255,1)
#background_normal: ''
<RoundedButton#Button>
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba: (0/255,255/255,203/255,1)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [58]
thanks,can anyone help, don't like these errors,
indentation error it seems like
You are not doing proper indentation you must use only one type of indentation in a file but you are using 8 spaces and 4 spaces both as indentation that is why error is coming.
Here,I have used 4 spaces as indentation in whole code that is why its working fine.
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Button:
text: "Hello World!"
RoundedButton:
text: "Goodbye World!"
pos_hint: {'center_x': 0.5}
size_hint: (1, .3)
#background_color: (0/255,255/255,203/255,1)
#background_normal: ''
<RoundedButton#Button>
background_color: (0,0,0,0)
background_normal: ''
canvas.before:
Color:
rgba: (0/255,255/255,203/255,1)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [58]

Kivy. Position of GridLayout inside ScrollView

I give up. I think I have tried everything I possibly could. I need some explatanion how to position nested layouts classes. In below code I need these labels to be positioned in the center of the screen. Anything I've tried leaves the Labels on the left side.
from kivy.app import App
from kivy.lang import Builder
kv = """
<StorageLabel#Label>
background_normal: ''
size_hint: None, None
size: 65, 50
canvas.before:
Color:
rgba: (1, 0, 0.5, 1)
Rectangle:
pos: self.pos
size: self.size
halign: "left"
valign: "middle"
<Storage#BoxLayout>
ScrollView:
size_hint_x: 1
bar_width: 10
scroll_type: ['bars', 'content']
bar_color: [0, 0, 0, 1]
bar_inactive_color: [0, 0, 0, 1]
pos_hint: {'center_x': 0.5}
GridLayout:
cols: 3
size_hint_y: None
size: self.minimum_size
height: self.minimum_height
StorageLabel:
text: '1m'
StorageLabel:
text: '2m'
StorageLabel:
text: '3m'
Storage:
"""
sm = Builder.load_string(kv)
class Main(App):
def build(self):
return sm
if __name__ == '__main__':
Main().run()
The easiest way to center the Labels is to let the GridLayout size and position them. This results in a larger width for each Label, but they are centered:
from kivy.app import App
from kivy.lang import Builder
kv = """
<StorageLabel#Label>
background_normal: ''
# leave size_hint_x at default of 1
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (1, 0, 0.5, 1)
Rectangle:
pos: self.pos
size: self.size
<Storage#BoxLayout>
ScrollView:
size_hint_x: 1
bar_width: 10
scroll_type: ['bars', 'content']
bar_color: [0, 0, 0, 1]
bar_inactive_color: [0, 0, 0, 1]
pos_hint: {'center_x': 0.5}
GridLayout:
cols: 3
# add some padding and spacing
padding: 5
spacing: 5
size_hint_y: None
height: self.minimum_height
StorageLabel:
text: '1m'
StorageLabel:
text: '2m'
StorageLabel:
text: '3m'
Storage:
"""
sm = Builder.load_string(kv)
class Main(App):
def build(self):
return sm
if __name__ == '__main__':
Main().run()
If you want the labels to be your original size, then you can place each in its own Layout (perhaps a FloatLayout), and let the GridLayout size and position those Layouts:
from kivy.app import App
from kivy.lang import Builder
kv = """
<StorageLabel#Label>
background_normal: ''
size_hint: None, None
size: 65, 50
# position the label in the center of its FloatLayout
pos_hint: {'center_x':0.5}
canvas.before:
Color:
rgba: (1, 0, 0.5, 1)
Rectangle:
pos: self.pos
size: self.size
<Storage#BoxLayout>
ScrollView:
size_hint_x: 1
bar_width: 10
scroll_type: ['bars', 'content']
bar_color: [0, 0, 0, 1]
bar_inactive_color: [0, 0, 0, 1]
pos_hint: {'center_x': 0.5}
GridLayout:
cols: 3
size_hint_y: None
height: self.minimum_height
# set the default row height to the height of the Labels
row_default_height: 50
FloatLayout:
StorageLabel:
text: '1m'
FloatLayout:
StorageLabel:
text: '2m'
FloatLayout:
StorageLabel:
text: '3m'
Storage:
"""
sm = Builder.load_string(kv)
class Main(App):
def build(self):
return sm
if __name__ == '__main__':
Main().run()

Resources