Input methods in Kivy - python

I was trying to get continuous touch motion in Kivy to move a rectangle for which I wrote a code
from kivy.app import App
from kivy.uix.button import Label
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.core.window import Window
class Game(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
with self.canvas:
Color=(0,1,0,1)
self.player=Rectangle(pos=(50,0),size=(20,50))
#touch and motion of our player
def on_motion(self,etype,motionevent,**kwargs):
print('hello')
touch_condition=False
x_touch=motionevent.spos[0]
xa=self.player.pos[0]
ya=self.player.pos[1]
if etype=='begin' or etype=='update':
touch_condition=True
if etype=='end':
touch_condition=False
if touch_condition and x_touch>0.5:
xa+=10
if touch_condition and x_touch<0.5:
xa-=10
self.player.pos=(xa,ya)
Window.bind(on_motion=on_motion)
class Try(App):
def build(self):
return Game()
if __name__=="__main__":
Try().run()
On mouse click as an input its giving an error
File "kiv.py", line 21, in on_motion
xa=self.player.pos[0] AttributeError: 'WindowSDL' object has no attribute 'player'
I read all documentation on Kivy inputs and Window.bind but I am still unable to understand how to solve it.

Your class structure is messed up, you're binding on_motion at the class level. I'm surprised this is the error you get, but that looks like the problem.
Add Window.bind(on_motion=self.on_motion) in the __init__ of your Game widget instead.

Related

MDSlider Bug in KivyMD - on_touch_up gets fired when clicked on the screen

I am facing a problem, where I want to get the value of the MDslider in KivyMD using the on_touch_up() method, it works but the problem is even when I click/touch anywhere on the screen apart from the MDSlider the on_touch_up() method gets fired.
And when I click/touch on the MDSlider the method gets fired twice
Code
from kivy.lang import Builder, builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivymd.uix.button import MDRectangleFlatButton
from kivymd.uix.slider import MDSlider
from kivymd.uix.gridlayout import MDGridLayout
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
self.slider = MDSlider(
min=0,
max=100,
size_hint=(0.4,0.1),
pos_hint={'center_x':0.5, 'center_y':0.5}
)
self.slider.bind(on_touch_up = self.get_slider_value)
self.add_widget(self.slider)
def get_slider_value(self, obj, obj_prop):
print(obj.value)
class MyApp(MDApp):
def build(self):
return MyScreen()
if __name__ == "__main__":
MyApp().run()
Thank you for your time :)
That's not a bug, it is the designed behavior. All Widgets get the on_touch_up event. You must use the collide_point(*touch.pos) method to determine if the touch is on your Slider. However, the on_touch_up() being fired twice does seem like a bug. Consider using:
self.slider.bind(value = self.get_slider_value)
instead of on_touch_up.
To use collide_point() in the get_slider_value() (if you bind to on_touch_up) try something like:
def get_slider_value(self, slider, touch):
if slider.collide_point(*touch.pos):
print(slider.value)

How to change screen by swiping in kivy python

I am trying to change to another screen by swiping the screen. I've tried carousel but it seems that it only works with images, so I've tried detecting a swipe motion and changing the screen after it has been detected.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.button import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.carousel import Carousel
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
class HomeScreen(Screen):
def on_touch_move(self, touch):
if touch.x < touch.ox: # this line checks if a left swipe has been detected
MainApp().change_screen(screen_name="swipedhikr_screen") # calls the method in the main app that changes the screen
class ImageButton(ButtonBehavior, Image):
pass
class LabelButton(ButtonBehavior, Label):
pass
class SettingsScreen(Screen):
pass
class SwipeDhikrScreen(Screen):
pass
#def quit_verification():
# pop = Popup(title="verification", content=Label(text= "Are you sure?"))
GUI = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return GUI
def change_screen(self, screen_name):
# get the screen manager from the kv file
screen_manager = self.root.ids["screen_manager"]
screen_manager.transition.direction = "up"
screen_manager.current = screen_name
def quit_app(self):
MainApp().stop()
MainApp().run()
I got an attribute error: "None type object has no attribute 'ids'"
MainApp().change_screen(screen_name="swipedhikr_screen")
This line creates a new instance of MainApp, which doesn't have any widgets and therefore naturally fails when you try to access them.
Use the existing instance of MainApp, i.e. the one that you're actually running, via MainApp.get_running_app().
Also you are not correct that Carousel works only with images.

