Kivy scatter on desktop with size=Window.size - kivy

I am developing an application for Linux desktop using Kivy framework. I am trying to set Scatter size the same as the size of the window.
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.scatter import Scatter
from kivy.graphics import Color, Rectangle
class MyScatter(Scatter):
def __init__(self, *args, **kwargs):
super(MyScatter, self).__init__(*args, **kwargs)
self.size_hint=(None, None)
self.size=(Window.width, Window.height)
with self.canvas:
Color(1, 0, 0)
Rectangle(pos=self.pos, size=(100, 200))
class ScatterApp(App):
def build(self):
return MyScatter()
ScatterApp().run()
When I run the code the scatter immediately reflects my mouse motion and moves rectangle.
When I maximize window it reacts agter I press the button only but also scales and rotates itself as if I used two fingers.
When I use a fixed size (i.e. self.size=(100, 200)) the behavior is identical in both cases and scatter moves after I press the button.
Passing the size as a parameter doesn't change anything.
I don't use kv language.
"Mouse" is touchpad.

Not sure about your mouse problems, but the MyScatter widget will fill the window by default. Your code doesn't reflect the correct size. Try this version:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.scatter import Scatter
from kivy.graphics import Color, Rectangle
from kivy.clock import Clock
class MyScatter(Scatter):
def __init__(self, *args, **kwargs):
super(MyScatter, self).__init__(*args, **kwargs)
Clock.schedule_once(self.show_size, 0.1)
def show_size(self, *args):
with self.canvas:
Color(1, 0, 0)
Rectangle(pos=self.pos, size=self.size)
class ScatterApp(App):
def build(self):
return MyScatter()
if __name__=="__main__":
ScatterApp().run()

Related

Moving a tiled surface in a kivy widget

I'm building a simple game in kivy where I move a player on a map and the map moves consequently to keep the player at the center of the screen.
But, the problem is that the map is composed by individual tiles with individual properties. How can I move all the elements at the same time??
I'm in trouble with that and I can't reach a solution.
This is the portion of code:
'''
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.uix.behaviors import DragBehavior
class MainGame(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Rectangle(source= "stone_tile.png",pos=(220,-300), size=(1000,1000))
Rectangle(source= "grass_tile.png", pos=(0,-400), size=(1000,1000))
class FarIslands(App):
def build(self):
return MainGame()
if __name__ == '__main__':
FarIslands().run()
'''
I need to move the two rectangles at the same time. In the final version there will be hundreds of elements to create a game map.
Maybe, is there a better way, instead using Widget canvas?
Because I need to add other functions to the tiles...

how to put a kivy button in the middle? X coordinates not working

I've learnt kivy halfway and I've stopped using it for some time I've forgotten a little so anyway I've made a little project so-called a "Tally Counter" and I've wanted to add a button in the middle and little downwards - I've done it and suddenly the x coordinates were not working - heres the output -
the code -
from kivy.core import window
from kivy.uix.label import Label
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.lang import builder
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.core.window import Window
import os, sys
from kivy.resources import resource_add_path, resource_find
builder.Builder.load_file("tally.kv")
Window.size = (450,600)
class Tally(Widget):
pass
class Count(App):
def build(self):
return Tally()
if __name__ == "__main__":
Count().run()
And last but not least the KV file
<Tally>
BoxLayout:
orientartion:"vertical"
size: root.width,root.height
Button:
text:"Count"
size_hint: (None, None)
height: 70
width: 400
pos_hint: {"center_x":.5,"center_y":.3}
Yet I feel the guilt for forgetting kivy, I'm kind of stupid for asking these questions, I'll ask better questions from now on. I'll try my best.
From the BoxLayout Documentation:
Position hints are partially working, depending on the orientation:
If the orientation is vertical: x, right and center_x will be used.
If the orientation is horizontal: y, top and center_y will be used.
However, you have a typo in your kv file. Try changing:
orientartion:"vertical"
to:
orientation:"vertical"
Refer this three button hope you find your solution from it
# import modules
import kivy
# 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
# This layout allows you to set relative coordinates for children.
from kivy.uix.relativelayout import RelativeLayout
# To change the kivy default settings
# we use this module config
from kivy.config import Config
# 0 being off 1 being on as in true / false
# you can use 0 or 1 && True or False
Config.set('graphics', 'resizable', True)
# creating the App class
class Pos_Size_App(App):
def build(self):
# A Relative Layout with a size of (300, 300) is created
rl = RelativeLayout(size =(300, 300))
# creating button
# size of button is 20 % by height and width of layout
# position is 'center_x':.7, 'center_y':.5
b1 = Button(size_hint =(.2, .2),
pos_hint ={'center_x':.7, 'center_y':.5},
text ="pos_hint")
# creating button
# size of button is 20 % by height and 50 % width of layout
b2 = Button(size_hint =(.5, .2),
text ="size_hint")
# creating button
# size of button is 20 % by height and width of layout
# position is 200, 200 from bottom left
b3 = Button( size_hint =(.2, .2),
pos =(200, 200),
text ="pos")
# adding button to widget
rl.add_widget(b1)
rl.add_widget(b2)
rl.add_widget(b3)
# returning widget
return rl
# run the App
if __name__ == "__main__":
Pos_Size_App().run()

