Canvas instruction invisible in Kivy - python

I want to create a TextInput and modify its canvas to have a white RoundedRectangle in the background. I made the background_color transparent, but I don't see that rectangle behind the TextInput.
I've tried to instead draw on canvas.before and canvas.after. The both seemed to result in one thing: the expected Rectangle covered the cursor and the text. And while this would be expected for canvas.after, I thought canvas.before wouldn't cover anything? How to make a background through canvas instructions for a TextInput?
Here is the code:
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
Builder.load_string('''
<Test>:
canvas: # no rectangle this way
Color:
rgba: 1, 1, 1, 1
RoundedRectangle:
pos: self.pos
size: self.size
background_color: 1, 1, 1, 0
''')
class Test(TextInput):
pass
runTouchApp(Test())

Simple! You set Color in canvas which is set to (some?) other components too (probably via OpenGL directly). Therefore you have to "unset" it - or better said set it to the default Color, which you have already access to:
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.textinput import TextInput
Builder.load_string('''
<Test>:
canvas.before:
Color:
rgba: 1, 0, 0, .5
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: root.foreground_color
background_color: 1,1,1,0
''')
class Test(TextInput): pass
runTouchApp(Test())
You already have colors set in the default TextInput, so you can access them with root.
Also for more features play with background_* properties. Making an image with rounded corners will be probably better for a performance if you need it(mobiles) and you can switch between them just with setting those properties, because TextInput handles switchess automatically.

Related

kivy canvas doesn't shows

I'm trying to have a white background in window and I'm using Kivy modules and Kv language but the background still black.
main.py :
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
class MyUI(FloatLayout):
pass
class MyApp(App):
def build(self):
return MyUI()
def main():
MyApp().run()
if __name__ == '__main__':
main()
my.kv :
<MyUI>:
canvas:
Color:
rgba: 1,1,1,1
Color instructions are applied to shapes that you draw, e.g. if you write the following:
<MyUI>:
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
now you will see a white Rectangle filling the screen (as that's what its pos and size are set to do).

Image in Kivy Scrollview isn't scorllable

I'm trying to make a notebook app using kivy, where the user will be able to scroll the sheet up and down and write on it. I tried using ScrollView, but it doesn't seem to work - I wanted the sheet image to be stretched to the width of the window and as the height is greater than the width - have the image scrollable up and down. What happened instead was this:
I would really appreciate anyone looking into the code and trying the figure out what I was doing wrong :)
python code:
import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from PIL import Image as Image1
from kivy.uix.image import Image
GUI = Builder.load_file('style.kv')
Window.size = (1000, 200)
img_size = Image1.open("images/notebook.png").size
class NotebookScreen(GridLayout):
def __init__(self, **kwargs):
self.rows = 1
super(NotebookScreen, self).__init__(**kwargs)
def get_size_for_notebook(self, **kwargs):
global img_size
width, height = Window.size
return width, (img_size[0] * height / width)
class MainApp(App):
def build(self):
return NotebookScreen()
if __name__ == "__main__":
MainApp().run()
kv file:
<NotebookScreen>
FloatLayout:
rows: 2
GridLayout:
size_hint: 1, .05
pos_hint: {"top": 1, "left": 1}
id: tool_bar
cols: 1
canvas:
Color:
rgba: 0, 0, 1, 1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
id: notebook_grid
size_hint: 1, .95
pos_hint: {"top": .95, "left": 0}
cols: 1
ScrollView:
Image:
id: notebook_image
source: 'images/notebook.png'
allow_stretch: True
keep_ratio: True
pos: self.pos
size: root.get_size_for_notebook()
The problem is that you are setting the size of the Image in your kv, but it is having no effect, since size_hint over-rules size. The default size_hint is (1,1), so no scrolling is done (the Image is constrained to fit in the ScrollView). To allow your size to take effect, just add:
size_hint: None, None
to the Image in your kv.

Advanced open and close animation for a button

The animation I currently have for opening and closing a button, is simply a sub button comes out from the main button and expands using size_hint. This animation simply enlarges the sublayout. I would like to 'unveil' the sublayout instead. What I mean by that, is to not mess with size_hint of the sub and instead of expanding itself, I want it to 'unveil' itself which makes for a much cleaner animation. Heres a link of a button animation that uses the same effect. https://codemyui.com/button-to-a-list-animation/.
In the linked animation, the bottom border goes down and reveals the list underneath, the same effect I want.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import *
from kivy.animation import Animation
from kivy.lang.builder import Builder
from kivy.uix.behaviors import *
from kivy.properties import *
Builder.load_string("""
<Root>
Button1:
size_hint: 0.2,0.1
pos_hint: {'top':0.9,'center_x':0.5}
canvas:
Color:
rgba: [0.4,0.4,0.4,1]
Rectangle
size: self.size
pos: self.pos
SubLayout:
pos_hint: {'top':1,'center_x':0.5}
canvas:
Color:
rgba: [0.7,0.7,0.7,1]
Rectangle
size: self.size
pos: self.pos
Color:
rgba: [1,1,1,1]
Ellipse:
pos: self.pos
size: self.size
""")
class Root(FloatLayout):
pass
class Button1(ToggleButtonBehavior, FloatLayout):
def __init__(self,**kwargs):
super(Button1,self).__init__(**kwargs)
def on_state(self, *args):
if self.state == 'down':
anim = Animation(pos_hint={'top':0},d=0.2)
anim += Animation(size_hint=(2,2),d=0.2) #: expanding sublayout, how do I unveil instead?
anim.start(self.children[0])
else:
anim = Animation(size_hint=(1,1),d=0.2)
anim += Animation(pos_hint={'top':1},d=0.2)
anim.start(self.children[0])
class SubLayout(FloatLayout):
pass
class TestApp(App):
def build(self):
return Root()
if __name__ == '__main__':
TestApp().run()
As you can see, SubLayout expands and you can see the ellipse inside expanding with the button. What I would like is for the borders to move away, revealing whats underneath them while leaving the ellipse's size the same, which is the 'unveiling' effect. Any ideas on how to do this would be appreciated. Maybe something to do with an Fbo?

