Popup fails depending on what I BIND - kivy

Here is the relevant portion of my Animal Picker in KIVY file shown below:
AniPic#ANIMALPICKER
id: aroot
labelText: ''
imageSource: ''
animalCode: 'AB'
animalName: 'GOGGA'
BoxLayout:
orientation: 'horizontal'
width: root.width
pos: 0,0
canvas.before:
RoundedRectangle:
pos: 5, 5
# the next two lines determine the position of the rectangle for the image
size: root.width-10, root.height-10
source: root.imageSource
radius:[10]
PinButton:
id: _pin
on_release:
root.pin_action(root.labelText)
Label:
id: _label
text: root.labelText
width: root.width
color: (1, 1, 1, 1)
MapButton:
id: _map
on_release:
root.map_show(root.labelText)
#==========================================================================
AnimalWindow:
:
id: animalid
name: 'animal'
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'vertical'
Label:
id: choice
text: "Sightings"
color: 0, 0, 0, 1
size_hint_y: 0.05
canvas.before:
Color:
rgba: 0.5, 1, 0.5, 1
Rectangle:
pos: self.pos
size: self.size
ScrollView:
do_scroll_x: False
do_scroll_y: True
GridLayout:
size: (root.width, root.height)
cols: 1
rows: 9
padding: 10
spacing: 10
size_hint_x: None
size_hint_y: 9
height: self.minimum_height
row_default_height: 120
row_force_default: True
AniPic:
labelText: 'LION'
imageSource: 'images/lion_pic.jpg'
animalCode: 'LI'
AniPic:
labelText: 'CHEETAH'
imageSource: 'images/cheetah_pic.png'
animalCode: 'CH'
Now when I click on a 'PinButton' of a particular animal (CHEETA) I get the app executing
def pin_it(_animal):
print('aaaa', _animal )
and shows.
'aaaa CHEETAH'
BUT the POPUP code below, where I want 'confirmation' for pin action, does not show the popup but crashes:
class ANIMALPICKER(RelativeLayout):
def pin_action(self, _animal):
# Prepare to confirm that you want to Pin the sighting
title_text = _animal + ' ' + 'SIGHTING'
content_text = 'Confirm Sighting?'
content_box = BoxLayout(orientation='vertical')
btn_box = BoxLayout(orientation='horizontal')
btn_box.height = 24
content_label = Label()
content_label.text = content_text
yes_btn = Button(text='Yes')
yes_btn.background_color = 0, 1, 0, 1
no_btn = Button(text='No')
no_btn.background_color = 1, 0, 0, 1
btn_box.add_widget(yes_btn)
btn_box.add_widget(no_btn)
content_box.add_widget(content_label)
content_box.add_widget(btn_box)
# Now confirm that you want to Pin the sighting
popup = Popup(title=title_text,
separator_height=4,
title_size='20sp',
content=content_box,
size_hint=(None, None),
size=(200, 240),
auto_dismiss=False)
# dismiss popup and proceed to pin the sighting, on release of yes button
yes_btn.bind(on_press=pin_it(_animal))
# dismiss popup on release of the NO button
yes_btn.bind(on_release=popup.dismiss)
popup.open()
with the following message:
File "/home/sib/PycharmProjects/SpotMap/animalWindow.py", line 66, in pin_action
yes_btn.bind(on_press=pin_it(_animal))
File "kivy/_event.pyx", line 444, in kivy._event.EventDispatcher.bind
AssertionError: None is not callable
However when I bind a simple 'yes_btn.bind(on_press=dismiss)' instead of 'yes_btn.bind(on_press=pin_it(_animal))' the popup does display and the the popup dismisses when the button to which it is attached is pressed.
Please at 82 years of age and a limited knowledge of Python, Kivy and OO I desperately need help in completing this app.
A work around will also satisfy me
Many Thanks

I think the problem is that pin_it(_animal) completes the function instead of referencing the function object.
from functools import partial
myfun = partial(pin_it, animal=_animal)
# this should be a function, not function()
yes_btn.bind(on_press=myfun)

Related

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)

Move search items more to the top

