Trouble with Kivy Python? Function error and image error - python

I am trying to use Kivy to build an app.
Here is the code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
class Background_Animation(Widget):
def __init__(self, imageStr, **kwargs):
super(Background_Animation, self).__init__(**kwargs)
self.__init__= __init__(self, imageStr, **kwargs)
with self.canvas :
self.size= (Window.width * 0.002 * 25, Window.height *0.002 * 25 )
# bind the fbo to the current opengl context
self.bind(pos == self.update_graphics_pos)
# x center position
self.x = self.center_x
# declare the image
imageStr= Image("~/Downloads/psychTREE.jpg", **kwargs)
# y center position
self.y = self.center_y
self.pos= (self.x, self.y)
self.image= self.pos
return image
def build(self):
self.build = build
run = __init__(self, imageStr, **kwargs)
return run
if __name__ == "__main__" :
build(self, imageStr, **kwargs).run()
When I try to run the code, it says name "build" is not defined . Any ideas on how to solve this problem? Also, how would I make the image appear in the gui?

Related

How to align a rectangle using kivy?

Does anybody know the code to center align a rectangle using kivy but in a py file not kv. This is my code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics import Color
class PongGame(Widget):
def __init__(self, **kwargs):
super(PongGame, self).__init__(**kwargs)
with self.canvas:
Color(255,255,255, mode='rgba')
self.rect = Rectangle(pos=(self.x + 50, self.y + 50), size=(50, 50))
# print(self.rect)
class PingyPong(App):
def build(self):
return PongGame()
# class MakeRectangle(Widget):
# def __init__(self, **kwargs):
# with self.canvas:
# # Color(255,255,255, mode='rgba')
# self.rect = Rectangle(pos=(200, 200), size=(50, 50))
# class PingPong(App):
# def build(self):
# return Rectangle()
if __name__ == '__main__':
PingyPong().run()
This is the output:
enter image description here
please help
You can do it by getting Window size and then create rectangle at the center
from kivy.core.window import Window
class PongGame(Widget):
def __init__(self, **kwargs):
super(PongGame, self).__init__(**kwargs)
with self.canvas:
Color(255,255,255, mode='rgba')
window_size = Window.size
size = 50
self.rect = Rectangle(pos=(window_size[0]/2-size/2, window_size[1]/2-size/2), size=(size, size))
print()

How to update a texture from array in Kivy?

I'm new to Kivy, but have watched the tutorials. I want to have a widget containing a texture or image generated from an array, which will change at each frame. See below for what I currently have. Current behaviour is wrong when I resize the window - I think that the old Rectangle is never being deleted, but I can't see how to do that. It also shows the same image in a default (100,100) view at the bottom left of the main window. What do I need to change to achieve the desired behaviour, and not get artifacts when resizing the window?
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.layout import Layout
from kivy.graphics import Rectangle
from kivy.graphics.texture import Texture
from kivy.clock import Clock
import numpy as np
import random
class MainDisplay(Layout):
tex = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainDisplay, self).__init__(**kwargs)
Clock.schedule_once(self.texture_init, 0)
def texture_init(self, instance):
self.tex = Texture.create()
def update(self, dt):
size = 64 * 64 * 3
buf = np.array([int(random.random() * x * 255 / size) for x in range(size)])
print('update', max(buf), min(buf), np.mean(buf))
# then blit the buffer
self.tex.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
print('end update')
print(self.canvas)
print(self.size, self.pos, self, self.parent)
with self.canvas:
Rectangle(texture=self.tex, size=(self.width / 2, self.height / 2), pos=(self.center_x / 2, self.center_y / 2))
class MainWindow(BoxLayout):
md = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
def update(self, dt):
self.md.update(dt)
class ProtoApp(App):
def build(self):
mainWindow = MainWindow()
Clock.schedule_interval(mainWindow.update, 1.0/10.0)
return mainWindow
if __name__ == "__main__":
ProtoApp().run()
with the proto.kv file:
<MainWindow>:
md: md
MainDisplay:
id: md
size_hint: (0.5, 0.5)
Thanks in advance for your help!
Problem
Whenever the window is resized, it is creating new rectangle and leaving traces of the previous one.
Solution
Use the canvas's built-in function, clear()
Snippets
def update(self, dt):
size = 64 * 64 * 3
buf = np.array([int(random.random() * x * 255 / size) for x in range(size)])
# then blit the buffer
self.tex.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
with self.canvas:
self.rect = Rectangle(texture=self.tex, size=(self.width / 2, self.height / 2),
pos=(self.center_x / 2, self.center_y / 2))
self.bind(pos=self.update_rect, size=self.update_rect)
def update_rect(self, *args):
self.canvas.clear()
self.rect.pos = self.pos
self.rect.size = self.size

How to convert Kivy touch corordinates to widget space

