AttributeError: object has no attribute 'ids' - kivy

I am new in kivy and I am trying to change image of float layout with a button
I tried everything I can but it didn't worked out.
I am getting the below error
AttributeError: 'Chat_Bot' object has no attribute 'ids'
May be I need to extend the class but I am not sure
Below is my main.py file
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager
from kivy.clock import Clock
from kivy.core.text import LabelBase
from kivymd.uix.label import MDLabel
from kivymd.uix.label import MDLabel
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty,NumericProperty
from kivymd.uix.textfield import *
import lk_k
Window.keyboard_anim_args = {"d":.2,"t":"in_out_quart"}
Window.softinput_mode = ""
class Command(MDLabel):
text = StringProperty()
size_hint_x = NumericProperty()
halign = StringProperty()
font_size=26
class Response(MDLabel):
text = StringProperty()
size_hint_x = NumericProperty()
halign = StringProperty()
font_size=26
class main(MDApp):
def change_screen(self, name):
screen_manager.current = name
def build(self):
global screen_manager
screen_manager = ScreenManager()
screen_manager.add_widget(Builder.load_file("Chats.kv"))
return screen_manager
def response(self, *args):
q=lk_k.get_response(message)
if len(q)<6:
s=.22
h="center"
elif len(q)<11:
s=.32
h="center"
elif len(q) < 16:
s = .45
h = "center"
elif len(q) < 21:
s = .58
h = "center"
elif len(q) < 26:
s = .71
h = "center"
else:
s = .77
h = "center"
screen_manager.get_screen('chats').chat_list.add_widget(Response(text=q, size_hint_x=s,halign=h))
def send(self):
global message, size, halign
if screen_manager.get_screen('chats').text_input != "":
message = screen_manager.get_screen('chats').text_input.text
if len(message)<6:
size=.22
halign="center"
elif len(message)<11:
size=.32
halign="center"
elif len(message) < 16:
size = .45
halign = "center"
elif len(message) < 21:
size = .58
halign = "center"
elif len(message) < 26:
size = .71
halign = "center"
else:
size = .77
halign = "left"
screen_manager.get_screen('chats').chat_list.add_widget(Command(text=message,size_hint_x=size,halign=halign))
Clock.schedule_once(response, 1)
screen_manager.get_screen('chats').text_input.text = ""
global counter
counter = 0
def clear_image(self):
global counter
if counter==0:
self.ids.img2.source ='LOGO.png'
self.ids.img2.reload()
counter += 1
elif counter==1:
self.ids.img2.source ='on.png'
self.ids.img2.reload()
counter += 1
elif counter==2:
self.ids.img2.source ='off.png'
self.ids.img2.reload()
counter += 1
elif counter==3:
self.ids.img2.source =''
self.ids.img2.reload()
counter =0
if __name__ == "__main__":
main().run()
My chats.kv file
<Command>
size_hint_y:None
pos_hint:{"right": .99}
height: self.texture_size[1]
padding: 12,10
theme_text_color: "Custom"
text_color:53/255,56/255,60/255,1
canvas.before:
Color:
rgb: (1, 1,1,1)
RoundedRectangle:
size:self.width,self.height
pos:self.pos
radius:[23,0,23, 23]
<Response>
size_hint_y:None
pos_hint:{"x": .01}
height: self.texture_size[1]
padding: 12,10
theme_text_color: "Custom"
text_color: 53/255,56/255,60/255,1
canvas.before:
Color:
rgb: ( 0,1,1, 1)
RoundedRectangle:
size:self.width,self.height
pos:self.pos
radius:[0,23,23,23]
MDScreen:
bot_name: bot_name
text_input: text_input
chat_list: chat_list
name: "chats"
MDFloatLayout:
canvas :
Color:
rgb:1,1,1, 1
Rectangle:
id: img2
source:'q3.png'
size:self.size
pos:self.pos
MDFloatLayout:
md_bg_color: 0,1,1,1
size_hint_y:.11
pos_hint: {"center_y":.96}
MDLabel:
id: bot_name
text:"OLIVIA"
right_action_items: [["dots-vertical", lambda x: app.callback(x)]]
font_size: "25sp"
pos_hint: {"center_y": .43}
halign: "center"
theme_text_color: "Custom"
text_color: 53/255,56/255,60/255,1
MDIconButton:
icon:"emma.png"
pos_hint:{"center_x":.2,"center_y":.43}
user_font_size:"15sp"
theme_text_color:"Custom"
text_color:53/255,56/255,60/255,1
md_bg_color: 127/255,1, 212/255, 1
MDIconButton:
icon:"video-outline"
pos_hint:{"center_x":.80,"center_y":.43}
user_font_size:"31sp"
theme_text_color: "Custom"
text_color:53/255,56/255,60/255,1
MDIconButton:
text:"M"
pos_hint:{"center_x":.90,"center_y":.43}
user_font_size:"31sp"
theme_text_color: "Custom"
text_color:53/255,56/255,60/255,1
on_release: app.clear_image()
ScrollView:
size_hint_y:.78
background_color:1,1,1,1
pos_hint:{"x":0,"y":.116}
do_scroll_x:False
do_scroll_y:True
BoxLayout:
id:chat_list
orientation:'vertical'
size:(root.width,root.height)
height:self.minimum_height
size_hint:None, None
pos_hint:{"top": 1}
cols:1
spacing:3
MDFloatLayout:
size_hint_y:.08
md_bg_color:0,1,1,1
MDFloatLayout:
size_hint:.8, .75
pos_hint:{"center_x":.43,"center_y":.5}
md_bg_color:0,1,1,1
canvas:
Color:
rgb:1,1,1, 1
RoundedRectangle:
size:self.size
pos:self.pos
radius:[23, 23, 23, 23]
TextInput:
id:text_input
hint_text:"Type your message"
size_hint:1, None
pos_hint:{"center_x":.5,"center_y":.5}
multiline:False
font_size:"18sp"
height:self.minimum_height
cursor_color:1, 170/255, 23/255, 1
cursor_width:"2sp"
foreground_color:53/255,56/255,60/255,1
background_color:0,0,0,0
padding:30
MDIconButton:
icon:"send-outline"
pos_hint:{"center_x":.91,"center_y":.5}
user_font_size:"23sp"
theme_text_color:"Custom"
text_color:1,1,1,1
md_bg_color: 0,1,1,1
on_press:app.send()
Any help would be great