I have the following code snippet displaying a popup Window.
class SearchBar(TextInput):
articles = ListProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(text=self.on_text)
self.bind(articles=self.on_articles)
def on_text(self, *args):
WikiSearcher().get_search_results(self.text, self)
def on_articles(self, *args):
self.parent.parent.children[0].update_recommendations(self.articles)
class SearchItem(ButtonBehavior, Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.url = ''
def on_release(self):
print (self.url)
class Recommendations(BoxLayout):
def update_recommendations(self, recommendations: list):
for (search_item, recommendation) in zip(reversed(self.children), recommendations):
search_item.text = recommendation
try:
search_item.url = wikipedia.page(recommendation).url
except:
search_item.url = 'https://en.wikipedia.org/wiki/' + recommendation.replace(" ", "_")
Builder.load_string('''
<SearchItem>:
font_size: self.height * 0.4
canvas.before:
Color:
rgba: [0.8, 0.8, 0.8, 1] if self.state == 'normal' else [30/255, 139/255, 195/255, 1]
Rectangle:
#pos: self.pos
#size: self.size[0], self.size[1]
size: root.size[0], root.size[1]
pos: self.pos[0], self.pos[1]
Color:
rgba: 0, 0, 0, 1
Line:
rectangle: self.x, self.y, self.width, self.height
color: 0, 0, 0, 1
<Urlpup>:
size_hint: 1, 1
auto_dismiss: False
title: 'Enter URL or keywords'
BoxLayout:
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
size: self.size
pos: self.pos
orientation: 'vertical'
padding: self.width * 0.1
spacing: self.height * 0.1
BoxLayout:
orientation: 'horizontal'
Spinner:
id: spinner
size_hint: 0.5, 0.4
pos_hint: { 'top' : 1 }
text: 'en'
values: 'en', 'fr', 'de', 'it'
SearchBar:
id: url_input
size_hint: 1, 0.4
pos_hint: { 'center_x' : 0.5, 'top' : 1 }
multiline: False
font_size: self.height*0.8
Button:
text: 'OK'
size_hint: 0.5, 0.4
pos_hint: { 'top' : 1 }
on_press: root.dismiss()
on_release: app.create_new_article(url_input.text)
Recommendations:
id: recommendations
orientation: 'vertical'
SearchItem
SearchItem
SearchItem
SearchItem
''')
class Urlpup(Popup):
pass
Here is a picture of the popup Window
You can see that the SearchItems are not tightly below the SearchBar, where I'm struggling to position it. Can you fix it? On the picture there are 4 SearchItems but I plan to have 10 Searchitems so it should work for 10 SearchItems or be flexible when I decide to change the number of SearchItems
The BoxLayout tries to distribute its available space equally among its children, unless you tell it otherwise. So, your top level BoxLayout in the Urlpup class evenly divides its space between the BoxLayout containing the TextInput and the Recommendations widget. You can reduce the space between those two widgets by limiting the space given to the horizontal BoxLayout. You can do that by specifying a height for that BoxLayout, like this:
BoxLayout:
size_hint_y: None
height: 50
orientation: 'horizontal'
Spinner:
id: spinner
size_hint: 0.5, 1
pos_hint: { 'top' : 1 }
text: 'en'
values: 'en', 'fr', 'de', 'it'
SearchBar:
id: url_input
size_hint: 1, 1
pos_hint: { 'center_x' : 0.5, 'top' : 1 }
multiline: False
font_size: self.height*0.8
Button:
text: 'OK'
size_hint: 0.5, 1
pos_hint: { 'top' : 1 }
on_press: root.dismiss()
on_release: app.create_new_article(url_input.text)
Note that the children of this BoxLayout all have a size_hint_y of 1.0, so they will all be the height that is specified for their container.
The Recommendations widget gets the remaining vertical space (minus the spacing). You can move the Recommendations even closer by reducing the spacing.

How can I make border to the text in the label?

I'm still learning kivy language .
please can you tell me how to add a border to a text in a label in the kv file
and thanks
In the kivy language documentation, you can redefine a widget's style by adding a - to the beginning of the kv rule. So, in the kv you can define a new widget like this:
<-LabelWithBorder#Label>:
border_width: 0
border_color: [1,1,1,1]
canvas.before: # draw the border
Color:
rgba: root.border_color if root.border_width > 0 else [0,0,0,1]
Rectangle:
size: self.size
pos: self.pos
Color:
rgba: 0, 0, 0, 1
Rectangle:
size: self.width - 2*root.border_width, self.height - 2*root.border_width
pos: int(self.center_x - (self.width - 2*root.border_width)/2.), int(self.center_y - (self.height - 2*root.border_width)/2.)
canvas: # modified from Label
Color:
rgba: 1, 1, 1, 1
Rectangle:
texture: self.texture
size: self.texture_size[0] - 2*root.border_width, self.texture_size[1] - 2*root.border_width
pos: int(self.center_x - self.width/2.) + root.border_width, int(self.center_y - self.height/2.) + root.border_width
The canvas.before is the section that draws the border, and the canvas section is the normal Label style with slight modifications to account for the border.
This can be used, for example, like this:
FloatLayout:
LabelWithBorder:
text: 'Hello, World'
font_size: 50
border_width: 10
border_color: [1,0,0,1]
size_hint: None, None
size: self.texture_size
pos_hint: {'center_x':0.5, 'center_y':0.5}
I believe you are looking for 'outline'
This is the docs link for it Label Outline - Kivy Docs
Here's some example code (color defaults to black .. 0, 0, 0, 1):
Label:
id: label_StackOverflowSample
pos_hint: {"x": 0.25, "y": 0.18}
size_hint: 0.6, 0.365
font_size: 18
text_size: self.size
halign: 'left'
italic: True
outline_width: 10
outline_colour: (0, 0, 0, 1)
text:
'''
long long long
long long long
long long long
long long long
long long long
textt
'''
And this is a picture showing its example:
sorry, not enough reputation to post pictures yet
Hope this helps

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

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

Kivy TextInput Text Overflow. Cursor Outside TextInput Viewport

The last letter is overflowing
I'm using Kivy 1.10.1. I've added a text input (multiline = False). The sentence entered above is "This is a long sentence being typed into Kivy". All the letters have been entered. But the last letter - the "y" is outside the text input.
I've tried changing the padding size, the border size and changing the size of the textinput itself. I don't know if I'm doing something wrong or it is a bug with the library.
Edit:( I should have added the widget code here )
text_input: input_text_field
canvas:
Color:
rgba: self.background_color_intensity_red, self.background_color_intensity_green, self.background_color_intensity_blue, 1
Rectangle:
size: 396, 768
pos: self.pos
source: "sprites/phone.png"
BoxLayout:
size: 354, 598
pos: 21, 96
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.1
pos: root.pos
orientation: 'horizontal'
Image:
size_hint: 0.15, 1
source: "sprites/profile_pic.png"
TextInput:
id: input_text_field
size_hint: 0.85, 0.5
pos_hint: {'top': 0.75}
background_color: 1,1,1,1
border: (20, 20, 20, 20)
multiline: False
halign: 'center'
focus: True
on_text_validate: self.parent.parent.parent.on_text_input()
BoxLayout:
size_hint: 1, 0.9
pos: root.pos
orientation: 'vertical'
Thank you.

Resources