Kivy save widget without being drawn results in blank Fbo

I am trying to render some labels over the top of a canvas texture i have previously saved. When i render the widget to an Fbo without drawing it to the screen first i get a blank output. I believe this is replicated in the snippet below, save_file called from on_start writes the file incorrectly, but if the same logic is called from the button press it saves a file of the widget rendered correctly.
Is there a way to render the widget to the Fbo without rendering to the canvas?
Is there an update or draw command i need to call on the widget?
(notshown.texture seems to be None, and adding notshown.canvas.draw() seems to crash with no stacktrace or reason?)
from kivy.app import App
from kivy.factory import Factory
class TestApp(App):
def build(self, *kwargs):
layout = Factory.BoxLayout()
test1 = Factory.Button(text='test1', size_hint=(None,None), size=(200,200))
test1.bind(on_press=self.save_file1)
layout.add_widget(test1)
test2 = Factory.Button(text='test2', size_hint=(None,None), size=(200,200))
test2.bind(on_press=self.save_file2)
layout.add_widget(test2)
return layout
def save_file1(self, widget, value=False):
fbo = Factory.Fbo(size=widget.size, with_stencilbuffer=True)
fbo.add(widget.canvas)
fbo.draw()
fbo.texture.save('C:/Temp/test1.png', flipped=True)
def save_file2(self, widget, value=False):
notshown = Factory.Button(text='notshown', size_hint=(None,None), size=(200,200))
fbo = Factory.Fbo(size=notshown.size, with_stencilbuffer=True)
fbo.add(notshown.canvas)
fbo.draw()
fbo.texture.save('C:/Temp/test2.png', flipped=True)
TestApp().run()
Per John Anderson's input, the issue was not giving the application enough time to render a frame before attempting to save the texture.
Using Clock.schedule_once to await the next frame means that export_to_png or all other uses of the texture of the widget succeed with little to no fuss.
img = Factory.FinalImage(imagedata, size_hint=(None,None), size=imagedata.size)
Clock.schedule_once( lambda x: img.export_to_png(filename=imagename) )

Kivy:Can't put 'BorderImage' at the specified position

(1) By using the following kv file version was able to place BorderImagewidget at the specified position..
<Screen>:
ProgressBar:
max: 100
pos_hint: {'top':0.86, 'x':0.01}
size_hint_x: 0.49
size_hint_y: 0.1
canvas:
BorderImage:
border: (10, 10, 10, 10)
pos: self.x, self.center_y
size: self.width, 8
source: '0.png'
(2) But, the following Pure Python code that should realize the same function as (1) doesn't work properly.BorderImagewidget is placed at the bottom of the screen.
pos_hint={'top':0.86,'x':0.01} doesn't work.
I think that how to specify pos=(bar.x, bar.center_y) is not good because bar.center_y value is different from the code of (1).
class BarWidget(FloatLayout):
def __init__(self, **kwargs):
super(BarWidget, self).__init__(**kwargs)
self.build()
def build(self):
bar = ProgressBar(pos_hint={'top':0.86,'x':0.01}, max=100, size_hint_x=0.49, size_hint_y=0.1)
with bar.canvas:
BorderImage(border=(10, 10, 10, 10), pos=(bar.x, bar.center_y), size=(self.width/2, 8), source='0.png')
self.add_widget(bar)
How should I modify bar.center_y?
(1):screen shot
(2):screen shot
In the kv language, when you set an attribute like size: self.size, this attribute is automatically updated whenever the 'self' widget changes size of shape. When things are loading up in a screen/layout, they start with funky positions and sizes then move to be correct. Since things automatically update upon changing sizes/positions if you work in kv, it works as you expect.
In python, you have to explicitly bind some function to update the canvas if the size or position of the widget it's inheriting its size and pos from changes. You can do that by using the bind function (available in most/all kivy widgets). Using bind, you can say bind(<attribute>=<function>) which means anytime the widget's <attribute>, aka size or pos, is changed, it calls the <function>
I didn't test this exactly with your code since not all of it is posted, but this is what I do for my projects. Let me know how it works. If it doesn't work, edit your answer to be a snippet of code that I can copy/paste to work with and I'll update my answer.
class BarWidget(FloatLayout):
def __init__(self, **kwargs):
super(BarWidget, self).__init__(**kwargs)
self.build()
def build(self):
# Make it so you can reference the bar and border image later
self.bar = ProgressBar(pos_hint={'top':0.86,'x':0.01}, max=100, size_hint_x=0.49, size_hint_y=0.1)
with self.bar.canvas:
# Make it so you can reference the border image
self.border_image = BorderImage(border=(10, 10, 10, 10), pos=(bar.x, bar.center_y), size=(self.width, 8), source='0.png')
self.add_widget(self.bar)
# Make it so whenever the widget's pos or size changes, we update the border image
self.bar.bind(pos=self.update_border_image, size=self.update_border_image)
# make a function to update border image
def update_border_image(self, *args):
self.border_image.size = (self.width, 8) # Should this 8 be 0.8 by the way?
self.border_image.pos = (self.bar.x, self.bar.center_y)

