I'm trying to remove an Image widget after its animation is complete.
So far I have managed to animate the widget and then call the animation_complete method after the animation ends. Unfortunately, the widget is not removed.
What am I doing wrong?
class ShootButton(Widget):
def bullet_fly(self):
def animation_complete(animation, widget):
print "removing animation"
self.remove_widget(widget=bullet1)
with self.canvas:
bullet1 = Image(source='bullet.png', pos = (100,200))
animation1 = Animation(pos=(200, 300))
animation1.start(bullet1)
animation1.bind(on_complete=animation_complete)
You do not have to use the canvas to add an animation but add the widget directly using add_widget() and then remove it with remove_widget(). In your initial case bullet1 is not the children of ShootButton.
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.animation import Animation
Window.size = (360, 640)
class ShootButton(Widget):
def bullet_fly(self):
def animation_complete(animation, widget):
self.remove_widget(widget)
bullet1 = Image(source='bullet.png', pos = (100,200))
self.add_widget(bullet1)
animation1 = Animation(pos=(200, 300))
animation1.start(bullet1)
animation1.bind(on_complete=animation_complete)
class MyApp(App):
def build(self):
button = ShootButton()
button.bullet_fly()
return button
if __name__ == '__main__':
MyApp().run()
Related
I am currently trying to create an app using Kivy that will turn the video into grayscale when the button is pressed.
At first, I was able to display the camera image on the GUI, but I'm having trouble figuring out how to place buttons and other parts from here.
import sys
import numpy as np
import cv2
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics.texture import Texture
from kivy.clock import Clock
from kivy.core.window import Window
import datetime
import random
WINDOW_WIDTH = 1500
WINDOW_HEIGHT = 1008
### Setting of the window
Window.size = (WINDOW_WIDTH, WINDOW_HEIGHT)
class MyApp(App, Widget):
title = "opencv on kivy"
def __init__(self, **kwargs):
super(MyApp, self).__init__(**kwargs)
Clock.schedule_interval(self.update, 1.0 / 30)
self.widget = Widget()
# self.cap = cv2.VideoCapture(0)
self.cap = cv2.VideoCapture(1)
# The method by the intarval
def update(self, dt):
ret, img = self.cap.read()
### The color sequence in openCV is BGR, so fix it to RGB.
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
### The origin of Kivy's coordinates is the lower left, so flip it upside down.
img = cv2.flip(img, 0)
# if img is not None:
texture = Texture.create(size=(img.shape[1], img.shape[0]))
texture.blit_buffer(img.tostring())
with self.widget.canvas:
Rectangle(texture=texture ,pos=(0 + int(WINDOW_WIDTH/2) - int(img.shape[1]/2), WINDOW_HEIGHT - img.shape[0]), size=(img.shape[1], img.shape[0]))
return self.widget
def build(self):
return self.widget
# return MyApp()
if __name__ == '__main__':
MyApp().run()
Also, the application that displays the button works fine.
However, I have no idea how to combine these since build(self) can only return a button or a single widget for the camera image.
# import kivy module
import kivy
# this restrict the kivy version i.e
# below this kivy version you cannot
# use the app or software
kivy.require("1.9.1")
# base Class of your App inherits from the App class.
# app:always refers to the instance of your application
from kivy.app import App
# creates the button in kivy
# if not imported shows the error
from kivy.uix.button import Button
# class in which we are creating the button
class ButtonApp(App):
def build(self):
btn = Button(text ="Push Me !")
return btn
# creating the object root for ButtonApp() class
root = ButtonApp()
# run function runs the whole program
# i.e run() method which calls the
# target function passed to the constructor.
root.run()
thank you in advance.
You can use self.add_widget(..) to add other widgets inside Widget, Button, etc. but it doesn't have function to automatically arange layout.
But build() can use any widget - it doesn't have to Button or Widget.
If you use BoxLayout then you can use self.add_widget(...) to add widgets in rows or columns.
Other layout widgets can be useful to organize widgets in different way.
class MyApp(App, BoxLayout): # class MyApp(App, Widget)
def __init__(self, **kwargs):
# ... code ...
self.orientation = 'vertical' # BoxLayout
self.widget = Widget()
self.add_widget(self.widget)
self.button = Button(text='Gray', on_press=self.change_color)
self.add_widget(self.button)
Full working code.
I use BoxLayout with orientation = 'vertical' to organize in rows I put Widget in top row, and Button in bottom row.
Button runs function which switch value self.convert_to_grey - True/False - and update() uses this value to convert image to gray (and back to RGB but with gray color)
import sys
import numpy as np
import cv2
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.graphics.texture import Texture
from kivy.clock import Clock
from kivy.core.window import Window
import datetime
import random
WINDOW_WIDTH = 1500
WINDOW_HEIGHT = 1008
### Setting of the window
Window.size = (WINDOW_WIDTH, WINDOW_HEIGHT)
class MyApp(App, BoxLayout):
title = "opencv on kivy"
def __init__(self, **kwargs):
super(MyApp, self).__init__(**kwargs)
self.orientation = 'vertical' # BoxLayout
self.convert_to_grey = False #
self.cap = cv2.VideoCapture(0)
#self.cap = cv2.VideoCapture(1)
self.widget = Widget()
self.add_widget(self.widget)
self.button = Button(text='Gray', on_press=self.change_color)
self.add_widget(self.button)
Clock.schedule_interval(self.update, 1.0 / 30)
def change_color(self, *args):
print('args:', args)
self.convert_to_grey = not self.convert_to_grey
def update(self, dt):
ret, img = self.cap.read()
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.flip(img, 0)
if self.convert_to_grey:
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
texture = Texture.create(size=(img.shape[1], img.shape[0]))
texture.blit_buffer(img.tostring())
with self.widget.canvas:
Rectangle(texture=texture, pos=(0 + int(WINDOW_WIDTH/2) - int(img.shape[1]/2), WINDOW_HEIGHT - img.shape[0]), size=(img.shape[1], img.shape[0]))
return self.widget
def build(self):
return self
if __name__ == '__main__':
MyApp().run()
More layouts in Kivy doc:
Getting Started ยป Layouts
BTW: you can nested layouts - ie. inside BoxLayout you can use one row with GridLayout and other row with different layout or widget.
from kivy.uix.button import Button
from kivy.uix.behaviors.button import ButtonBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
from kivy.uix.widget import Widget
from kivy.graphics import BorderImage
from kivy.graphics import Color, RoundedRectangle, Rectangle, Triangle
from kivy.core.window import Window
#from kivy.config import Config
from kivy.uix.checkbox import CheckBox
from kivy.uix.popup import Popup
from kivy.uix.scrollview import ScrollView
from kivy.uix.filechooser import FileChooserListView
from kivy.properties import ObjectProperty
class OpeningPage(FloatLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.but = RoButton(text = 'START', pos = (350,100), font_size=14, size=(100,60), size_hint=(None,None))
self.add_widget(self.but)
class RoButton(Button):
butt = ObjectProperty()
def __init__(self, **kwargs):
super(RoButton, self).__init__(**kwargs)
text = self.text
with self.canvas:
# Color(1., 0, 0)
self.butt = RoundedRectangle( size= self.size, pos = self.pos, radius =[400])
class UI(App):
def build(self):
self.screen_manager = ScreenManager()
self.opening_page = OpeningPage()
screen = Screen(name ='Opening_Page')
screen.add_widget(self.opening_page)
self.screen_manager.add_widget(screen)
return self.screen_manager
if __name__ == '__main__':
the_app = UI()
the_app.run()
Everytime I try to make a circular button using this code I get a box behind the circle. I tried doing self.canvas.before but still no luck if possible could answers be in python rather than .kv language thanks.
Attached image of problem]1
The box you see is the normal Button image. If you don't want that, probably don't use a Button, instead use class RoButton(ButtonBehavior, Widget):.
I am trying to make tambola coin picker with Python and Kivy and I am new to kivy.
Here, I created gridlayout buttons from 1 to 90. I want to change the color of particular button in gridlayout when its number is picked. I am facing issues to update gridlayout with new colored button. Here I am attaching my code. screenshot
#!/usr/bin/python
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import Color
import random
coins = random.sample(range(1,91), 90)
#print(coins)
picked_coins=[]
current_coin=0
#print(picked_coins)
class Housie(FloatLayout):
def __init__(self,**kwargs):
super(Housie,self).__init__(**kwargs)
self.title = Label(text="Housie Coin Picker",font_size = 50,size_hint=(1, .55),pos_hint={'x':0, 'y':.45})
self.main_label = Label(text = "Click PICK NUMBER", size_hint=(1, .60),pos_hint={'x':0, 'y':.35})
self.picked_ones = Label(text = "picked_coins", size_hint=(1, .40),pos_hint={'x':0, 'y':.40})
self.help_button = Button(text = "PICK NUMBER", size_hint=(.3, .1),pos_hint={'x':.65, 'y':.1},on_press = self.update)
self.add_widget(self.title)
self.add_widget(self.main_label)
self.add_widget(self.picked_ones)
self.add_widget(self.help_button)
self.add_widget(self.userinterface())
def userinterface(self):
self.layout = GridLayout(cols = 10,size_hint=(.50, .50))
for i in range(1,91):
self.layout.add_widget(Button(background_color=(1,0,0,1),text =str(i)))
return self.layout
def update(self,event):
for coin in coins:
if coin not in picked_coins:
current_coin=coin
picked_coins.append(coin)
self.main_label.text = str(coin)
for i in self.layout.children:
if i.text == str(coin):
#What to do Here?
break
self.picked_ones.text = "Picked coins = {}".format(" ".join(str(sorted(picked_coins))))
class app1(App):
def build(self):
return Housie()
if __name__=="__main__":
app1().run()
You can bind a method to each Button like this:
def userinterface(self):
self.layout = GridLayout(cols = 10,size_hint=(.50, .50))
for i in range(1,91):
self.layout.add_widget(Button(background_color=(1,0,0,1),text=str(i), on_release=self.butt_pressed))
return self.layout
def butt_pressed(self, button):
button.background_normal = ''
button.background_color = (1,0,0,1)
Th butt_pressed() method changes the background color of the pessed Button.
I have put the video inside kivy canvas, first 3 sec showing image afterthat will be play video. But only show all time image only.
Any suggestion.
Thanks
import kivy
from kivymd.app import MDApp
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle ,Color
from kivy.core.video import Video as CoreVideo
from kivy.clock import Clock
class Mycanvas(Widget):
def __init__(self,**kw):
super(Mycanvas,self).__init__(**kw)
with self.canvas:
self.bg = Rectangle(source='Flower.jpg', pos=self.pos, size=self.size)
self.video = CoreVideo()
self.video.bind(on_frame=self.set_bg_texture)
self.video.filename = 'Garden.mp4'
Clock.schedule_once(self.start_vid, 3)
self.start_vid(3)
def start_vid(self, dt):
self.video.play()
def set_bg_texture(self, *args):
self.bg.texture = self.video.texture
class mainapp(MDApp):
def build(self):
return Mycanvas()
mainapp().run()
Hello i'm relatively new to python and kivy and I've been looking around but i cant quite find the answer, i'm trying to make a hub where I can display live data from my rasberry-pi. I made a clock widget using a Label, and it updates time, but when i try to add my CPU usage only one label shows up. I thought the widgets might be covering each other but I used size_hint and it wont help. When i run the code below, only the timex will show up and only if i delete the Clock.schedule_interval(display32.timex, (1)) will the *updatex * display.
Thanks alot for the help
from kivy.app import App
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
import psutil
from kivy.lang import Builder
import time
class Display(Label, FloatLayout):
def __init__(self):
super(Display, self).__init__()
def updatex(self, *args):
self.cpu2 = psutil.cpu_percent()
self.text=str(self.cpu2)
self.size_hint=(.5, .25)
self.pos=(500, 500)
self.texture_size=(0.1,0.1)
def timex(self, *args):
self.time2 = time.asctime()
self.text = str(self.time2)
self.size_hint = (.5, .25)
self.pos = (30, 500)
self.size_hint=(0.1,0.1)
class TimeApp(App):
def build(self):
display32 = Display()
Clock.schedule_interval(display32.updatex, (1))
Clock.schedule_interval(display32.timex, (1))
return display32
if __name__ == "__main__":
TimeApp().run()
Instead of passing both labels to the clock, you can define a widget, add both labels and start the clock on the widget.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.clock import Clock
import psutil
import time
class Display(Widget):
def draw(self, *args):
self.clear_widgets()
self.add_widget(Label(text=str(psutil.cpu_percent()), pos=(500, 500)))
self.add_widget(Label(text=str(time.asctime()), pos=(30, 500)))
class TimeApp(App):
def build(self):
display32 = Display()
Clock.schedule_interval(display32.draw, 1)
return display32
if __name__ == '__main__':
TimeApp().run()