Loading Image in Kivy

I want an image to be displayed in the center of the layout. I could not figure it out. Is there any way to display the image on the center of the layout and be there till the animation is stopped?
Here is my code.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.animation import Animation
from kivy.properties import NumericProperty
Builder.load_string('''
<Loading>:
canvas:
Rotate:
angle: root.angle
origin: self.center
Color:
rgb: .0, 0, -.1
Ellipse:
size: min(self.size), min(self.size)
pos: 0.5*self.size[0] - 0.5*min(self.size), 0.5*self.size[1] - 0.5*min(self.size)
Color:
rgb: .5, 0, 1
Ellipse:
size: 30, 30
pos: 0.5*root.size[0]+25, 0.8*root.size[1]-25
''')
class Loading(FloatLayout):
angle = NumericProperty(0)
def __init__(self, **kwargs):
super(Loading, self).__init__(**kwargs)
anim = Animation(angle = 1009, duration=2.5)
anim += Animation(angle = 1900, duration=2.5)
anim.repeat = True
anim.start(self)
def on_angle(self, item, angle):
if angle == 360:
item.angle = 0
class TestApp(App):
def build(self):
return Loading()
TestApp().run()
I don't think your canvas should be "loose" like that. Place it inside of a Widget, this will let you use Kivy's various layouts to arrange things. It will also let you insert an Image above the widget and without making the image spin around.
A second thing, use rgba so you can specify transparencies for the background. This example below works for me, just replace the Builder string with this:
"""<Loading>:
FloatLayout:
Image:
source: 'logo.png'
Widget:
canvas:
Rotate:
angle: root.angle
origin: self.center
Color:
rgba: 1, 1, 1, 0
Ellipse:
size: min(self.size), min(self.size)
pos: 0.5*self.size[0] - 0.5*min(self.size), 0.5*self.size[1] - 0.5*min(self.size)
Color:
rgba: .5, 0, 1, 1
Ellipse:
size: 30, 30
pos: 0.5*root.size[0]+25, 0.8*root.size[1]-25
Color:
rgba: 0.5, 0, 1"""
I also attached our Departments logo that I used for the example. I leave it to you to tweak sizes and add the appropriate resizing calls.logo

Kivy roundish menu

I'd like to write a roundish menu with Kivy. At the end it should somehow look like this:
I've stumbled upon some problems at the early beginnings. I already created the "mainmenu"-button (0.1). Now I wanted to create 2 new menu-circles 2.1 + 2.2. The problem is that the events for the two new buttons occur when I click on the main-button but nothing happens by clicking on the new buttons.
I really appreciate any help. :)
menu.py
import kivy
kivy.require('1.8.0') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.label import Label
from kivy.factory import Factory
from kivy.uix.scatter import Scatter
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
class menuApp(App):
print "test"
def secTouch(self):
print "sectouch"
class RootWidget(FloatLayout):
pass
class Menu (FloatLayout):
def newMenu(self):
dynamicMenu = Factory.First()
self.add_widget(dynamicMenu)
pass
class First(Scatter):
def firstTouch(self):
dynamicWidget = Factory.Second()
self.add_widget(dynamicWidget)
print "touch"
pass
if __name__ == '__main__':
menuApp().run()
menu.kv
#:kivy 1.8.0
#: set buttonSize 100, 100
#: set middleOfScreen 0,0
RootWidget:
<RootWidget>:
Menu
<Menu>
on_touch_down: root.newMenu()
<First>:
id: first
pos: root.size[0]/2-self.size[0]/2, root.size[1]/2-self.size[1]/2
size: 100, 100
size_hint: None, None
Widget:
on_touch_down: root.firstTouch()
id: me
size_hint: None, None
size: 100, 100
pos: root.size[0]/2-self.size[0]/2, root.size[1]/2-self.size[1]/2
canvas:
Color:
rgb: 1, 0, 0
Ellipse:
pos: me.pos
size: buttonSize
<Second#Scatter>:
pos: root.size[0]/2-self.size[0]/2+40, root.size[1]/2-self.size[1]/2+40
size: 100, 100
size_hint: None, None
on_touch_down: app.secTouch()
canvas:
Color:
rgb: 1, 0, 0
Ellipse:
pos: root.size[0]/2-self.size[0]/2+40, root.size[1]/2-self.size[1]/2+40
size: buttonSize
Every touch event is dispatched to the on_touch_down event handlers, not just touches in a given area (within the widget). Each time you touch the screen, regardless of where, the Menus on_touch_down is fired. You should use collide_point() to ensure the touch is within the given boundaries.
The Grabbing Touch Events section of the Kivy guide has an example of collide_point(), as well as some more info about touch events in general.
But, the basic idea:
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
# do stuff here
return True # 'handle' the event so it will not propagate

Categories