kivy python widget instance or all widgets

Please help me with understanding classes/instances in python. I want to make a few buttons, and change color of the button, when it's clicked. I don't understand why on_touch_down changes the color of all the instances of the class, not the one that is touched. It's difficult for me to find answer because I don't know how to name it, I don't have much experience with objects. Please explain this. Thank you a million.
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.graphics import Color, Ellipse
class MemoWidget(Button):
def on_touch_down(self, touch):
self.background_color=[100,100,1,1]
class MyApp(App):
def build(self):
root = BoxLayout(orientation='vertical',spacing=4)
m1 = MemoWidget()
m2 = MemoWidget()
m3 = MemoWidget()
root.add_widget(m1)
root.add_widget(m2)
root.add_widget(m3)
return root
if __name__ == '__main__':
MyApp().run()
You might think that on_touch_down only affects the widget you touch. But it affects all widgets of that class.
So what you might want, is on_press or on_release, to only affect the widget itself.
class MemoWidget(Button):
def on_release(self):
self.background_color=[100,100,1,1]

What is a root widget and how to implement it in Kivy Python ?

Here is my code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.image import Image as CoreImage
class WeaselApp(App):
def __init__(self, image):
self.image = image
def coreimage(self, load_image):
self.load_image = load_image
load_image = CoreImage("psychTREE.jpg")
#return load_image
def built(self):
return coreimage(self, load_image)
if __name__== "__main__":
WeaselApp(App).run()
When I run it, it says " WeaselApp has no attribute 'root' ". Why is this the case? Any hints or suggestions are greatly appreciated.
You don't return any widget from your build method, for two reasons:
As Joran Beasley said, you need a build method, not built.
CoreImage is not a widget that can be displayed on screen, it's a low level tool to load image data. You should use a kivy.uix.image.Image widget.
Edit: Following the comments, replace your code with this:
from kivy.app import App
from kivy.uix.image import Image
class YourApp(App):
def build(self):
return Image(source='psychTREE.jpg')
YourApp().run() # edited this in after

kivy custom widget bind error

I am trying to make a small tetris game for learning python with kivy. I am trying to create a custom widget with size 20,20. When I add it to the float layout and run the below code I receive the following error:
Error:
File "D:\OS Files\workspace\Tetris\holder.py", line 10, in __init__ self.add_widget(c)
File "C:\Kivy180\kivy\kivy\uix\floatlayout.py", line 115, in add_widget pos_hint=self._trigger_layout)
TypeError: descriptor 'bind' of 'kivy._event.EventDispatcher' object needs an argument
Code:
holder.py File:
from items import Cell
class Holder(FloatLayout):
def __init__(self, **kwargs):
super(Holder,self).__init__(**kwargs)
self.size=(300,300)
c=Cell
#c.pos= (20,20)
self.add_widget(c)
#self.add_widget(c)
items.py File:
from kivy.uix.widget import Widget
from kivy.graphics import *
class Cell(Widget):
def __init__(self, **kwargs):
super(Cell,self).__init__(**kwargs)
with self.canvas:
Color(1, 0, 0)
Rectangle(pos=(0, 0), size=(50, 50))
self.height=50
self.width=50
main.py File:
from kivy.app import App
from holder import Holder
class start(App):
def build(self):
return Holder()
if __name__ == '__main__':
start().run()
Could you please explain where I went wrong, I am stuck at the starting point itself. Regarding the error, I haven't written any events also, and it is just a widget class. Could you please explain where I went wrong in understanding kivy.
c=Cell
I bet you want c to be an instance of the Cell class. If you want to do that, you need to do:
c=Cell()

Categories

Resources