Kivy Dynamic selection image according to button - python

I want to place image on button. Button's size depends on size of screen. I want to select ideal image's size according to button's size. Buttons are defined in class ButtonTools. With my knowledges I cann obtain size only in fuction of class ButtonTools. How do I obtain size of screen?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.image import Image
class Paint(Widget):
pass
class ButtonTools(BoxLayout):
def __init__(self, **kwargs):
super(ButtonTools, self).__init__(**kwargs)
self.size_hint = (1, None)
self.height = 50
but = Button(on_press = self.DrawAbscissa)
but.background_normal = 'abscissa.png'
self.add_widget(but)
but = Button( on_press = self.DrawCurve)
but.background_normal ='curve.png'
self.add_widget(but)
def DrawAbscissa(self, obj):
size = self.parent.size
p=1
pass
def DrawCurve(self, obj):
pass
class WorkShop(BoxLayout):
def __init__(self, **kwargs):
super(WorkShop, self).__init__(**kwargs)
self.orientation = "vertical"
self.paint = Paint()
self.tools = ButtonTools()
self.add_widget(self.paint)
self.add_widget(self.tools)
class MyPaintApp(App):
def build(self):
return WorkShop()
if __name__ == '__main__':
MyPaintApp().run()

You can obtain the screen size using the following:
from kivy.core.window import Window
...
print("Window.size={}".format(Window.size))
print("Window.height={}".format(Window.height))
print("Window.width={}".format(Window.width))

Related

Kivy: Create a list of coloured labels using build() method

