I am trying to get a background around a label that fits the number of lines in the texted in it. For example, a label with text 'Line1\nLine1\nLine3' would have a larger Y dimension that just 'line1'
What currently happens is all of the labels are the same size and clip-off text that doesn't fit within them, the labels are also inside a recycleview layout because I would like to be able to scroll and update large amount of the labels often.
I have tried a few things but have had no luck, and am struggling to get a variable to be understood where I have added # HERE in the .kv file
from kivy.app import App
from kivy.properties import NumericProperty, Clock, ObjectProperty, StringProperty
from kivy.uix.widget import Widget
from kivy.uix.recycleview import RecycleView
from kivy.uix.button import Button
from kivy.uix.label import Label
class TopPostsTest(RecycleView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
message_height = NumericProperty(20)
items = ["hello\ntest\ntest", "test, gghgjhgjhgjhgjhghjghjgjhgjhgjhgjhgjhgjhgjhgjhg", "cheese"]
self.data = [{'text':str(p)} for p in items]
class LabelColor(Label):
pass
class TruthApp(App):
# def build(self):
# return super().build()
pass
if __name__ == "__main__":
TruthApp().run()
<MainControl#PageLayout>:
border: "25dp"
swipe_threshold: 0.4
TopPostsTest:
Settings:
<LabelColor>:
color: 0,0,0,1
text_size: self.size
halign: 'left'
valign: 'top'
font_name: "Assets/Fonts/Nunito-Bold.ttf"
font_size: "12dp"
multiline: True
canvas.before:
Color:
rgba: (0.8, 0.8, 0.8, 1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [5, 5, 5, 5]
canvas:
Color:
rgba:0,0.9,0.9,1
Line:
width:0.8
rounded_rectangle:(self.x,self.y,self.width,root.height, 5) # HERE
<TopPostsTest>:
viewclass: 'LabelColor'
scroll_y: 1
RecycleBoxLayout:
id: message_view
default_size: None, dp(40) # NewHERE
default_size_hint: 1, None
size_hint_y: None
padding: ["10dp", "16dp"]
spacing: "8dp"
height: self.minimum_height
orientation: 'vertical'
Thank you for any help :)
Edit:
I have found that I have been changing the wrong value and that the variable that needs changing has been marker with # NewHERE, however I am still unable to get it to work or get a variable from the py file into the kv
In order to get a Label that expands vertically as it's text-content grows you can set its height to its texture height.
Also, to fit the text within available space (width) you can change text_size.
Thus you can modify the kvlang for LabelColor as,
<LabelColor>:
color: 0,0,0,1
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
Related
I have a GridLayout which takes some Card widgets that are basically RoundedRectangles and are supposed to be filled with specific information, the problem is that the GridLayout can take many cards and I want the user to scroll the widget. Intuitively, I defined it inside a ScrollView to scroll the gridlayout, however, the scrollview does not work. I suspect that the problem is that the gridlayout's height is not actually changing and not adapting to its children but how can I achieve this?
My Python code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
Builder.load_file("design.kv")
class MyLayout(Widget):
pass
class MainApp(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MainApp().run()
My KV code:
#:kivy 2.0.0
<Card#Widget>:
size_hint_y: None
height: (self.parent.height - self.parent.padding[1] * 3) / 2
canvas:
Color:
rgba: 1, 1, 1, 1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [5]
<MyLayout>:
ScrollView:
size: root.size
do_scroll_x: False
do_scroll_y: True
GridLayout:
id: song_menu
cols: 2
size_hint_y: None
height: self.parent.height
padding: 10
spacing: 10
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
size: self.size
pos: self.pos
Card:
Card:
Card:
Card:
Card:
Card:
EDIT: I forgot to mention that I have already tried height: self.minimum_height, however, an absurd thing happens. The gridlayout has a weird behavior and does not show up. Basically I get this in the terminal:
[CRITICAL] [Clock ] Warning, too much iteration done before the next frame. Check your code, or increase the Clock.max_iteration attribute
The GridLayout height isn't adjusting because you have constrained it with:
height: self.parent.height
Try replacing that with:
height: self.minimum_height
Hello I want to place a welcome message at the top of the app (Like the photo this)
I use a FloatLayout for my entire screen (since I want to add some other widgets later) but the problem is the label won't position itself at the center but like this
Here is my python code:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
class MainPage(FloatLayout):
pass
class SmartMirrorApp(App):
def build(self, **kwargs):
return MainPage()
if __name__ == "__main__":
SmartMirrorApp().run()
And this is my kv file:
#:kivy 1.10.1
<MainPage>:
canvas:
Color:
rgba: 1,0,1,0.5
Rectangle:
size: self.size
pos: self.pos
Label:
canvas:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
text: "Welcome, you look beautiful today!"
font_size: 20
size_hint: None, None
size: self.texture_size
pos_hint: {'x': 0.5, 'y': 0.9}
Now if instead of putting 'x':0.5 inside the pos_hint dictionary I use center_x: root.center_x
the image moves to the desired position ONLY if I resize the window but it starts at the position of the second image.
For your pos_hint, use:
pos_hint: {'center_x': 0.5, 'top': 0.9}
That will center the Label horizontally, and the top of the Label will be at 90% of the MainPage height.
I'm trying to build a log viewer on kivy using recycleview since logs can be pretty large. I'm assigning one label widget per line so I can have more control over the text in the future. Some lines will have more text than others so adapted the Label widget to resize according, but when putting that inside recycleview can't seem to be able to control the height of the widget per line anymore, it stays at the same size. What I expect is the label to wrap on the text and adjust height since don't need the extra space between lines. If there's to little text a lot of free space is shown, if I put to much text in the label it floods and label doesn't grow.
One workaround that I tried with different code was to assign at least a 200 lines per label, that seems to work, but I do need more control over each line of text.
This is the example code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
Builder.load_string('''
<Row#BoxLayout>:
canvas:
Color:
rgba: 1, 0.1, 0.1, 0.5 #Red Marker
Rectangle:
size: self.size
pos: self.pos
value: ''
orientation: 'vertical'
Label:
text: root.value
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
font_size: 20
<LogDisplayWidget>:
rv: rv
orientation: 'vertical'
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
''')
class LogDisplayWidget(BoxLayout):
rv = ObjectProperty()
def __init__(self):
super(LogDisplayWidget, self).__init__()
self.load_text()
def load_text(self):
for i in range(10):
line = str(i) + 'This is a test of a bunch of text'
self.rv.data.append({'value': line})
class TestApp(App):
def build(self):
return LogDisplayWidget()
if __name__ == "__main__":
TestApp().run()
enter image description here
enter image description here
Did a code rewrite, the labels appear resized correctly in first page, but getting jerky unexpected results after scrolling, it shows correct label size sometimes then some are to big, and the scroll skips like trying to adjust itself and it fixes size again. Does anyone have a better way to implement this or I'm missing something? I'm suspecting it has something to do with the way the view refreshes
This is the new code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
import random
Builder.load_string('''
<Row#Label>:
canvas.before:
Color:
rgba: 0.8, 0.1, 0.1, 0.5 #Red Marker
Rectangle:
size: self.size
pos: self.pos
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
font_size: dp(20)
<RV>:
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(3)
''')
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
line = ''
for i in range(50):
n = random.randint(0, 1)
if n:
j = random.randint(5, 30)
line = 'Line: ' + str(i+1) + ' This is a test of a bunch of text' * j
else:
line = 'Line: ' + str(i+1) + ' This is a test of a bunch of text'
self.data.append({'text': line})
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
I am new to kivy. I want to insert a text into a kivy label at the startup. But the text of the lable shows out of the label as shown below. I can't find a way to fix this. So please give me a solution.
This is the code of the kv file.
<SmoothLabel#Label>
background_color: (0,0,0,0)
background_normal: ''
back_color: (255,255,255,1)
border_radius: [18]
canvas.before:
Color:
rgba: (255,255,255,0.3)
RoundedRectangle:
size: 50,50
pos: 100,10
radius: self.border_radius
<Money_Manager>
FloatLayout:
size_hint_y: None
height:100
Image:
source:'image4.png'
size: self . texture_size
allow_stretch: True
keep_ratio: False
SmoothLabel:
d: Total_Wealth
text: "Total_Wealth"
This is the code of the python file.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
Builder.load_file('total_wealth.kv')
class Money_Manager(App, FloatLayout):
def build(self):
return self
Money_Manager().run()
In your kv file, you have set the pos and size of the RoundedRectangle to fixed values. You need to set them to the pos and size of the Label. So change this:
<SmoothLabel#Label>
background_color: (0,0,0,0)
background_normal: ''
back_color: (255,255,255,1)
border_radius: [18]
canvas.before:
Color:
rgba: (255,255,255,0.3)
RoundedRectangle:
size: 50,50
pos: 100,10
radius: self.border_radius
to:
<SmoothLabel#Label>
background_color: (0,0,0,0)
background_normal: ''
back_color: (255,255,255,1)
border_radius: [18]
canvas.before:
Color:
rgba: (255,255,255,0.3)
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
Here is my answer for yours
# import kivy module
import kivy
# this restricts the kivy version i.e
# below this kivy version you cannot use the app or software
kivy.require("1.9.1")
# base Class of your App inherits from the App class.
# app:always refers to the instance of your application
from kivy.app import App
# if you not import label and use it it through error
from kivy.uix.label import Label
# defining the App class
class MyLabelApp(App):
def build(self):
# label display the text on screen
lbl = Label(text ="Label is Added on screen !!:):)")
return lbl
# creating the object
label = MyLabelApp()
# run the window
label.run()
Output:
How can I make my boxlayout expand according to dynamically added content?
Here is my code to illustrate what I am trying to do:
main.py
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def add_label(self):
label = Label(text='StackOverflow', color=(0,0,0,1))
self.root.ids.myBox.add_widget(label)
if __name__ == '__main__':
TestApp().run()
test.kv
BoxLayout:
orientation: 'vertical'
spacing: 400
BoxLayout:
orientation: 'vertical'
size_hint: None, None
size: dp(280), dp(100)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
#width: self.minimum_width
#height: self.minimum_height
id: myBox
background_color: (1,1,1,1)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
pos: self.pos
size: self.size
Button:
text: 'BUTTON'
size_hint: None, None
size: dp(100), dp(50)
pos_hint: {'center_x': 0.5, 'center_y': 0.1}
on_release: app.add_label()
The button has the effect of dynamically adding a label to the boxlayout. But the more the labels are added, the size of the boxlayout does not change and the texts are superimposed.
Thanks in advance for your help.
One way to do this is do recalculate the size of the BoxLayout yourself. By changing your add_label() method to:
def add_label(self):
label = Label(text='StackOverflow', color=(0,0,0,1))
self.root.ids.myBox.add_widget(label)
label.texture_update()
boxlayout = self.root.ids.myBox
height = 0
for child in boxlayout.children:
height += child.texture_size[1]
height += 2 * child.padding_y
boxlayout.height = height
The BoxLayout changes height on each Label addition. You would think that you could use the child.height in the calculation, but the default value for height is always 100 until the layout is actually calculated. But, as you have seen, when the layout is calculated, the height of the label is reduced to fit in the BoxLayout. The texture of the Label can be updated before layout, and therefore, I have used its height in the calculation. This will decrease the size of the BoxLayout with the first Label added, and will increase it on every following addition. Note that this will only work for widgets that have a texture property like the Label or Button.