How do you compacted a GridLayout vertical space in Kivy? - python

Have a look at the screenshot below:
I kinda new in this Kivy layout scheme, previously I work a lot in PyQt. In PyQt, that blank vertical space can easily get rid of by using Spacer. But how do you do this in Kivy? Below is part of the KV file that constitute this layout.
GridLayout:
cols: 1
GridLayout:
cols: 2
row_default_height: '48dp'
row_force_default: True
spacing: 10, 10
padding: 10, 10
Label:
size_hint: None, None
text: 'Input'
halign: 'left'
valign: 'top'
text_size: self.size
width: 50
TextInput:
id: txt_url
size_hint: 1, None
text: ''
TabbedPanel:
id: tp
do_default_tab: False
TabbedPanelItem:
id: tab_fl
text: ''
TabbedPanelItem:
text: ''
FloatLayout
id: box
TabbedPanelItem:
text: ''
FloatLayout
id: box
I Would love to know what is the best practice of using Kivy layout mechanism. :)

In this case, you can take advantage of the GridLayout's minimum_height property to size it appropriately.
GridLayout:
cols: 1
GridLayout:
cols: 2
row_default_height: '48dp'
row_force_default: True
spacing: 10, 10
padding: 10, 10
# add these two lines
size_hint_y: None
height: self.minimum_height
...

Because you're using one column width in your root GridLayout, it be possible to resize the rows based off children height using the following trick for setting rows_minimum.
GridLayout:
cols: 1
row_force_default: True
## Call it what ya like, just interested in setting 'self.rows_minimum'
foo: [self.rows_minimum.update({i: x.height}) for i, x in enumerate(reversed(list(self.children)))]
## ... rest of layout ...
The internal GridLayout and TabbedPanel are the rows/children of your root GridLayout, so setting heights for the internal elements should allow for the foo generator redirection to pull-up the excess space.
Now for readers that may have more than one column there be a more extensive example, that shows one way of handling auto-sizing of grid layouts and a bunch of other goodies, over at another answer regarding text input word wrapping.

Related

Insert a widget to the beginning of a layout. Kivy

I am trying to understand how StackLayout works within ScrollView in Kivy. And i have got a problem. I do not know how to insert a widget to the beginning of the layout. If i use .add_widget() method, it adds the widget to the end(in the bottom) of the layout. And if i change the orientation of the layout(it
has stacking id) to 'lr-bt' and then add the widget(with "Title" and "Print" labels), then it causes some padding from the top of the ScrollView. So here is what i get:
May we could use other layouts. If anyone could help me fix that top padding or insert widget to the beginning, that would be great. Thanks.
Here is some code from .py file:
pln = Plan(text_label="Title", text="Print")
self.root.ids.stacking.add_widget(pln)
And here is my ScrollView with the StackLayout from .kv file:
BoxLayout:
id: stack_box
size_hint_y: 1
pos: 2, root.height-1057
RecycleView:
scroll_y: 1
do_scroll_x: False
do_scroll_y: True
size_hint: 1, None
height: 1000
id: scroll_plans
StackLayout:
spacing: 10
padding: 10
id: stacking
orientation: 'lr-bt'
size_hint_y: None
height: 9000

Adjust Kivy FileChooser Font Size

