Design where image is centered in the left half of the screen with scale and move possibility - kivy

I have this design of the UI:
The hardest part is to center the image in the left half of the screen, with scale and move possibility. I'm trying to do it with FloatLayout and somehow combine the behavior of Scatter and Image.
I have this code sofar:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.config import Config
from kivy.uix.button import Button
from kivy.uix.scatter import Scatter
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
class Tedegraph(App):
def build(self):
mainbox = FloatLayout()
mainbox.add_widget(Button(text="Prev",
font_size="17dp",
size_hint=(.15, .15),
pos_hint={"left":1,
"center_y":0.5},
))
#sp = Scatter(scale=1, do_scale = True, do_rotation = False, pos_hint={"center_x":0.5, "center_y":0.5})
self.img = Image(source='img.png')
#sp.add_widget(self.img)
mainbox.add_widget(self.img) # images will change during execution
self.text_label = Label(text="HELLO", size_hint=(1, None), pos_hint={"center_x":0.5, "center_y":0.5}) # text will change during execution
self.text_label.bind(
width=lambda *x: self.text_label.setter('text_size')(self.text_label, (self.text_label.width, None))) # only wrapping functionality
mainbox.add_widget(self.text_label)
mainbox.add_widget(Button(text="Next",
font_size="17dp",
size_hint=(.15, .15),
pos_hint={"right":1,
"center_y":0.5},
))
return mainbox
if __name__ == "__main__":
Tedegraph().run()
I hope it is possible with keeping the ratio of the image. Thanks for suggestions

You can set the size and position of the Image widget when you create it:
self.img = Image(source='img.png', size_hint=(0.33,0.33), pos_hint={'center_x':0.33, 'center_y':0.5}, allow_stretch=True, keep_ratio=True)
And similarly, with the Label:
self.text_label = Label(text="HELLO\nThis is a Test", halign='center', size_hint=(0.33, None), pos_hint={"center_x":0.67, "center_y":0.5})

Related

I want write codes for counting numbers app. My app can count the numbers of pages. I want to add button for cleaning screen

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class TestScreen(Screen):
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
layout = BoxLayout(orientation="vertical")
self.add_widget(layout)
layout.add_widget(Label(text=self.name, font_size="150sp"))
button = Button(text="Count",font_size='30sp')
layout.add_widget(button)
button.bind(on_press=self.add_screen)
def add_screen(self, *args):
n = len(self.manager.screen_names)
screen = TestScreen(name="{}".format(n))
self.manager.add_widget(screen)
self.manager.current = screen.name
# Create the screen manager
sm = ScreenManager()
sm.add_widget(TestScreen(name=''))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
I can't add button with a view to cleaning screen. I know this app not for counting. But i only need add button for cleaning numbers.

Since the rectangle is not a button, then how can I create a callback function to print('something') after clicking on that rectangle?

I have a rectangle in a canvas. Since the rectangle is not a button, then how can I create a callback function to print('something') after clicking on that rectangle?
In a button I can use on_release to call a function, but in rectangle how should I call a function after clicking on that rectangle?
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
#from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.animation import Animation
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.clock import Clock
Builder.load_string('''
<main>:
RelativeLayout :
size: root.width,root.height
canvas:
Color:
rgba:196/255, 195/255, 49/255,1
Rectangle:
size:470,root.height
''')
class main(Screen):
pass
class test(App):
def build(self):
sm = sm = ScreenManager()
sm.add_widget(main(name='main'))
Window.clearcolor=(55/255, 77/255, 33/255)
return sm
if __name__=='__main__':
test().run()

how can i get the image property that is in .kv file and change the size in .py file