i have a simple ModalView and its size is (640,426).My window's size is (1366,732).My Screen Resolution is (1366,768).When i click at the top left corner of the ModalView,i get something like 363,690.Which is my touch coordinates taken from the window itself.i would however like to somehow convert this value to local widget space so that touching the top left corner i get the coordinate (0,0) instead of (363,690).Is this possible with kivy or any other way.What Im trying to do,for those interested is to crop an image using a box drawn by the user.Drawing the box isn't the problem,the problem is getting those bounds and transfering them to the image's coords.
NB: I read about the to_local(),to_parent(),to_window() and those functions are simply not working...for some reason,maybe i missed a thing there,would appreciate your help big time
Here is the code similar to my usecase but stripped
from kivy.app import App
from kivy.uix.modalview import ModalView
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
class CropBounds(ModalView):
def __init__(self, **kwargs):
super(CropBounds, self).__init__(**kwargs)
self.to_crop = True
self.size = (400,400)
print('Center: ',self.center)
print('Size: ',self.size)
print('Window Center: ',Window.center)
print('Window Size:(',Window.width,',',Window.height,')')
def on_touch_down(self, touch):
self.canvas.clear()
if self.collide_point(*touch.pos) and self.to_crop:
with self.canvas:
self.start_x = touch.x
self.start_y = touch.y
touch.ud['area'] = Line(points=(touch.x, touch.y, touch.x, 400,touch.x, touch.y,touch.x, touch.y, touch.x, touch.y))
print("Pos: ",touch.pos)
print(touch.x,touch.y)
return True
return MainWindow().on_touch_down(touch)
class GalleryWindow(BoxLayout):
def __init__(self, **kwargs):
super(GalleryWindow, self).__init__(**kwargs)
self.add_widget(Button(text='crop',size_hint=(1,None),size=(None,40),on_release=self.crop_img))
def crop_img(self):
bounds = CropBounds()
bounds.open()
class GalleryApp(App):
def build(self):
return GalleryWindow()
if __name__=='__main__':
GalleryApp().run()
Subtracting the ModalView position from the touch coordinates does work. I think your are getting confused about the size and position of your ModalView. The way your code is written, the ModalView is the same size and position as your GalleryWindow (recall that the default size_hint is (1.0, 1.0)). So, for there to be any difference between coordinates in the ModalView and GalleryWindow, you need to change the size_hint for the ModalView.
After correcting many errors in your code (to get it to run). I have made some changes to demonstrate the position of the ModalView and the location of the touch.
Here is the code:
from kivy.app import App
from kivy.core.window import Window
from kivy.graphics.vertex_instructions import Line
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.modalview import ModalView
from kivy.uix.button import Button
class CropBounds(ModalView):
def __init__(self, **kwargs):
super(CropBounds, self).__init__(**kwargs)
self.to_crop = True
self.size_hint = (None, None) # without this, the size below has no effect
self.size = (400,400)
print('Center: ',self.center)
print('Size: ',self.size)
print('Window Center: ',Window.center)
print('Window Size:(',Window.width,',',Window.height,')')
def on_touch_down(self, touch):
if self.collide_point(*touch.pos) and self.to_crop:
self.canvas.clear()
with self.canvas:
# plot the boundary of the ModalView
Line(points=[self.pos[0], self.pos[1],
self.pos[0], self.pos[1] + self.height,
self.pos[0] + self.width, self.pos[1] + self.height,
self.pos[0] + self.width, self.pos[1],
self.pos[0], self.pos[1]])
# plot a line from the touch point to the pos of the ModalView
Line(points=[self.pos[0], self.pos[1], touch.x, touch.y])
# calculate touch minus position of ModalView
touch_in_modal = (touch.x - self.pos[0], touch.y - self.pos[1])
print('touch : ' + str(touch.pos) + ', touch in modal: ' + str(touch_in_modal))
return True
#return MainWindow().on_touch_down(touch)
class GalleryWindow(BoxLayout):
def __init__(self, **kwargs):
super(GalleryWindow, self).__init__(**kwargs)
self.add_widget(Button(text='crop',size_hint=(1,None),size=(40,40),on_release=self.crop_img))
def crop_img(self, *args):
bounds = CropBounds()
bounds.open()
class GalleryApp(App):
def build(self):
return GalleryWindow()
if __name__=='__main__':
GalleryApp().run()
If you want to see what was happening in your code, just comment out the size_hint line.
Also, when we ask you to post a MCV example, please try running what you post. If we have to debug your example before we can see what you problem is, you won't get many responses.

How do you add a controllable graphic with an image overtop in kivy?