I'm looking for how I can change the font size of all text in a kivy FileChooserListView class. I am hoping to do so in pure python if possible. I like that the standard Label and Button uix classes take font_size as an initialize parameter, but it appears the FileChooserListView does not. If doing so in pure python isn't an easy approach and there's a good .kv file approach, I'd take that too. Thanks!
There is no direct way to do that, but you can fiddle with the FileListEntry template that the FileChooserListView uses to display the entries. In that template, you can adjust the font sizes used. Here is my attempt at that:
Builder.load_string('''
[FileListEntry#FloatLayout+TreeViewNode]:
locked: False
entries: []
path: ctx.path
# FIXME: is_selected is actually a read_only treeview property. In this
# case, however, we're doing this because treeview only has single-selection
# hardcoded in it. The fix to this would be to update treeview to allow
# multiple selection.
is_selected: self.path in ctx.controller().selection
orientation: 'horizontal'
size_hint_y: None
height: '96dp' if dp(1) > 1 else '48dp' # height must be big enough to hold font sized below
# Don't allow expansion of the ../ node
is_leaf: not ctx.isdir or ctx.name.endswith('..' + ctx.sep) or self.locked
on_touch_down: self.collide_point(*args[1].pos) and ctx.controller().entry_touched(self, args[1])
on_touch_up: self.collide_point(*args[1].pos) and ctx.controller().entry_released(self, args[1])
BoxLayout:
pos: root.pos
size_hint_x: None
width: root.width - dp(10)
Label:
id: filename
font_size: '48dp' # adjust this font size
size_hint_x: None
width: root.width - sz.width # this allows filename Label to fill width less size Label
text_size: self.width, None
halign: 'left'
shorten: True
text: ctx.name
Label:
id: sz
font_size: '48dp' # adjust this font size
#text_size: self.width, None
size_hint_x: None
width: self.texture_size[0] # this makes the size Label to minimum width
text: '{}'.format(ctx.get_nice_size())
''')
This is based heavily on the FileListEntry template in style.kv. There are two font_sizes that you can adjust, and a height for the entry. All three must be coordinated to get a reasonable result.

Multiple valigns in one label

I am programming a Chat Bot and I want to build a GUI using kivy. To make the chat I am using labels in a scrollview:
GridLayout:
cols: 1
rows: 0
ScrollView:
size: self.size
do_scroll_x: False
Label:
id: msg
text_size: self.width,None
size_hint_y: None
height: self.texture_size[1]
font_size: 20
Python Code:
def send(self,x):
#global msgback
self.msg_list.text += str(x + "\n")
The problem is, that I do not know how to make the valign, that only makes the messages from the user on the right side. How do I do that?
Use halign to align text to the right.
Label:
id: msg
text_size: self.width,None
size_hint_y: None
height: self.texture_size[1]
font_size: 20
halign: 'right'
valign: 'middle'
Label » halign
halign
Horizontal alignment of the text.
halign is an OptionProperty and defaults to ‘left’. Available options
are : left, center, right and justify.
Warning
This doesn’t change the position of the text texture of the Label
(centered), only the position of the text in this texture. You
probably want to bind the size of the Label to the texture_size or set
a text_size.

GridLayout Not Scrolling in Kivy

Please tell me why this doesn't work, the whole program works fine, it uses a function inside the main program to get it's text, but it won't scroll so the user won't be able to view the entire output.
<AnswerScreen#Screen>:
input_textb: input_textb
ScrollView:
size_hint: (1, None)
do_scroll_y: True
do_scroll_x: False
bar_width: 4
GridLayout:
padding: root.width * 0.02, root.height * 0.02
cols: 1
size_hint_y: None
size_hint_x: 1
height: self.minimum_height
Label:
id: input_textb
text: ""
font_size: root.height / 25
text_size: self.width, None
Edit:
I had already tried doing the same as many previous answers, in the particular one mentioned in the comments, I got an error saying "NoneType" has no attribute "bind".
I removed the size hint, it still doesn't work, but thanks anyway.
The text is definitely long enough.
I believe the label's size is not set, which i agree can be confusing at first, Label has a widget size (size as all widgets) and a texture_size, which is set to the actual size of the displayed text, kivy doesn't relate these two in any particular way at first, and it's up to you to decide how one influences the other, you did half of the work in setting text_size to (width, None), which forces the texture into having the width of the widget, but you are missing the other part of the deal, which is that you want to be the widget to be as tall as the generated texture. For this size to be effective, you also have to disable size_hint_y for Label, since it's in a GridLayout.
Label:
id: input_textb
text: ""
font_size: root.height / 25
text_size: self.width, None
height: self.texture_size[1]
size_hint_y: None
and you should be all set.
You should set a value for the property scroll_y of the ScrollView between 0 and 1.