You cannot assign an id to a canvas instruction, but you can assign one to the widget that contains the canvas instruction. And, if you want to change the canvas instruct using python, it will be easier if the canvas instructions are defined in python rather than in kv. In order to do that, you can define an extension of MDFloatLayout that does the canvas instructions:
class MyMDFloatLayout(MDFloatLayout):
def __init__(self, **kwargs):
super(MyMDFloatLayout, self).__init__(**kwargs)
with self.canvas:
Color(1, 1, 1, 1) # set the colour
# Setting the size, position, and source of canvas
self.rect = Rectangle(pos=self.pos,
size=self.size,
source='q3.png')
# Update the canvas when the position/size changes
self.bind(pos=self.update_rect,
size=self.update_rect)
# update function which makes the canvas adjustable.
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
Then you can use this widget in your kv file in place of the MDFloatLayout that contains the canvas that we want to adjust:
MyMDFloatLayout:
id: img2
# canvas :
# Color:
# rgb:1,1,1, 1
# Rectangle:
# id: img2
# source:'q3.png'
# size:self.size
# pos:self.pos
Note that these canvas instructions in the kv are no longer required
Then, in your python code:
def clear_image(self):
global counter
if counter == 0:
widget = self.root.get_screen('chats').ids.img2
widget.rect.source = 'LOGO.png'
# self.ids.img2.source = 'LOGO.png'
# self.ids.img2.reload()
counter += 1
and similar for the other counter values.

Related

Why do I get a black screen when I increase the font size and how do I fix it? kivy