I am new to python and have messed around with Kivy a little. This is the first app of my own design I've been tying to make. The goal is for it to be a game where there is a character that moves in all directions around the screen. My problem right now is that I can't get the character widget to display and I don't know if it's a problem with the widget or the image in the widget. When I run the program all I get is a black screen and no errors. Can anyone see where I went wrong?
Also if you have any recommendations in a better way to structure anything it would be appreciated :)
import kivy
kivy.require('1.7.2')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import NumericProperty
from kivy.graphics import Rectangle, Color, Canvas
from kivy.uix.image import Image
class WidgetDrawer(Widget):
def __inti__(self, imageStr, **kwargs):
super(WidgetDrawer,self).__inti__(**kwargs)
with self.canvas:
self.size = (Window.width*.05, Window.width*.05)
self.x = self.center_x
self.y = self.center_y
self.pos = (self.x, self.y)
self.rect_pl = Rectangle(source= imageStr, pos=self.pos, size=self.size)
self.bind(pos=self.update_graphics_pos)
self.rect_pl.pos = self.pos
def update_graphic_pos(self, value):
self.rect_pl.pos = value
def setSize(self, width, height):
self.size = (width,height)
class Player(WidgetDrawer):
impulse_x = 3
impulse_y = 3
winre = -0.1
velocity_x = NumericProperty(0)
velocity_y = NumericProperty(0)
def move(self):
self.x = self.x + self.velocity_x
self.y = self.y + self.velocity_y
if self.x > Window.width*.95 or self.x < Window.width*.05:
velocity_x = 0
if self.y > Window.height*.95 or self.y < Window.height*.05:
velocity_y = 0
def determineVelocity(self):
self.velocity_x = self.impulse_x + self.winre
self.velocity_y = self.impulse_y + self.winre
def update(self):
self.determineVelocity()
self.move()
class GUI(Widget):
def __init___(self, **kwargs):
super(GUI, self).__init__(**kwargs)
self.character = Player(imageStr = './character.png')
self.character.x = Window.width/4
self.character.y = Window.height/2
self.add_widget(self.character)
class GameApp(App):
def build(self):
parent = Widget()
app = GUI()
parent.add_widget(app)
return parent
if __name__ == '__main__':
GameApp().run()
The problem is self.add_widget(self.character) i.e. adding widget in __init__ method. Try to run python main.py -m inspector, Ctrl+E and get to GUI(). No children, nothing. Add children after __init__.
About the structure:
use kv language
use one naming style
fix typos(__inti__ != __init__)
if you have 1.7.2 version, you definitely need to update asap

Python Kivy widget animation

I've posted similar topic recently, but this time I'll try to be more clear and specific. My problem is that widgets in Kivy aren't animating as they are expected to. Here's some example code, why are scatters better to animate than widgets:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.animation import Animation
from kivy.graphics import Color, Rectangle
class ExampleWidget(Widget):
def __init__(self, **kwargs):
super(ExampleWidget, self).__init__(**kwargs)
self.size = (100,100)
self.pos = (100,100)
with self.canvas:
Color(1,0,0)
self.texture = Rectangle(size=self.size, pos=self.pos)
def on_pos(self, obj, value):
try: self.texture.pos = value
except: pass
class ExampleScatterTexture(Widget):
def __init__(self, **kwargs):
super(ExampleScatterTexture, self).__init__(**kwargs)
with self.canvas:
Color(0,1,0)
texture = Rectangle(size=self.size, pos=self.pos)
class ExampleScatter(Scatter):
def __init__(self, **kwargs):
super(ExampleScatter, self).__init__(**kwargs)
self.do_rotation = False
self.do_scale = False
self.do_translation = False
self.size = (100,100)
self.pos = (100,300)
texture = ExampleScatterTexture(size=self.size)
self.add_widget(texture)
class ExampleScreen(Widget):
def __init__(self, **kwargs):
super(ExampleScreen, self).__init__(**kwargs)
self.size = Window.size
example_widget = ExampleWidget()
self.add_widget(example_widget)
example_scatter = ExampleScatter()
self.add_widget(example_scatter)
#SCATTER IS GREEN, WIDGET IS RED
example_widget_animation = Animation(pos=(300,100), duration=2., t='in_bounce') + Animation(pos=(100,100), duration=2., t='in_bounce')
example_scatter_animation = Animation(pos=(300,300), duration=2., t='in_bounce') + Animation(pos=(100,300), duration=2., t='in_bounce')
example_widget_animation.repeat = True
example_scatter_animation.repeat = True
example_widget_animation.start(example_widget)
example_scatter_animation.start(example_scatter)
class BadAnimationExample(App):
def build(self):
root = ExampleScreen()
return root
if __name__ == "__main__":
BadAnimationExample().run()
As you can see, the widget animation is executed very fast and then there comes a pause, while scatter animation is very much like we expect it to be. My problem is that when I have my finger on the scatters all my on_touch_move() functions aren't working. Is there any solution?
Ok, I fixed the problem. I used my on_touch_move() method in the child widget class and the solution is to use it in the parent widget. Then there is no problem with scatter selection.

Categories