Kivy (kv language) StackLayout Issue and Boundary Issue

I'm new to Kivy and still working out the best way to use it. Currently, I'm taking an example from their repo (textsize demo) and attempting to use layout concepts in a personal project.
At the end of the day, all I want is a "navbar" at the top of my screen and a content section below it. At the moment, I'm trying to accomplish this with a BoxLayout which includes a StackLayout (nav items) and a GridLayout (other content).
My Code Snippet:
<WindowWidget>:
BoxLayout:
orientation: 'vertical'
StackLayout:
Label:
text: 'Test1'
Label:
text: 'Test1.1'
Label:
text: 'Test2'
This code produces this: Kivy Screenshot.
I don't understand why label 1.1 is pushed down on top of label 2 rather than appearing beside label 1.
I added the following code taken from the kivy examples hoping the height setting would add some clarity, but I get the error below:
Code:
<StackLayout>:
size_hint_y: None
spacing: dp(6)
padding: dp(6), dp(4)
height: self.minimum_height
Error:
Warning, too much iteration done before the next frame. Check your
code, or increase the Clock.max_iteration attribute
This is caused by my inclusion of the "height: self.minimum_height" line. However, this works in the demo, so I'm not sure how I managed to screw it up. I'll include the example's kv code below for reference.
The original:
BoxLayout:
orientation: 'vertical'
HeadingLabel:
text: 'These modify all demonstration Labels'
StackLayout:
# Button is a subclass of Label and can be sized to text in the same way
Button:
text: 'Reset'
on_press: app.reset_words()
ToggleButton:
text: 'Shorten'
on_state:
app.shorten=self.state=='down'
ToggleButton:
text: 'max_lines=3'
on_state:
app.max_lines=3 if self.state=='down' else 0
Spinner:
text: 'bottom'
values: 'bottom', 'middle', 'top'
on_text: app.valign=self.text
Spinner:
text: 'left'
values: 'left', 'center', 'right', 'justify'
on_text: app.halign=self.text
GridLayout:
id: grid_layout
cols: 2
height: cm(6)
size_hint_y: None
HeadingLabel:
text: "Default, no text_size set"
HeadingLabel:
text: 'text_size bound to size'
DemoLabel:
id: left_content
disabled_color: 0, 0, 0, 0
DemoLabel:
id: right_content
text_size: self.size
padding: dp(6), dp(6)
ToggleButton:
text: 'Disable left'
on_state:
left_content.disabled=self.state=='down'
# Need one Widget without size_hint_y: None, so that BoxLayout fills
# available space.
HeadingLabel:
text: 'text_size width set, size bound to texture_size'
text_size: self.size
size_hint_y: 1
DemoLabel:
id: bottom_content
# This Label wraps and expands its height to fit the text because
# only text_size width is set and the Label size binds to texture_size.
text_size: self.width, None
size: self.texture_size
padding: mm(4), mm(4)
size_hint_y: None
# The column heading labels have their width set by the parent,
# but determine their height from the text.
<HeadingLabel#Label>:
bold: True
padding: dp(6), dp(4)
valign: 'bottom'
height: self.texture_size[1]
text_size: self.width, None
size_hint_y: None
<ToggleButton,Button>:
padding: dp(10), dp(8)
size_hint: None, None
size: self.texture_size
# This inherits Button and the modifications above, so reset size
<Spinner>:
size: sp(68), self.texture_size[1]
<DemoLabel#Label>:
halign: app.halign
valign: app.valign
shorten: app.shorten
max_lines: app.max_lines
canvas:
Color:
rgb: 68/255.0, 164/255.0, 201/255.0
Line:
rectangle: self.x, self.y, self.width, self.height
<StackLayout>:
size_hint_y: None
spacing: dp(6)
padding: dp(6), dp(4)
height: self.minimum_height
TYIA

Categories