how do you change the canvas or window size of an app using kivy

How do you change the size of a window using Kivy. I've been searching around and am able to change pretty much everything except the size of the window that things go into.
From the sample pictures file:
main.py
#!/usr/bin/kivy
'''
Pictures demo
=============
This is a basic picture viewer, using the scatter widget.
'''
import kivy
kivy.require('1.0.6')
from glob import glob
from random import randint
from os.path import join, dirname
from kivy.app import App
from kivy.logger import Logger
from kivy.uix.scatter import Scatter
from kivy.properties import StringProperty
# FIXME this shouldn't be necessary
from kivy.core.window import Window
class Picture(Scatter):
'''Picture is the class that will show the image with a white border and a
shadow. They are nothing here because almost everything is inside the
picture.kv. Check the rule named <Picture> inside the file, and you'll see
how the Picture() is really constructed and used.
The source property will be the filename to show.
'''
source = StringProperty(None)
class PicturesApp(App):
def build(self):
# the root is created in pictures.kv
root = self.root
# get any files into images directory
curdir = dirname(__file__)
for filename in glob(join(curdir, 'images', '*')):
try:
# load the image
picture = Picture(source=filename, rotation=randint(-30,30))
# add to the main field
root.add_widget(picture)
except Exception as e:
Logger.exception('Pictures: Unable to load <%s>' % filename)
def on_pause(self):
return True
if __name__ == '__main__':
PicturesApp().run()
pictures.kv
#:kivy 1.0
#:import kivy kivy
#:import win kivy.core.window
FloatLayout:
canvas:
Color:
rgb: 1, 1, 1
Rectangle:
source: 'data/images/background.jpg'
size: self.size
BoxLayout:
padding: 10
spacing: 10
size_hint: 1, None
pos_hint: {'top': 1}
height: 44
Image:
size_hint: None, None
size: 24, 24
source: 'data/logo/kivy-icon-24.png'
Label:
height: 24
text_size: self.width, None
color: (1, 1, 1, .8)
text: 'Kivy %s - Pictures' % kivy.__version__
<Picture>:
# each time a picture is created, the image can delay the loading
# as soon as the image is loaded, ensure that the center is changed
# to the center of the screen.
on_size: self.center = win.Window.center
size: image.size
size_hint: None, None
Image:
id: image
source: root.source
# create initial image to be 400 pixels width
size: 400, 400 / self.image_ratio
# add shadow background
canvas.before:
Color:
rgba: 1,1,1,1
BorderImage:
source: 'shadow32.png'
border: (36,36,36,36)
size:(self.width+72, self.height+72)
pos: (-36,-36)
I'd expect to be able to put a size tag in the FloatLayout or the Canvas in order to resize a window, but it doesn't seem to work.
How do I determine how large the canvas (or containing window -- perhaps i'm searching on the wrong terms) is going to be before the app is run?
-edit-
I've found that adding the following in the includes section of the .py works:
from kivy.config import Config
Config.set('graphics', 'width', '640')
Config.set('graphics', 'height', '1163')
Is there a way of doing this using just the .kv file?
No, the size cannot be set in kv. You can set it using Config as you do above, or you can change the window size later by setting the size on the Window object:
from kivy.core.window import Window
Window.size = (640, 1163)
To manage window config you can use the import from kivy.config import Config on top of source file.
from kivy.config import Config
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'width', '640')
Config.set('graphics', 'height', '480')
Don't use
from kivy.core.window import Window
which makes these not work
Config.set('graphics', 'width', '200')
Config.set('graphics', 'height', '400')

Resources