my python code is:
from kivy.app import App
from kivy.lang import Builder
from kivymd.theming import ThemeManager
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
login=Builder.load_file('login.kv')
class Login(BoxLayout):
imge=ObjectProperty()
def press(self):
self.imge.size_hint=(.2,.2)
class Main(App):
def build(self):
theme_cls=ThemeManager()
return Login()
if __name__=="__main__":
Main().run()
my .kv file is:
<Login>:
imge:img
Image:
id:img
source:'22.png'
Button:
text:"click"
on_press:root.press()
i need to change the image size on click button,but the Objectproperty is not providing the image properties
So first of all you it is better using a boylayout when you want to use size_hints But it is your wish. In your case you have to give your image also size_hints
from kivy.app import App
from kivy.lang import Builder
from kivymd.theming import ThemeManager
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
login=Builder.load_file('login.kv')
class Login(BoxLayout):
image = ObjectProperty()
def press(self):
self.image.size_hint = (.2,.5)
class Main(App):
def build(self):
return Login()
if __name__=="__main__":
Main().run()
kv file:
<Login>:
image:img
Image:
size_hint:.5,1
id:img
source:'play.png'
Button:
text:"click"
size_hint:.2,.1
on_release:
root.press()
With FloatLayout. When using boxlayout the button will also increase the size. So floatlayout is better
from kivy.app import App
from kivy.lang import Builder
from kivymd.theming import ThemeManager
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
login=Builder.load_file('login.kv')
class Login(FloatLayout):
image = ObjectProperty()
def press(self):
self.image.size_hint = (.2,.5)
class Main(App):
def build(self):
return Login()
if __name__=="__main__":
Main().run()
and kv file
<Login>:
image:img
Image:
size_hint:.5,1
id:img
source:'play.png'
Button:
text:"click"
size_hint:.2,.1
on_release:
root.press()
So check the effect with box and floatlayouts. Ur problem was u did not give the image size_hints in kv file

Kivy property observer objects left behind after ModalView is dismissed

I display in a popup (ModalView) a dynamically changing value. I use a method in my main widget class to open/dismiss the popup, and bind a Kivy StringProperty to a Label in the popup. There is a problem - each time the popup is dismissed, something is left behind. Listing all observers of the StringProperty shows how with each cycle of open/dismiss the number of objects accumulates. See the example code below. When I run this on Raspberry Pi 2 under Raspbian Jessie (Pixel) with 128M allocated for VRAM, within about a minute the progam stops functioning correctly - popup starts to show a black screen. Am I doing something silly in my code?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.modalview import ModalView
from kivy.clock import Clock
from kivy.properties import StringProperty
from random import randint
Builder.load_string('''
#:kivy 1.9.2
<MainWidget>:
BoxLayout:
Button:
''')
class MainWidget(BoxLayout):
value_str = StringProperty()
def show_popup(self, even=True):
if even:
popup = ModalView(size_hint=(None, None), auto_dismiss=False, size=(700,480))
popup_label = Label(font_size = 200, text_size=self.size, halign='center', valign='center')
self.bind(value_str=popup_label.setter('text')) # value_str must be a Kivy StringProperty
popup.add_widget(popup_label)
self.value_str = str(randint(0,100))
popup.open()
else: # find all instances of ModalView and dismiss them
for widget in App.get_running_app().root_window.children:
if isinstance(widget, ModalView):
print "observers of value_str property:"
observers = self.get_property_observers('value_str')
for observer in observers:
print observer
widget.dismiss(force=True, animation=False)
Clock.schedule_once(lambda dt: self.show_popup(not even), 0.25)
class MyApp(App):
def build(self):
mw=MainWidget()
Clock.schedule_once(lambda dt: mw.show_popup(),0)
return mw
if __name__ == '__main__':
MyApp().run()
I found a workaround, inspired by this How to unbind a property automatically binded in Kivy language?
I now preserve the Label child by removing it from the ModalView and adding it to the MainWidget before ModalView is dismissed, then reversing this for the next popup. This way the property binding takes place only once so no new observers are created. The label can be made invisible by assigning an empty string to the bound property.
I think this may be a bug - ModalView dismiss() method should not leave behind observers, but cannot test with latest Kivy version (1.10.1.dev0).
Here's the code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.modalview import ModalView
from kivy.clock import Clock
from kivy.properties import StringProperty
from random import randint
Builder.load_string('''
#:kivy 1.9.2
<MyLabel>:
font_size: 100
text_size: self.size
halign: 'center'
valign: 'center'
<MainWidget>:
Button:
background_color: 0.5, 0.5, 1, 1
''')
class MyLabel(Label):
pass
class MainWidget(FloatLayout):
value_str = StringProperty()
popup_label = MyLabel()
def __init__(self, **kwargs):
super(MainWidget, self).__init__(**kwargs)
self.bind(value_str=self.popup_label.setter('text')) # value_str must be a Kivy StringProperty
self.add_widget(self.popup_label)
def show_popup(self, even=True):
if even:
popup = ModalView(size_hint=(None, None), auto_dismiss=False, size=(500,380))
self.remove_widget(self.popup_label)
popup.add_widget(self.popup_label)
self.value_str = str(randint(0,100))
popup.open()
else: # find all instances of ModalView and dismiss them
for widget in App.get_running_app().root_window.children:
if isinstance(widget, ModalView):
print "observers of value_str property:"
observers = self.get_property_observers('value_str')
for observer in observers:
print observer
widget.remove_widget(self.popup_label)
self.add_widget(self.popup_label)
self.value_str =''
widget.dismiss(force=True, animation=False)
Clock.schedule_once(lambda dt: self.show_popup(not even), 0.25)
class MyApp(App):
def build(self):
mw=MainWidget()
Clock.schedule_once(lambda dt: mw.show_popup(),0)
return mw
if __name__ == '__main__':
MyApp().run()