By pressing the two buttons I display the information (text) obtained from the site. But when I try to increase the font size of this text, I get a black screen at all values above a certain one.
For example at a size of 35 I still display the text, but at 40 it is already a black screen
python script:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from bs4 import BeautifulSoup
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
import requests
Builder.load_string('''
# Define the scroll view
<ScrollableLabel>:
Label:
canvas.before:
Color:
rgba: (.93, .91, .67, 1)
Rectangle:
pos: self.pos
size: self.size
padding: (10,10)
id: label
color: (0,0,0,1)
font_size: 35
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
<MyGridLayout>:
spacing: 30
size_hint_y: None
size: self.width, 200
padding: (10,0,10,10)
<NextButton>:
text: 'Следующая стр...'
font_size: self.width / 9
size_hint: 0.02,1
background_color: (.93, .91, .67, 1)
background_normal: ''
color: (0,0,0,1)
<PreviousButton>:
text: 'Предыдущая стр...'
font_size: self.width / 9
size_hint: 0.02,1
background_color: (.93, .91, .67, 1)
background_normal: ''
color: (0,0,0,1)
<MyLabel>:
size_hint: 0.01,0.01
''')
x = 1
class MyGridLayout(GridLayout):
pass
class NextButton(Button):
pass
class PreviousButton(Button):
pass
class MyLabel(Label):
pass
class MyButton(Button):
color = (0, 0, 0, 1)
valign = 'bottom'
padding_y = 10
background_color = (.93, .91, .67, 1)
background_normal = ''
font_size = 35
class ScrollableLabel(ScrollView):
pass
class Box(BoxLayout):
color = (.98, .98, .82, 1)
orientation = "vertical"
spacing = 10
def on_kv_post(self, widget):
self.add_widget(MyButton(text='4 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='5 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='6 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='7 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='8 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='9 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='10 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='11 класс', on_press=self.btn_menu))
def btn_menu(self, widget):
self.clear_widgets()
self.add_widget(MyButton(text='И. С. Тургенев. Отцы и дети', on_press=self.btn_press))
self.add_widget(MyButton(text='И. А. Гончаров. Обломов.', on_press=self.btn_press))
self.add_widget(MyButton(text='Ф. М. Достоевский. Преступление и наказание.', on_press=self.btn_press))
self.add_widget(MyButton(text='Л. Н. Толстой. Война и мир.', on_press=self.btn_press))
self.add_widget(MyButton(text='Н. С. Лесков. Очарованный странник. ', on_press=self.btn_press))
self.add_widget(MyButton(text='Н. А. Некрасов. Лирика. Кому на Руси жить хорошо...', on_press=self.btn_press))
self.add_widget(MyButton(text='А. И. Островский. Гроза.', on_press=self.btn_press))
self.add_widget(MyButton(text='А. П. Чехов. Вишневый сад.', on_press=self.btn_press))
def btn_press(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
global x
data = ''
url = "http://loveread.ec/read_book.php?id=12021&p=1"
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
sc.ids.label.text = data
self.add_widget(sc)
gd = MyGridLayout(cols=3)
gd.add_widget(PreviousButton(on_press=self.previous_page))
gd.add_widget(MyLabel(text=f'стр № {x}', color=(1, 1, 1, 1)))
gd.add_widget(NextButton(on_press=self.next_page))
self.add_widget(gd)
def next_page(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
data = ''
global x
x += 1
url = "http://loveread.ec/read_book.php?id=12021&p=" + f'{x}'
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
sc.ids.label.text = data
self.add_widget(sc)
gd = MyGridLayout(cols=3)
gd.add_widget(PreviousButton(on_press=self.previous_page))
gd.add_widget(MyLabel(text=f'стр № {x}'))
gd.add_widget(NextButton(on_press=self.next_page))
self.add_widget(gd)
def previous_page(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
data = ''
global x
if x != 1:
x -= 1
url = "http://loveread.ec/read_book.php?id=12021&p=" + f'{x}'
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
sc.ids.label.text = data
self.add_widget(sc)
gd = MyGridLayout(cols=3)
gd.add_widget(PreviousButton(on_press=self.previous_page))
gd.add_widget(MyLabel(text=f'стр № {x}'))
gd.add_widget(NextButton(on_press=self.next_page))
self.add_widget(gd)
class MyApp(App):
def build(self):
return Box()
if __name__ == "__main__":
MyApp().run()
How can i fix it?
The label and text, which i need are in this part of the code
<ScrollableLabel>:
Label:
canvas.before:
Color:
rgba: (.93, .91, .67, 1)
Rectangle:
pos: self.pos
size: self.size
padding: (10,10)
id: label
color: (0,0,0,1)
font_size: 35
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
Your Label is exceeding the max allowed Texture size. You can access the max allowed size as:
from kivy.graphics.opengl import glGetIntegerv, GL_MAX_TEXTURE_SIZE
max_texture_size = glGetIntegerv(GL_MAX_TEXTURE_SIZE)[0]
I suggest using a BoxLayout in your ScrollableLabel and put a series of Labels in the BoxLayout instead of just one huge Label. Or perhaps replace the ScrollableLabel with a TextInput with readonly: True.

Why does disabled_color not work on the disabled widget?

I encountered a problem that if I want to make TextInput disabled=True, it repaints the background and font in a grayer color. Background_disabled_normal: '' helped me, and removed color for background, but for font disabled_color does not work at all. The thing is that the TextInput's text appears when the program is running, not during the build phase. How to fix it I don't know)
All of the application code:
import time
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from bs4 import BeautifulSoup
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
import requests
Builder.load_string('''
# Define the scroll view
<ScrollableLabel>:
id: scrlv
TextInput:
id: tx
background_disabled_normal: ''
padding: (10,10)
background_color: (.93, .91, .67, 1)
font_size: 50
text_size: self.width, None
size_hint: 1,None
height: max(self.minimum_height, scrlv.height)
background_active: ''
background_normal: ''
readonly: True
<MyGridLayout>:
spacing: 30
size_hint_y: None
size: self.width, 200
padding: (10,0,10,10)
<NextButton>:
text: 'Следующая стр...'
font_size: self.width / 9
size_hint: 0.02,1
background_color: (.93, .91, .67, 1)
background_normal: ''
color: (0,0,0,1)
<PreviousButton>:
text: 'Предыдущая стр...'
font_size: self.width / 9
size_hint: 0.02,1
background_color: (.93, .91, .67, 1)
background_normal: ''
color: (0,0,0,1)
<MyLabel>:
size_hint: 0.01,0.01
''')
x = 1
class MyTextInput(TextInput):
pass
class ScrollableLabel(ScrollView):
pass
class MyGridLayout(GridLayout):
pass
class NextButton(Button):
pass
class PreviousButton(Button):
pass
class MyLabel(Label):
pass
class MyButton(Button):
color = (0, 0, 0, 1)
valign = 'bottom'
padding_y = 10
background_color = (.93, .91, .67, 1)
background_normal = ''
font_size = 35
class Box(BoxLayout):
color = (.98, .98, .82, 1)
orientation = "vertical"
spacing = 10
def on_kv_post(self, widget):
self.add_widget(MyButton(text='4 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='5 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='6 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='7 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='8 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='9 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='10 класс', on_press=self.btn_menu))
self.add_widget(MyButton(text='11 класс', on_press=self.btn_menu))
def btn_menu(self, widget):
self.clear_widgets()
self.add_widget(MyButton(text='И. С. Тургенев. Отцы и дети', on_press=self.btn_press))
self.add_widget(MyButton(text='И. А. Гончаров. Обломов.', on_press=self.btn_press))
self.add_widget(MyButton(text='Ф. М. Достоевский. Преступление и наказание.', on_press=self.btn_press))
self.add_widget(MyButton(text='Л. Н. Толстой. Война и мир.', on_press=self.btn_press))
self.add_widget(MyButton(text='Н. С. Лесков. Очарованный странник. ', on_press=self.btn_press))
self.add_widget(MyButton(text='Н. А. Некрасов. Лирика. Кому на Руси жить хорошо...', on_press=self.btn_press))
self.add_widget(MyButton(text='А. И. Островский. Гроза.', on_press=self.btn_press))
self.add_widget(MyButton(text='А. П. Чехов. Вишневый сад.', on_press=self.btn_press))
def btn_press(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
global x
data = ''
url = "http://loveread.ec/read_book.php?id=12021&p=1"
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
sc.ids.tx.text = data
self.add_widget(sc)
gd = MyGridLayout(cols=3)
gd.add_widget(PreviousButton(on_press=self.previous_page))
gd.add_widget(MyLabel(text=f'стр № {x}', color=(1, 1, 1, 1)))
gd.add_widget(NextButton(on_press=self.next_page))
self.add_widget(gd)
def next_page(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
data = ''
global x
x += 1
url = "http://loveread.ec/read_book.php?id=12021&p=" + f'{x}'
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
sc.ids.tx.text = data
self.add_widget(sc)
gd = MyGridLayout(cols=3)
gd.add_widget(PreviousButton(on_press=self.previous_page))
gd.add_widget(MyLabel(text=f'стр № {x}'))
gd.add_widget(NextButton(on_press=self.next_page))
self.add_widget(gd)
def previous_page(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
data = ''
global x
if x != 1:
x -= 1
url = "http://loveread.ec/read_book.php?id=12021&p=" + f'{x}'
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
sc.ids.tx.text = data
self.add_widget(sc)
gd = MyGridLayout(cols=3)
gd.add_widget(PreviousButton(on_press=self.previous_page))
gd.add_widget(MyLabel(text=f'стр № {x}'))
gd.add_widget(NextButton(on_press=self.next_page))
self.add_widget(gd)
class MyApp(App):
def build(self):
return Box()
if __name__ == "__main__":
MyApp().run()
TextInput itself and where its text is updated:
<ScrollableLabel>:
id: scrlv
TextInput:
id: tx
background_disabled_normal: ''
padding: (10,10)
background_color: (.93, .91, .67, 1)
font_size: 50
text_size: self.width, None
size_hint: 1,None
height: max(self.minimum_height, scrlv.height)
background_active: ''
background_normal: ''
readonly: True
sc.ids.tx.text = data

drag file onto bounding area of kivy widget

I want to display an Image when I drag a .png into a specific area of my Kivy window. I've been trying to visualize the bounding area of my widgets and layouts using
canvas.before:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
However I'm not convinced I understand this yet, because of the behavior I get with the following:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 20 08:42:50 2022
#author: erik
"""
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.core.window import Window
Builder.load_string('''
<MyLayout>:
padding: 20,20, 20, 20
id: img_box
orientation: 'vertical'
size_hint_min_x: self.minimum_width
size_hint_min_y: self.minimum_height
canvas.before:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
Splitter:
sizable_from: 'bottom'
id: dig_img_spltr
canvas.before:
Color:
rgb: 1, 1, 0
Rectangle:
pos: self.pos
size: self.size
#keep_within_parent: True
rescale_with_parent: True
Image:
id: dig_img
Button:
text: 'hello'
size_hint: .6,.6
pos_hint: {'center_x': .5, 'center_y':.5}
''')
class MyLayout(BoxLayout):
digimgfilePath = StringProperty('')
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
Window.bind(on_drop_file=self._on_file_drop)
def _on_file_drop(self, window, filename, x, y):
'''
Documentataion for on_drop_file
doesn't show window parameter. I
found this out with locals()
'''
print(f'x: {x}')
print(f'y: {y}')
x_lower_bound = self.ids.dig_img_spltr.pos[0]
x_upper_bound = self.ids.dig_img_spltr.pos[0] + self.ids.dig_img_spltr.width
y_lower_bound = self.ids.dig_img_spltr.pos[1]
y_upper_bound = self.ids.dig_img_spltr.pos[1] + self.ids.dig_img_spltr.height
print(f'xlb {x_lower_bound}')
print(f'xub {x_upper_bound}')
print(f'ylb {y_lower_bound}')
print(f'yub {y_upper_bound}')
print()
#if x_lower_bound < x < x_upper_bound and y_lower_bound < y < y_upper_bound:
if self.ids.dig_img_spltr.collide_point(x,y):
self.digimgfilePath = filename.decode("utf-8") # convert byte to string
self.ids.dig_img.source = self.digimgfilePath
self.ids.dig_img.reload() # reload image
class sliderdropApp(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
sliderdropApp().run()
What I want, and expect, is for a image (.png for example) to be displayed when I drop the file into the area above the splitter. But I can't make sense of the area where collide_point returns True. It returns True when I drop the file within some un-explainable margin above and below the splitter. After I do get an image to display, the splitter canvas does to turn yellow above the splitter. Is this yellow area defined by the canvas not the same area of the splitter? Why doesn't collide_point return True when I drop on the area colored by the splitter's canvas?
The y dimension from the on_drop_file event is inverted from the window coordinates. If I send (x, Window.size[1] - y) to collide_point, it works as I expect and intent it to.

KIVY zindex dynamic change

I am trying to add 4 boxes in Relativelayout. Able to horizontally move only the box which gets added last in relativelayout. All other box gets strucked up when it is moved closer to its box which got added later. In given sample code below 'Actor 400' freely moves horizontally across the scene. 'Actor 300' able to move freely over 'Actor 200' and 'Actor 100'. But when I try to move Actor 300 above Actor 400, it get strucked and only after mouse moves beyond Actor 400, I am able to move.
Can I change the zindex of the widget dynamically when I touch it.
from kivy.app import App
from kivy.graphics import Line, Color
from kivy.uix.scatter import Scatter
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.lang import Builder
KV = '''
<Actor>:
canvas:
Color:
rgba: 0,1,0,.8
Rectangle:
id: _rect_
size: 100, 30
pos: 0, root.height - 30
Line:
points: 50, root.height - 30, 50, 20
width:2
Label:
id: _actr_lbl
text: 'Hello World'
color: 0,0,0,1
size_hint: None, None
size: 100, 30
pos: 0, root.height - 30
'''
Builder.load_string(KV)
class Actor(Scatter):
def __init__(self, **kwargs) :
Name = kwargs.pop('Name', 'Actor-NoName')
super(Actor, self).__init__(**kwargs)
self.Name = Name
self.ids._actr_lbl.text = Name
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.selected = True
self.pos_hint = {'top':1}
self.hint_diff_touch_to_x = self.right - touch.x
return True
return super(Actor, self).on_touch_down(touch)
def on_touch_move(self, touch):
if (self.selected) :
future_right = touch.x + self.hint_diff_touch_to_x
if (future_right <= self.parent.size[0]) and ((future_right - self.width) >= 0) :
self.right = future_right
self.pos_hint = {'top':1}
return True
return super(Actor, self).on_touch_move(touch)
def on_touch_up(self, touch):
if (self.selected) :
self.selected = False
self.hint_diff_touch_to_x = 0
self.iy = 0
return True
return super(Actor, self).on_touch_up(touch)
class MyPaintApp(App):
def build(self):
root = RelativeLayout()
(ix, iy) = (100,100)
clr = Color(0.2, 0.2, 1)
for ix in [100, 200, 300, 400 ] :
root.add_widget(Actor(Name = 'Actor ' + str(ix), pos=(ix,0), size_hint=(None,1)))
return root
if __name__ == '__main__':
Window.clearcolor = (1, 1, 1, 1)
MyPaintApp().run()
When one of your Actor Widgets is selected, you can move it to the top by removing it and re-adding it, like this:
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.selected = True
self.pos_hint = {'top':1}
self.hint_diff_touch_to_x = self.right - touch.x
parent = self.parent
# move this Actor to the front
parent.remove_widget(self)
parent.add_widget(self)
return True
return super(Actor, self).on_touch_down(touch)

How do I use widget collision to switch screens in kivy?

Im trying to create a game which consists of several areas, accessed by moving the circle onto the boundaries of the screen. I created a transit widget and defined a function to switch screens when there's a collision but it keeps giving errors. The error I got is that WindowManager does not have an attribute manager.
.py file:
class Transit(Widget):
def transit(self,circle):
if self.collide_widget(circle):
WindowManager.manager.current = "a1"
pass
class Wall(Widget):
def collision(self, circle):
if circle.collide_widget(self):
if circle.center_x > (self.pos[0] + self.size[0]) or circle.center_x < self.pos[0]:
circle.velocity_x = -1 * circle.velocity_x
elif circle.center_x > self.pos[0] and circle.center_x < (self.pos[0] + self.size[0]):
circle.velocity_y = -1 * circle.velocity_y
class Circle(Widget):
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
velocity = ReferenceListProperty(velocity_x, velocity_y)
def move(self):
self.pos = Vector(*self.velocity) + self.pos
class Move(Widget):
circle = ObjectProperty(None)
wall1 = ObjectProperty(None)
wall2 = ObjectProperty(None)
wall3 = ObjectProperty(None)
wall4 = ObjectProperty(None)
transit1 = ObjectProperty(None)
def __init__(self, **kwargs):
super(Move, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down = self._on_keyboard_down)
Clock.schedule_interval(self.update, 0)
def update(self, dt):
self.circle.move()
self.wall1.collision(self.circle)
self.wall2.collision(self.circle)
self.wall3.collision(self.circle)
self.wall4.collision(self.circle)
self.transit1.transit(self.circle)
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.circle.velocity_x -= 0.1
elif keycode[1] == 'right':
self.circle.velocity_x += 0.1
elif keycode[1] == 'up':
self.circle.velocity_y += 0.1
elif keycode[1] == 'down':
self.circle.velocity_y -= 0.1
return True
class Menu(Screen):
pass
class Start(Screen):
pass
class area1(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("dw.kv")
class Adventure(App):
def build(self):
return kv
Adventure().run()
and heres my .kv file
Circle:
size: 30,30
canvas:
Ellipse:
pos: self.pos
size: self.size
WindowManager:
Menu:
Start:
area1:
Menu>:
name: "menu"
#Adding gridlayout
GridLayout:
rows :3
cols : 1
AnchorLayout:
anchor_x : "center"
anchor_y : "center"
Label:
text: "Adventure"
font_size: 40
AnchorLayout:
anchor_x : "center"
anchor_y : "center"
TextInput:
id: ign
size_hint : (.4, None)
height : 30
hint_text : "Enter your name"
multiline : False
AnchorLayout:
anchor_x : "center"
anchor_y : "center"
Button:
text: "Start"
font_size: 40
size: 100, 75
size_hint: (None, None)
on_release: app.root.current = "start"
Start>:
name: "start"
Move:
wall1 : r1
wall2 : r2
wall3 : r3
wall4 : r4
transit1 : t1
circle : circle
Circle:
id : circle
pos: root.center_x , root.center_y
Wall:
id : r1
pos: 0, 400
size: 350, 250
canvas:
Rectangle:
pos: self.pos
size: self.size
Wall:
id : r2
pos: 0 , 0
size: 350, 250
canvas:
Rectangle:
pos: self.pos
size: self.size
Wall:
id : r3
pos: 500 , 400
size: 800, 250
canvas:
Rectangle:
pos: self.pos
size: self.size
Wall:
id : r4
pos: 500 , 0
size: 800, 250
canvas:
Rectangle:
pos: self.pos
size: self.size
Transit:
id : t1
pos: 0, root.center_y
size: 1, 600
area1>:
name: 'a1'
Your only problem is that the line:
WindowManager.manager.current = "a1"
is trying to access the manager attribute of the WindowManager class. You actually want to access that attribute of the WindowManager instance. To do that, you can replace that line with:
App.get_running_app().root.current = "a1"

Resources