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

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()

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...

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)

Kivy scatter on desktop with size=Window.size

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()

rotate entire widget, not only its canvas

In this example, we can see a rotation of the canvas. But clicking the button's corners isn't registered. How can I rotate the entire button?
You can probably override its collide_point method to account for the rotation by transforming the touch coordinates.
If you use the widget system (e.g. putting the Button in a Scatter), the collision is taken care of for you.
Based on inclement's answer, I've created a button on a scatter layout, which has its hitbox set correctly.
from kivy.app import App
from kivy.lang import Builder
kv = '''
FloatLayout:
ScatterLayout:
size_hint: None, None
size: 200, 200
pos_hint: {'center_x': .5, 'center_y': .5}
rotation: 45
do_rotation: False
do_scale: False
do_translation: False
Button:
text: 'hello world'
'''
class RotationApp(App):
def build(self):
return Builder.load_string(kv)
RotationApp().run()
I used scatter layout instead of scatter, because it passes its size to children widgets. The do_x: False aren't needed in this example, because button intercepts touching events, but if I placed a label, it would move on touch.

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