How do I get the fixed window size at one point in time? (s.t. this value will not change later)
I would like to add an image:
Image:
width: self.parent.width
height: self.parent.height
size_hint: None, None
which should keep its initial size when rescaling the window.
I can do this like
Image:
width: 800
height: 800
size_hint: None, None
But I can't get the windows current dimensions in a way that they stay constant when rescaling the window later.
Thanks for your help.
The only way I can think of is to do it outside of your .kv file. Precisely, you can set the values on any event triggered, such as on button press or when starting your app, just like that:
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
class Main(App):
def build(self):
base = Builder.load_file("main.kv")
base.ids.img.width = Window.width
base.ids.img.height = Window.height
return base
In the example provided the width and height are set only once, when building the app. Alternatively you could achieve the same behaviour by moving the code to the __init__ of your class and access the image whenever you'd like to by calling self.base.ids.img (under the assumption you provide self.base).
Related
I'm trying to get the size of the rectangle from the canvas called Canvas_Widget class, but no matter what I do, it keeps on giving an error
the code that I wrote and the description of the error are given in the code as a comment.
source file:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.metrics import dp
Window.size= dp(500),dp(500)
class Canvas_Widget(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
class MainWidget(BoxLayout):
def __init__(self,**kwargs):
super(MainWidget, self).__init__(**kwargs)
def minimizer(self,button):
button.background_color=(1,0,0,1)
#here i want to try and print the size of that rect id that i created
# i tried "print(self.ids.Canvas.ids.rect.size)"
"""the error says: (((File "f:\canvas\1\main.py", line 16, in minimizer
print(canvas.ids.rect.size)
File "kivy\properties.pyx", line 964, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__')))"""
def minimizer_release(self,button):
button.background_color=(.3,.3,1,1)
class mynewApp(App):
pass
mynewApp().run()
here is the kivy file:
MainWidget:
<Canvas_Widget>:
canvas:
Color:
rgb:.4,.4,.4,1
Rectangle:
id:rect #this is the id that Im trying to share with the MainWidget
pos:dp(100),dp(100)
size:self.width - dp(200),self.height - dp(200)
Color:
rgb:0,1,0,1
Line:
points:(dp(100),self.height - dp(100),self.width - dp(100),dp(100))
Line:
points:(dp(100),dp(100),self.width - dp(100),self.height - dp(100))
<MainWidget>:
Button:
text:'press'
on_press:root.minimizer(self)
background_color:(.3,.3,1,1)
on_release: root.minimizer_release(self)
Canvas_Widget:
id:Canvas
here is also the problem with the placement of the canvas on the screen. its suppose to be on the right side, but it's on the left side, on the button:
image 1
image 2
by the way, I'm sorry to ask for too much. it's just that I really want to know how to fix this problem.
thanks
First thing to notice that in kvlang binding happens by Builder automatically (at least from developer's side). That's why it's convenient to use this language for design purpose. From kivy doc.,
As your application grows more complex, it’s common that the construction of widget trees and explicit declaration of bindings becomes verbose and hard to maintain. The KV Language is an attempt to overcome these shortcomings. The KV language, sometimes called kvlang or the kivy language, allows you to create your widget tree in a declarative way and to bind widget properties to each other or to callbacks in a natural manner.
Now in kvlang when you do something like this :
Rectangle:
pos:dp(100),dp(100)
in the canvas instructions, you are basically instructing to draw a rectangle at (100, 100) in the window. But what you want (as it seems) is to draw that rectangle where the widget is and shifted by (100, 100) from its position.
Now as you used BoxLayout as container, each of its child's position, size are managed by itself (if not provided explicitly). So to reflect that changes you need to change the above lines of code by the following,
Rectangle:
pos: self.x+dp(100), self.y+dp(100)
This will reposition the rectangle (automatically) whenever the position of widget (x, y) changes.
Thus the changes you need in your kvlang are,
<Canvas_Widget>:
canvas:
Color:
rgb:.4,.4,.4,1
Rectangle:
# id:rect # Will not work here.
# pos:dp(100),dp(100)
pos: self.x+dp(100), self.y+dp(100)
size: self.width - dp(200), self.height - dp(200)
Color:
rgb:0,1,0,1
Line:
# points:(dp(100),self.height - dp(100),self.width - dp(100),dp(100))
points: (self.x+dp(100), self.y+self.height-dp(100), self.x+self.width-dp(100),self.y+dp(100))
Line:
# points:(dp(100),dp(100),self.width - dp(100),self.height - dp(100))
points: (self.x+dp(100), self.y+dp(100),self.x+self.width-dp(100), self.y+self.height-dp(100
when a user click on a widget on my application, the keyboard that appears can hide it if the widget is too low.
I tried ScrollView.scroll_to() to ask for a focus on the widget, it works but it doesn't take the keyboard in the equation.
Before I click on "Raison Sociale".
After I click on "Raison Sociale
So the widget is hidded by the keyboard.
I don't know if a function like this already exist.
If widget.hiddedByKeyboard():
widget.show_taking_consideration_of_the_keyboard()
There is also the problem of the widgets at the end of the Screen, if we try to show them by scrolling down, the ScrollView will try to go up again even if that will hide the widget.
Ahh the classic, the keyboard covers the widget problem. I encountered this and here's what I did to solve it:
In my KV file I had something like this:
<MainWindow>:
... [A BUNCH OF WIDGETS] ...
ScrollView:
BoxLayout:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
... [A BUNCH OF WIDGETS] ...
Widget: # The important widget
id: buffer
size_hint: (1, None)
height: root.buffer
I added at the bottom of the ScrollView a blank Widget whose height was defined by a NumericProperty in the top level widget (Window - a BoxLayout).
In the Python file I had:
from kivy.core.window import Window # Need to import this
class MainWindow(BoxLayout):
buffer = NumericProperty()
Then when I requested the keyboard, I made sure to set buffer = Window.keyboard_height. This adjusted the height of blank Widget to the height of the keyboard, essentially creating extra room for the keyboard. This gives the user extra scrolling room to position the keyboard.
You can combine this implementation with the ScrollView.scroll_to() method to create a really nice effect. Essentially pass ScrollView.scroll_to(text_input_widget) when the user clicks on the TextInput. This will automatically scroll the ScrollView down so that the TextInput is at the top and the keyboard is below it.
This probably isn't the cleanest implementation (I could probably do it better now), but the concept of creating a blank Widget whose size is the height of the keyboard would be the same.
I found a better way, this attribute will do all the job.
from kivy.core.window import Window
Window.softinput_mode = "below_target"
I've been trying to create a simple application for android, and I've started working on the GUI first.
However, after I finished the tutorial, and tried implementing my own GUI, it stopped working.
The official documentation does not focus on .kv files, answers found in other questions here on SO all have different answers, and I am just lost.
All I need is the root widget, which has a white rectangle the size of the screen, to be rendered. Below is the minimum reproducable code.
I've tried:
changing canvas to Canvas, and canvas.before as written in another answer from SO.
Building the app using Builder.load_file()
Changing the build() override to pass
None worked.
Any help is appreciated.
My KV File (GutTrust.kv)
#:kivy 1.0.1
gutScreen:
Canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
#Many more elements but they are unnessesary for the demonstration.
My Python File (main.py)
from kivy.app import App
from kivy.uix.widget import Widget
class gutScreen(Widget):
"""Background"""
pass
class GutTrustApp(App):
def build(self):
return gutScreen()
if __name__ == '__main__':
GutTrustApp().run()
rename "gutScreen" to "GutScreen". replace "GutScreen:" with ":" in kv. replace "Canvas" with "canvas". That'd work. – Nattōsai Mitō
And rename GutTrust.kv to guttrust.kv – John Anderson
Those two comments solved the problem. Thank you!
How do I set my Kivy app to be resizable up to a specified size and no bigger than specified size but can be resized smaller than specified size?
This is quite simple to implement, but I'm afraid you can't do it in "realtime" (at least not on Windows), because the size property is updated after you release the button from resizing i.e. "confirm" the final size. For that you'd need to get to WinAPI and other appropriate system APIs, but beware it'll be really resource hungry as with the system API you'd basically check for every change (even 300 → 300.0000000001 if the window manager would allow floats).
That being said, with Kivy you can make it quite easily when the behavior has to check for resizing and forbid actually making it bigger without disabling the Window's resizing in any way.
You'll need to set the initial size first though (with Config before any other Kivy import) to make it consistent, otherwise you'll end up with a Window of size 800x600 and after you attempt to resize, then it'll scale down to 300x150. The rest is just about a binding to either size or on_resize attributes of the Window
# set the initial size
from kivy.config import Config
MAX_SIZE = (300, 150)
Config.set('graphics', 'width', MAX_SIZE[0])
Config.set('graphics', 'height', MAX_SIZE[1])
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
class My(App):
def check_resize(self, instance, x, y):
# resize X
if x > MAX_SIZE[0]:
Window.size = (300, Window.size[1])
# resize Y
if y > MAX_SIZE[1]:
Window.size = (Window.size[0], 150)
def build(self):
Window.bind(on_resize=self.check_resize)
return Button()
My().run()
I found a very simple solution when I was experimenting:
#:import W kivy.core.window.Window
<SomeWidget>:
size_hint: None, None
width: 300 if W.width <= 400 else (W.width - (W.width * .1))
height: 300 if W.height <= 500 else (W.height - (W.height * .2))
That worked for me. I recommend to put all after the colon of the 'width' and 'height' in other place, because as you can see it consumes a lot of room in kv language.
I am in a bit of a predicament. While working with Kivy's ScrollView Layout and (Current Experimental) reStructuredText renderer module, I ran into a slight problem. Whenever I run my code, my terminal spams me with:
[CRITICAL] [Clock] Warning, too much iteration done before the next frame. Check your code, or increase the Clock.max_iteration attribute
Now, the application seems to run perfectly fine, until you get to the page with the rST Document inside a ScrollView Layout. That page does all kinds of odd things. The Main scroll view will slowly scroll down, forever, trailing off the page into whiteness, and the rST document is placed oddly, shifted slightly to the left.
When I remove the document though, the screen and application behave perfectly normal, running smoothly. Does anyone have any idea as to how I could fix this, to make the page work correctly? (Did I mention the rST Document was originally in a Carousel, but I took out the carousel to see if that was the problem.)
Here is the Kivy Language Code:
<Page>:
orientation: 'vertical'
ScrollView:
size_hint: (.99, .99)
StackLayout:
size_hint_y: None
id: content_layout
height: self.minimum_height
WrappedLabel:
text: "Test"
font_size: min(root.height, root.width)
RstDocument:
underline_color: 'blue'
text:("Some Text")
Could the problem be that rST Documents are based off of the ScrollView Layout by any chance?
Sometimes height: self.minimum_height and similar stuff are like shooting yourself in a foot. Definitely try to comment out these things first, because if you don't do something fancy, the sizing is the issue.
Now, why is it an issue? StackLayout has its minimum_height set from minimum_size, which is set I think somewhere here and has some initial value that is not zero.
Don't be confused though, minimum_height really defaults to zero at the beginning, but then it's recalculated probably on each added widget or so. If you add on_height: print(self.height) after your height: self.minimum_height, you'll see what I mean.
Why does it do it like that? Simple! You didn't set absolute size for those children (each child has size_hint == [1, 1]).
Also, ScrollView expects size bigger that the ScrollView if I remember correctly (so that it would scroll).
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<Test>:
orientation: 'vertical'
ScrollView:
size_hint: (.99, .99)
StackLayout:
size_hint_y: None
id: content_layout
height: self.minimum_height
on_height: print(self.height)
Label:
size_hint: None, None
size: 100, 30
text: "Test"
font_size: min(root.height, root.width)
RstDocument:
size_hint: None, None
size: 100, 1000
underline_color: 'blue'
text:("Some Text")
''')
class Test(BoxLayout): pass
runTouchApp(Test())
Remove size_hint and size from children and you have your too much iteration there.