Implement android back button function in Kivy

Firstly, i have gone thru many examples, but could not figure out this, so asking here.
My app is to be run on android. Screen 1 have a button which will go to screen 2 on click.
All i need is code to move back to screen 1 on pressing back button on screen 2
My code:
#!/usr/bin/kivy
import kivy
kivy.require('1.7.2')
from random import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from random import random
from random import choice
from kivy.properties import StringProperty
import time
from kivy.clock import Clock
from functools import partial
from kivy.utils import platform
from kivy.core.window import Window
Builder.load_string("""
<MenuScreen>:
Button:
text: "move to next screen 2"
on_press: root.manager.current = 'game_mode'
<GameMode>:
Label:
text: "screen 2"
""")
class MenuScreen(Screen):
pass
class GameMode(Screen):
pass
sm = ScreenManager()
menu_screen = MenuScreen(name='menu')
sm.add_widget(menu_screen)
sm.add_widget(GameMode(name='game_mode'))
class TestApp(App):
def build(self):
self.bind(on_start=self.post_build_init)
return sm
def post_build_init(self,ev):
if platform == 'android':
import android
android.map_key(android.KEYCODE_BACK, 1001)
win = Window
win.bind(on_keyboard=self.key_handler)
def key_handler(self, window, keycode1, keycode2, text, modifiers):
if keycode1 == 27 or keycode1 == 1001:
sm.go_back()
return True
return False
if __name__ == '__main__':
TestApp().run()
Please help. I want solution based on screen manager. I would really appreciate if you can improve my code to provide solution.
Finally, figured it out
#!/usr/bin/kivy
import kivy
kivy.require('1.7.2')
from random import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from random import random
from random import choice
from kivy.properties import StringProperty
import time
from kivy.clock import Clock
from functools import partial
from kivy.core.window import Window
Builder.load_string("""
<MenuScreen>:
Button:
text: "move to next screen 2"
on_press: root.manager.current = 'game_mode'
<GameMode>:
Label:
text: "screen 2"
""")
class MenuScreen(Screen):
pass
class GameMode(Screen):
pass
sm = ScreenManager()
menu_screen = MenuScreen(name='menu')
sm.add_widget(menu_screen)
sm.add_widget(GameMode(name='game_mode'))
class TestApp(App):
def build(self):
self.bind(on_start=self.post_build_init)
return sm
def post_build_init(self,ev):
from kivy.base import EventLoop
EventLoop.window.bind(on_keyboard=self.hook_keyboard)
def hook_keyboard(self, window, key, *largs):
if key == 27:
print sm.current
if(sm.current=='menu'):
App.get_running_app().stop()
sm.current='menu'
return True
if __name__ == '__main__':
TestApp().run()
ScreenManager has a previous() method that should solve your problem:
Builder.load_string("""
<MenuScreen>:
Button:
text: "move to next screen 2"
on_press: root.manager.current = 'game_mode'
<GameMode>:
BoxLayout:
orientation: "vertical"
Button:
text: "go back"
on_press: root.manager.current = root.manager.previous()
Label:
text: "screen 2"
""")

Resources