问题
How do I dynamically resize the a label or button, in particular, the text_size and height, depending on the amount of text, at run-time?
I am aware that this question has already been answered in one way with this question:
Dynamically resizing a Label within a Scrollview?
And I reflect that example in part of my code.
The problem is dynamically resizing the labels and buttons at run-time. Using, for example:
btn = Button(text_size=(self.width, self.height), text='blah blah')
...and so on, only makes the program think (and logically so) that the "self" is referring to the class which is containing the button.
So, how do I dynamically resize these attributes in the python language, not kivy?
My example code:
import kivy
kivy.require('1.7.2') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
i = range(20)
long_text = 'sometimes the search result could be rather long \
sometimes the search result could be rather long \
sometimes the search result could be rather long '
class ButtonILike(Button):
def get_text(self):
return long_text
class HomeScreen(Screen):
scroll_view = ObjectProperty(None)
def __init__(self, *args, **kwargs):
super(HomeScreen, self).__init__(*args, **kwargs)
layout1 = GridLayout(cols=1, spacing=0, size_hint=(1, None), \
row_force_default=False, row_default_height=40)
layout1.bind(minimum_height=layout1.setter('height'),
minimum_width=layout1.setter('width'))
layout1.add_widget(ButtonILike())
for result in i:
btn1 = Button(font_name="data/fonts/DejaVuSans.ttf", \
size_hint=(1, None), valign='middle',)#, \
#height=self.texture_size[1], text_size=(self.width-10, None))
btn1.height = btn1.texture_size[1]
btn1.text_size = (btn1.width-20, layout1.row_default_height)
btn1.text = long_text
btn2 = Button(font_name="data/fonts/DejaVuSans.ttf", \
size_hint=(1, None), valign='middle')
btn2.bind(text_size=(btn2.width-20, None))
btn2.text = 'or short'
layout1.add_widget(btn1)
layout1.add_widget(btn2)
scrollview1 = self.scroll_view
scrollview1.clear_widgets()
scrollview1.add_widget(layout1)
class mybuttonsApp(App):
def build(self):
return HomeScreen()
if __name__ == '__main__':
mybuttonsApp().run()
And the kv file:
#:kivy 1.7.2
<ButtonILike>:
text_size: self.width-10, None
size_hint: (1, None)
height: self.texture_size[1]
text: root.get_text()
#on_release: root.RunSearchButton_pressed()
<HomeScreen>:
scroll_view: scrollviewID
AnchorLayout:
size_hint: 1, .1
pos_hint: {'x': 0, 'y': .9}
anchor_x: 'center'
anchor_y: 'center'
Label:
text: 'Button Tester'
ScrollView:
id: scrollviewID
orientation: 'vertical'
pos_hint: {'x': 0, 'y': 0}
size_hint: 1, .9
bar_width: '8dp'
You can see that I added the button from the kv file which displays all the behavior that I want at the top of the list. Resize your window while running it, and you can see the magic. And, of course, changing the text_size also makes it possible for me to align text.
I simply have not been able to achieve the same behavior on the python side. My app requires that the buttons be created at run-time. I think the answer might lie with "bind()", though admittedly, I'm not sure I used it correctly in my attempts or that I understand it fully. You can see that I tried with "btn2", which I thought would've thrown the text to the left (since halign defaults to left), but didn't seem to do anything.
I appreciate the help.
回答1:
I think the best way is to set Label's/Button's size to texture_size
:
Label:
text: "test"
size_hint: None, None
size: self.texture_size
canvas.before: # for testing purposes
Color:
rgb: 0, 1, 0
Rectangle:
pos: self.pos
size: self.size
回答2:
btn2.bind(text_size=(btn2.width-20, None))
As with your other question, the problem is that you have the syntax of bind
wrong. You must pass a function, but you just wrote a tuple, and bind can't do anything useful with that - it certainly doesn't know you happened to write btn2.width there.
Also, the syntax is that bind
calls the function when the given property changes. That's the opposite of what you want - you need to change the text_size when btn2.width changes, not call a function when text_size changes
I think something like the following would work. instance
and value
are the default arguments we ignored in the other question.
def setting_function(instance, value):
btn2.text_size = (value-20, None)
btn1.bind(width=setting_function)
回答3:
My answer is slightly different from @martin's - I only want to modify the height.
def my_height_callback(obj, texture: Texture):
if texture:
obj.height = max(texture.size[1], 100)
class MyButton(Button):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.size_hint = (1, None)
self.bind(texture=my_height_callback)
When the text is rendered the texture property of the button gets set. That texture's height is then pushed to the button's height via the callback. Calling max()
allows for a minimum height to be set. This works fine with labels as well.
来源:https://stackoverflow.com/questions/21342472/dynamically-resizing-a-kivy-label-and-button-on-the-python-side