Get size from widget init - python

How can I find out the size of the screen (widget in this case) from the init of the widget? Below there are two print functions: one returns a default widget size, the other returns the real size of the widget.
from kivy.app import App
from kivy.uix.image import Image
from kivy.config import Config
class MyScreen(Image):
def __init__(self, **kwargs):
super(MyScreen, self).__init__ (**kwargs)
self.size_hint = 1, 1
print self.size #returns 100, 100
def on_touch_down(self, *ignore):
print self.size #returns real size for the screen 1280 800
class TemplateApp(App):
Config.set('graphics', 'fullscreen', 'auto')
def build(self):
return MyScreen()
if __name__ == "__main__" :
TemplateApp().run()

Both return the correct result, the widget size is 100, 100 during the __init__. It is updated later by its parent, in this case the Window itself.
If you care about size changes, bind a function to its size that does whatever updating you need.

Related

Dynamic grid in Kivy with each grid element containing multiple widgets

This is my first post here, but I will try to be as detailled as I can.
So my application is in python, and involves a grid in kivy, where each element in the grid is supposed to contain 4 additional widgets and possibility for a fifth. The four additional widgets are supposed to be in a cross shape at the edges and the fifth in the middle.
Problem is, whenever I add a sub widget it lands in the bottom left corner on position 0,0 of the main window
So far so good. Right now I am just trying to get even one widget inside another widget to display correctly.
Heres what I attempted:
<GridCell#Label>
BoxLayout:
orientation:'horizontal'
Button:
text:'One'
size:10,10
size_hint:None,None
Building a .kv file for my app, where I would put a box layout inside of it and then a button.
Also I tried the following class configuration:
class GridCell(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.root = FloatLayout()
self.button = Button(text="test")
self.button.x = self.root.x
self.button.center_y = self.root.center_y
self.root.add_widget(self.button)
self.add_widget(self.root)
Also did not work.
I am adding the grid cells by just calling .add on the grid with a newly created widget for each iteration of a for loop.
All the child widgets are apparently created, but they all land in the bottom left corner!
This is the whole code of the gui right now:
import kivy
import World
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Color, Rectangle
kivy.require('1.10.0')
class GridCell(Label):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.root = FloatLayout()
self.button = Button(text="blargh")
self.button.x = self.root.x
self.button.center_y = self.root.center_y
self.root.add_widget(self.button)
self.add_widget(self.root)
def on_size(self, *args):
self.canvas.before.clear()
if self.id is "cliff":
with self.canvas.before:
Color(249 / 255, 6 / 255, 6 / 255, 0.3)
Rectangle(pos=self.pos, size=self.size)
if self.id is "goal":
with self.canvas.before:
Color(6 / 255, 6 / 255, 249 / 255, 0.3)
Rectangle(pos=self.pos, size=self.size)
if self.id is "start":
with self.canvas.before:
Color(11 / 255, 174 / 255, 6 / 255, 0.3)
Rectangle(pos=self.pos, size=self.size)
if self.id is "normal":
with self.canvas.before:
Color(119 / 255, 115 / 255, 115 / 255, 0.3)
Rectangle(pos=self.pos, size=self.size)
class GameGridApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.grid = GridLayout(cols=8, rows=5)
self.load_into()
def load_into(self):
world = World.World(8, 5)
world.build_gamegrid()
for cell in world.gamegrid:
name = str(cell.name)
grid_cell = GridCell()
grid_cell.text = name
if cell.start:
grid_cell.id = "start"
if cell.goal:
grid_cell.id = "goal"
if cell.cliff:
grid_cell.id = "cliff"
if cell.field:
grid_cell.id = "normal"
self.grid.add_widget(grid_cell)
def build(self):
return self.grid
customLabel = GameGridApp()
customLabel.run()
I may give an idea , that create a 'subgrids' object and a 'main grid' object that contain the 'subgrids'. These two objects would be GridLayout objects.
Here is a simple example in python2.7 :
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
class SubGrids(GridLayout):
def __init__(self):
GridLayout.__init__(self, cols=3, rows=3);
self.add_widget(Label(text='1st'));
self.add_widget(Label(text=''));
self.add_widget(Label(text='2nd'));
self.add_widget(Label(text=''));
self.add_widget(Label(text='3rd'));
self.add_widget(Label(text=''));
self.add_widget(Label(text='4th'));
self.add_widget(Label(text=''));
self.add_widget(Label(text='5th'));
class Grids(GridLayout):
def __init__(self):
GridLayout.__init__(self, cols=2, rows = 2);
self.add_widget(SubGrids());
self.add_widget(SubGrids());
self.add_widget(SubGrids());
self.add_widget(SubGrids());
class Example(App):
def build(self):
return Grids()
if __name__ == '__main__':
x = Example();
x.run();
Hope this gives an idea.

Python / Kivy - Changing Screen with phone screen orientation (android)

I haven't found anything on the internet so far, all I want to know is if its possible to change the current screen in kivy depending on the orientation of the phone's screen (Landscape or portrait) and how to do it. or at least a link to a tutorial because I couldn't find one myself.
I haven't found a way of doing this by recognizing the android device's orientation. However, the following program changes it's contents by comparing the window's height and width. The program's Label changes dynamically, so when the width is greater (landscape mode) it's Label has a different text then when the height is greater (portrait mode). Currently it works on Windows, but unfortunately I don't have a Linux system to build an android version. Theoretically it should work, but i'm not 100% sure.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.graphics import Rectangle, Color
class MainScreen(FloatLayout, Label):
"""MAIN WINDOW CLASS"""
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
with self.canvas.before:
Color(0.988, 0.725, 0.074, 1, mode='rgba')
self.rect = Rectangle(pos=self.pos, size=self.size)
self.bind(size=self.update_rect)
self.titlos = Label(text="",
bold=True,
text_size=(None,None),
font_size="20sp",
pos_hint={'center_x': 0.5, 'center_y': .85},
size_hint_y=None,
size = self.size,
height=self.texture_size[1],
halign="center",
valign = "middle",
color=(0.055, 0.235, 0.541, 1))
self.add_widget(self.titlos)
self.bind(size=self.update_orientation)
def update_rect(self, *args):
"""FUNCTION TO UPDATE THE RECATANGLE OF CANVAS TO FIT THE WHOLE SCREEN OF MAINSCREEN ALWAYS"""
self.rect.pos = self.pos
self.rect.size = self.size
def update_orientation(self, *args):
"""FUNCTION TO UPDATE THE SCREEN CONTENTS WHEN THE WINDOW SIZE CHANGES"""
if self.parent.size[1] > self.parent.size[0]:
self.titlos.text = "This is\nPortrait\nOrientation"
else:
self.titlos.text = "This is Landscape Orientation"
# This is just for checking. Not essential to the program.
print("Width:", self.parent.size[0], ", Height:", self.parent.size[1])
class main(App):
"""BUILDING THE APP"""
def build(self):
return MainScreen()
if __name__ == "__main__":
main().run()
You can use the update_orientation function to include whatever you need to change when the orientation changes.

Autoresizing Canvas in a Kivy App

I am writing my first Kivy app in python only (I'm avoiding kv for now). I have created a custom widget called WorldviewWidget, and I'm trying to use it as a place to draw. With the button widgets, I just give a size_hint and a pos_hint, and they show up where I want them. But with my widget, I don't know how to use the size_hint and position_hint to size the rectangle I am drawing in my WorldviewWidget. Here is the code. Thanks in advance!
#! /usr/bin/python
from kivy.app import App
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
class WorldviewWidget(Widget):
def __init__(self, **kwargs):
super(WorldviewWidget, self).__init__(**kwargs)
self.canvas.clear()
print self.size, self.pos
with self.canvas:
Color(1, 0, 0, 1, mode='rgba')
# HELP! I want the rectangle to be resized when the window changes size so that it always takes up the same proportion of the screen.
self.rect = Rectangle(size=???, pos=???)
class JFROCS_App(App):
def build(self):
Window.clearcolor = [1,1,1,1]
parent = FloatLayout(size=Window.size)
worldview = WorldviewWidget(size_hint=(0.4, 0.4), pos_hint = {'x':0.2, 'y':0.2})
parent.add_widget(worldview)
start_btn = Button(text='Start', size_hint=(0.1, 0.1), pos_hint={'x':.02, 'y':.7}, background_color=[0,1,0,1])
start_btn.bind(on_release=self.start_simulation)
parent.add_widget(start_btn)
pause_btn = Button(text='Pause', size_hint=(0.1,0.1), pos_hint={'x':.02, 'y':.6}, background_color=[1,1,0,1])
pause_btn.bind(on_release=self.pause_simulation)
parent.add_widget(pause_btn)
stop_btn = Button(text='Stop', size_hint=(0.1,0.1), pos_hint={'x':.02, 'y':.5}, background_color=[1,0,0,1])
stop_btn.bind(on_release=self.stop_simulation)
parent.add_widget(stop_btn)
return parent
def start_simulation(self, obj):
print "You pushed the start button!"
def pause_simulation(self, obj):
print "You pushed the pause button!"
def stop_simulation(self, obj):
print "You pushed the stop button!"
if __name__ == '__main__':
JFROCS_App().run()
I think that this sort of task is predestined for the kivy-language but here is a solution in Python. Basically, I have used the bind-method to make your widget listen for changes in its parent's size. Have a look at this for more information on this mechanism.
from kivy.app import App
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
class WorldviewWidget(Widget):
def __init__(self, **kwargs):
super(WorldviewWidget, self).__init__(**kwargs)
self.canvas.clear()
print self.size, self.pos
with self.canvas:
Color(1, 0, 0, 1, mode='rgba')
# *changed* ##############################################
self.rect = Rectangle(size=self.size, pos=self.pos)
# *new* ##########################################################
def update_size(self, instance, new_size):
print "UPDATING SIZE", instance, new_size
self.size[0] = new_size[0] * 0.4
self.size[1] = new_size[1] * 0.4
self.rect.size = self.size
self.pos[0] = self.parent.size[0] * 0.2
self.pos[1] = self.parent.size[1] * 0.2
self.rect.pos = self.pos
class JFROCS_App(App):
def build(self):
Window.clearcolor = [1,1,1,1]
parent = FloatLayout(size=Window.size)
# *changed* ##################################################
worldview = WorldviewWidget(size=(0.4*parent.size[0], 0.4*parent.size[1]),
pos=(0.2*parent.size[0], 0.2*parent.size[1]))
# makes sure that the widget gets updated when parent's size changes:
parent.bind(size=worldview.update_size)
parent.add_widget(worldview)
start_btn = Button(text='Start', size_hint=(0.1, 0.1), pos_hint={'x':.02, 'y':.7}, background_color=[0,1,0,1])
start_btn.bind(on_release=self.start_simulation)
parent.add_widget(start_btn)
pause_btn = Button(text='Pause', size_hint=(0.1,0.1), pos_hint={'x':.02, 'y':.6}, background_color=[1,1,0,1])
pause_btn.bind(on_release=self.pause_simulation)
parent.add_widget(pause_btn)
stop_btn = Button(text='Stop', size_hint=(0.1,0.1), pos_hint={'x':.02, 'y':.5}, background_color=[1,0,0,1])
stop_btn.bind(on_release=self.stop_simulation)
parent.add_widget(stop_btn)
return parent
def start_simulation(self, obj):
print "You pushed the start button!"
def pause_simulation(self, obj):
print "You pushed the pause button!"
def stop_simulation(self, obj):
print "You pushed the stop button!"
if __name__ == '__main__':
JFROCS_App().run()
And have a look at the kivy-language -- it takes care of all the binding for you :)

Python Kivy: Align text to the left side of a Label

I read the docs, and still don't know how to align the text inside a Kivy-Label to its left side. The text is centered from default. A halign = "left" didn't help.
Sorry, if the solution is obvious, but I simply don't find it.
EDIT:
Example code:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
class Example(App):
def build(self):
self.root = FloatLayout()
self.label = Label(text="I'm centered :(", pos=(0,0), size_hint=(1.0,1.0), halign="left")
self.label.text_size = self.label.size #no horizontal change
self.root.add_widget(self.label)
return self.root
Example().run()
According to the documentation, it appears that the new created label have a size which exactly fit the text length so you might not see any differences after setting the halign property.
It is recommended there to change the size property (as shown in the example)
text_size = self.size
which will set the size of the label to the widget containing it.
Then you should see that the label is correctly centered.
As Tshirtman pointed out, you also have to bind text_size property to size. Full working example:
#!/usr/bin/kivy
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
class Example(App):
def build(self):
self.root = FloatLayout()
self.label = Label(text="I'm aligned :)", size_hint=(1.0, 1.0), halign="left", valign="middle")
self.label.bind(size=self.label.setter('text_size'))
self.root.add_widget(self.label)
return self.root
Example().run()
I'm kind of late to the party, but another nice trick I found for this is if you create your labels using your own custom class, you can define in that class the on_size function to change the text_size to size.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
class MyLabel(Label):
def on_size(self, *args):
self.text_size = self.size
class Example(App):
def build(self):
self.root = FloatLayout()
self.label = MyLabel(text="I'm aligned :)", size_hint=(1.0, 1.0), halign="left", valign="middle")
self.root.add_widget(self.label)
return self.root
Example().run()
Example with on_size:
Example without on_size:

How to allow user to choose file as background image in kivy?

Or, how to do so using python, give it an ID, and set it as background image in kv language?
I would like to be able to draw on top of an image instead of a black screen, which I am doing here:
edited
new problem: upload button does not work, here is new code
from random import random
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.graphics import Color, Line, Rectangle
from kivy.uix.filechooser import FileChooserListView, FileChooserIconView
from kivy.uix.floatlayout import FloatLayout
class MyPaintWidget(Widget):
def on_touch_down(self, touch):
color = (random(), random(), random())
with self.canvas:
Color(*color)
d = 30.
touch.ud['line'] = Line(points=(touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
def build(self):
parent = Widget()
painter = MyPaintWidget()
Choose = Button(text = 'upload image')
parent.add_widget(painter)
parent.add_widget(Choose)
def chooose_file(obj):
fc = FileChooserIconView(title= 'upload image')
image_path = self.fc.selection[0]
image_name = file_path.split('/')[-1]
with self.canvas.before:
Rectangle(
size=self.size,
pos=self.pos,
source=image_name)
Choose.bind(on_release=choose_file)
return parent
if __name__ == '__main__':
MyPaintApp().run()
What about this:
If you used the kivy filechooser to get the user to select an image file,
then you could use the .selection attribute of the filechooser to get the name and/or path of that file. Once you have that, you could use it to set the source of a Rectangle on the canvas of the layout etc. where you want the background image.
For instance, to set a background image on a BoxLayout, inside the class that inherits from the BoxLayout:
fc = FileChooserIconView(title="Choose Image")
image_path = self.fc.selection[0]
image_name = file_path.split('/')[-1]
with self.canvas.before:
Rectangle(
size=self.size,
pos=self.pos,
source=image_name)
This is of course a very simplistic example, and isn't really taking the rest of your code into account, but with the kivy docs on FileChooser you should get it. Worth noting also that you could do this in the kv file, perhaps much more cleanly.

Categories

Resources