I want to create a list of coloured labels. The thing is that I could do it with the kv file, but I need to do it through the build() method. So I tried replicate what I have done, but it does not work. And I can't understand why.
This is what I've coded
from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
class RL(RelativeLayout): # Creates the background colour for each label
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Color(.7, 0, .5, 1)
Rectangle(size_hint=self.size)
class MainMenu(BoxLayout):
N_LBLS = 8
labels_text = []
RL_list = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
button = Button(text='do something')
button.bind(on_release=self.change_text)
box = BoxLayout(orientation='vertical', padding= 10, spacing = 15)
for i in range(0, self.N_LBLS):
self.RL_list.append(RL())
self.labels_text.append(Label(text=f'{i}º label', size_hint=self.size))
self.RL_list[i].add_widget(self.labels_text[i])
box.add_widget(self.RL_list[i])
self.add_widget(button)
self.add_widget(box)
def change_text(self, instance):
for lbl in self.labels_text:
if lbl.text[0] == '5':
lbl.text = 'Text changed'
class MainApp(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
MainApp().run()
It's supposed to make a button to the left, and a list of 8 coloured labels to the right.
The problem is that you are setting size_hint=self.size in each Label. The self.size is the size of the MainMenu, which is [100,100] when that code is executed. Note that size_hint is a multiplier that is applied to the parents size to calculate the widgets size. So a size_hint of [100,100] makes each Label 100 times bigger than the MainMenu. So your code is working, but the Labels are so large that the text is off the screen. Start by just removing size_hint=self.size.
And, to set a background color on a Label, you can just use the canvas of that Label, rather than some container. Here is a version of your code that does that:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
class ColorLabel(Label):
pass
Builder.load_string('''
<ColorLabel>:
bg_color: [.7, 0, .5, 1]
canvas.before:
Color:
rgba: self.bg_color
Rectangle:
pos: self.pos
size: self.size
''')
class MainMenu(BoxLayout):
N_LBLS = 8
labels_text = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
button = Button(text='do something')
button.bind(on_release=self.change_text)
box = BoxLayout(orientation='vertical', padding=10, spacing=15)
for i in range(0, self.N_LBLS):
self.labels_text.append(ColorLabel(text=f'{i}º label'))
box.add_widget(self.labels_text[i])
self.add_widget(button)
self.add_widget(box)
def change_text(self, instance):
for lbl in self.labels_text:
if lbl.text[0] == '5':
lbl.text = 'Text changed'
lbl.bg_color = [0, 1, 0, 1]
class MainApp(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
MainApp().run()

How do I control initial Size and positioning of labels and buttons in a splitter in Kivy?

It's me again, trying to understand Kivy concepts.
I have a widget with a base class of RelativeLayout containing a chessboard image displaying in a splitter. I want to display a label, and 2 buttons horizontally below the chessboard spaced a small distance away from the chessboard and still have everything resizable with splitter. I've tried numerous ways to no avail. What I currently have is this:
What I want is this: (How do I achieve it?)
Here is the code:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.splitter import Splitter
from kivy.uix.image import Image
kivy.require('2.0.0')
class ChessBoardWidget(RelativeLayout): # FloatLayout
def __init__(self, **kwargs):
super(ChessBoardWidget, self).__init__(**kwargs)
repertoire_boxlayout = BoxLayout(orientation='horizontal')
repertoire_boxlayout.add_widget(Label(text='Repertoire for:'))
repertoire_boxlayout.add_widget(Button(text='White'))
repertoire_boxlayout.add_widget(Button(text='Black'))
chessboard_gui_boxlayout = BoxLayout(orientation='vertical')
chessboard_gui_boxlayout.add_widget(
Image(source="./data/images/chess-pieces/DarkerGreenGreyChessBoard.png", pos=self.pos,
size_hint=(1, 1), keep_ratio=True, allow_stretch=True))
chessboard_gui_boxlayout.add_widget(repertoire_boxlayout)
self.add_widget(chessboard_gui_boxlayout)
class SplitterGui(BoxLayout):
def __init__(self, **kwargs):
super(SplitterGui, self).__init__(**kwargs)
self.orientation = 'horizontal'
# Splitter 1
split1_boxlayout = BoxLayout(orientation='vertical')
split1 = Splitter(sizable_from='bottom', min_size=74, max_size=1100)
chessboard_widget = ChessBoardWidget()
split1.add_widget(chessboard_widget)
split1_boxlayout.add_widget(split1)
s3_button = Button(text='s3', size_hint=(1, 1))
split1_boxlayout.add_widget(s3_button)
self.add_widget(split1_boxlayout)
# Splitter 2
split2 = Splitter(sizable_from='left', min_size=74, max_size=1800)
s2_button = Button(text='s2', size_hint=(.1, 1))
split2.add_widget(s2_button)
self.add_widget(split2)
class ChessBoxApp(App):
def build(self):
return SplitterGui() # root
if __name__ == '__main__':
ChessBoxApp().run()
In a BoxLayout (see the documentation), you can use size_hint and size (or height, width) to adjust sizes. So, you can set the height of your Buttons, and let the Image use the remaining height of the BoxLayout:
class ChessBoardWidget(RelativeLayout):
def __init__(self, **kwargs):
super(ChessBoardWidget, self).__init__(**kwargs)
repertoire_boxlayout = BoxLayout(orientation='horizontal', size_hint=(1, None), height=30) # set height of Buttons
repertoire_boxlayout.add_widget(Label(text='Repertoire for:'))
repertoire_boxlayout.add_widget(Button(text='White'))
repertoire_boxlayout.add_widget(Button(text='Black'))
chessboard_gui_boxlayout = BoxLayout(orientation='vertical')
chessboard_gui_boxlayout.add_widget(
Image(source="./data/images/chess-pieces/DarkerGreenGreyChessBoard.png", pos=self.pos, keep_ratio=True, allow_stretch=True)) # default size_hint of (1,1) claims all of remaining height
chessboard_gui_boxlayout.add_widget(repertoire_boxlayout)
self.add_widget(chessboard_gui_boxlayout)

How to change Image created in a for loop with on_press in kivy

I have created a group of images in a for loop in kivy and those images have the attribute of 'buttonbehavior' making them clickable. I am trying to change the image at a particular index to another image when clicked but it is not working.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager):
def __init__(self, **kwargs):
super(ScreenManagement, self).__init__(**kwargs)
class Screen2(Screen):
def __init__(self, **kwargs):
super(Screen2, self).__init__(**kwargs)
Pass
class ImageButton(ButtonBehavior,Image):
pass
class Screen1(Screen, ButtonBehavior,Image):
def __init__(self, **kwargs):
super(Screen1,self).__init__(**kwargs)
for i in range(6):
self.btn= ImageButton(source='put_any.png', size_hint=(.3, .2),
pos_hint={'center_x': .5, 'center_y': .32})
self.add_widget(self.btn)
If i==0:
self.btn.bind(on_press=self.change_image)
def change_image(self,*args)
self.source='put_any.png'
class Application(App):
def build(self):
sm = ScreenManagement(transition=FadeTransition())
sm.add_widget(Screen1(name='screen1'))
sm.add_widget(Screen2(name='screen2'))
return sm
if __name__ == "__main__":
Application().run()
I want the image at index 0 in the for loop to change to another image when it is pressed, but it is not working please what am I doing wrong.
If you refer self.source it means Screen.source that wont affect anything.
Change the func like this:
def change_image(self, btn)
btn.source='put_any.png'

How can I resize a picture in kivy?

I'm using kivy and I am trying to make a program to help me remember the super saiyans transformations. I wanted the buttons to be pictures instead of words. So here is the code I used to make the button a picture:
self.Goku = Button(background_normal = '106-1060675_goku-base-form-png-clipart (1).png')
self.Goku.bind(on_press = self.SonGoku)
self.add_widget(self.Goku)
When I runned the code to see what it looks like, I saw that one of the picture was to big and one to small. So I tried to resize the picture by adding size = ("10, 10") but it didn't work. I tried the same thing with size_hint, but it had the same result. Nothing moved. I looked at some documentations about the button and adding pictures to kivy but it didn't help much. Here's the entire code:
import kivy
from kivy.app import App
from kivy.graphics import *
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
class main(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 4
self.Goku = Button(background_normal = '106-1060675_goku-base-form-png-clipart (1).png', size_hint = (1, 0.5))
self.Goku.bind(on_press = self.SonGoku)
self.add_widget(self.Goku)
self.Vegeta = Button(background_normal = 'vegeta-png-clip-art.png', size_hint = (1, 1))
self.Vegeta.bind(on_press = self.PrinceVegeta)
self.add_widget(self.Vegeta)
def SonGoku(self, instance):
self.cols = 1
self.remove_widget(self.Goku)
self.remove_widget(self.Vegeta)
self.NormalGoku = Button(text = "Base form")
self.add_widget(self.NormalGoku)
self.SSJGoku = Button(text = "Super saiyan")
self.add_widget(self.SSJGoku)
self.SSJ2Goku = Button(text = "Super saiyan 2")
self.add_widget(self.SSJ2Goku)
def PrinceVegeta(self, instance):
self.cols = 1
self.remove_widget(self.Goku)
self.remove_widget(self.Vegeta)
self.NormalVegeta = Button(text = "Base form")
self.add_widget(self.NormalVegeta)
self.SSJVegeta = Button(text = "Super saiyan")
self.add_widget(self.SSJVegeta)
self.SSJ2Vegeta = Button(text = "Super saiyan 2")
self.add_widget(self.SSJ2Vegeta)
class Saiyan(App):
def build(self):
return main()
if __name__ == "__main__":
Saiyan().run()
Help would be appreciated. Feel free to ask any question. Thanks in advance.
One way of doing it would be to draw the image on the buttons canvas. the attributes "allow_stretch" and "keep_ratio" are used to fill the entire button size.
from kivy.uix.image import Image
Then:
self.Goku = Button(size_hint=(None, None), size=(120,120))
with self.Goku.canvas:
Image(source='vegeta-png-clip-art.png', size=self.Goku.size, pos=self.Goku.pos, allow_stretch=True, keep_ratio=False)
self.add_widget(self.Goku)
In case you are not setting the size explicitly for the button you need to bind the size attribute to a method in order to resize the image.
example:
class main(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 4
self.Goku = Button()
with self.Goku.canvas:
self.Goku_img = Image(source='vegeta-png-clip-art.png', size=self.Goku.size, pos=self.Goku.pos, allow_stretch=True, keep_ratio=False)
self.Goku.bind(size=self.adjust_size)
self.add_widget(self.Goku)
...
def adjust_size(self, instance, value):
self.Goku_img.size = value
I hope this is a suitable approach for you.

Kivy stop Video and show photo

I'm working on a kivy framework (v1.10). I'm trying to create a simple photo booth software that runs a video loop and stops the video when someone clicks on the screen. After that the camera takes a picture and the program displays it on the monitor together with two buttons yes or no. they will allow you to repeat the photo. I am developing this application for Raspberry PI. My question is how do I stop the video and make something else.
ok, so if I want to add another movie between the first movie and the buttons, do I have to add a new screen or maybe change the video source in this funtion self.bind (on_touch_down = self.on_stop)? I would like to add a video with a countdown time and let him release the camera by taking pictures. then display this photo once with the buttons: repeat and continue.
from kivy.app import App
from kivy.logger import Logger
from kivy.uix.videoplayer import Video
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
class Player(Video):
def __init__(self, **kwargs):
super(Player, self).__init__(**kwargs)
self.source = './START.mp4'
self.state='play'
self.options={'eos': 'loop'}
self.bind(on_touch_down = self.on_stop)
self.get_set_current_video_state = self.get_set_current_video_state()
def check(self):
Logger.info("film position:" + str(self.position))
def on_stop(self, *args):
print ('I have been clicked')
Player.state='stop'
#App.get_running_app().stop()
#self.get_set_current_video_state = ('pause')
return MyWindowApp().run()
class VideoPlayerApp(App):
def build(self):
return Player()
class MyWindowApp(App):
def __init__(self):
super(MyWindowApp, self).__init__()
self.btn = Button(text='Push Me!')
self.lbl = Label(text='Read Me!')
Instead of trying to use two Apps, just use two Screens. Here is a modification of your code using Screens:
from kivy.app import App
from kivy.logger import Logger
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.video import Video
from kivy.uix.label import Label
from kivy.uix.button import Button
class Player(Video):
def __init__(self, **kwargs):
super(Player, self).__init__(**kwargs)
self.source = './START.mp4'
self.state='play'
self.options={'eos': 'loop'}
self.bind(on_touch_down = self.on_stop)
def check(self):
Logger.info("film position:" + str(self.position))
def on_stop(self, *args):
print ('I have been clicked')
self.state='stop' # stop the video
sm.current = 'WindowApp' # switch to the other Screen
class MyWindowApp(Screen):
def __init__(self, **kwargs):
super(MyWindowApp, self).__init__(**kwargs)
self.btn = Button(text='Push Me!', pos_hint={'center_x': 0.5, 'center_y': 0.75}, size_hint=(0.2, 0.2))
self.lbl = Label(text='Read Me!', pos_hint={'center_x': 0.5, 'center_y': 0.25})
self.add_widget(self.btn)
self.add_widget(self.lbl)
sm = ScreenManager()
screen1 = Screen(name='video')
screen1.add_widget(Player())
sm.add_widget(screen1)
screen2 = MyWindowApp(name='WindowApp')
sm.add_widget(screen2)
class VideoPlayerApp(App):
def build(self):
return sm
VideoPlayerApp().run()
I corrected your import to from kivy.uix.video import Video

Categories