我试图使用一个带有GridLayout
的自定义小部件,但是结果总是在一个角落里有一个非常小的网格,而不是在整个窗口中展开一个网格。
示例代码:
import kivy
kivy.require('1.5.1')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
class MyWidget(Widget):
def __init__(self):
super(MyWidget, self).__init__()
grid_layout = GridLayout(cols=3)
grid_layout.add_widget(Button(text='A'))
grid_layout.add_widget(Button(text='B'))
grid_layout.add_widget(Label(text='text'))
grid_layout.add_widget(Label(text='other'))
grid_layout.add_widget(Button(text='text'))
self.add_widget(grid_layout)
class MyApp(App):
def build(self):
float =
return MyWidget()
MyApp().run()
因为
Widget
的默认size_hint
是(1,1)
它应该在整个窗口中展开,而且GridLayout
也应该展开。为什么没有发生?我怎样才能得到我想要的结果?
最佳答案
`class MyWidget(Widget):`
您的根小部件是
MyWidget
,它继承了Widget
而不是其中一个布局,因此不控制其子级的大小,如here,“size_提示是布局用于管理其子级大小的一组值”。根小部件确实占据了整个窗口空间。您可以通过将矩形添加到
MyWidget
的画布来进行测试,如下所示:with self.canvas.before:
Color(1,0,0,1)
Rectangle(pos=self.pos, size=self.size)
你应该熟悉画布,canvas.before and canvas.after它们基本上是指令组,before组在小部件的画布指令之前绘制,after组在之后绘制。
不过,Kivy的一个不同之处在于,widget的大小/布局会延迟到下一帧,所以如果您只是将上面的代码片段添加到代码中,就像这样:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import *
class MyWidget(Widget):
def __init__(self, **kwargs):
# I'd make sure to pass of kwargs through to the super
# as there are widgets's that process their initial
# arguments through.
super(MyWidget, self).__init__(**kwargs)
grid_layout = GridLayout(cols=3)
grid_layout.add_widget(Button(text='A'))
grid_layout.add_widget(Button(text='B'))
grid_layout.add_widget(Label(text='text'))
grid_layout.add_widget(Label(text='other'))
grid_layout.add_widget(Button(text='text'))
self.add_widget(grid_layout)
with self.canvas.before:
Color(1,0,0,1)
Rectangle(pos=self.pos, size=self.size)
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
这只会在小部件的初始位置和大小显示一个红色矩形,这在当时是默认的pos和size a.k.a(0,0)和(100,100)。
要使红色矩形符合小部件的大小,我们应该bind它的大小与小部件的大小一致,如下所示:
...
grid_layout.add_widget(Button(text='text'))
self.add_widget(grid_layout)
with self.canvas.before:
Color(1,0,0,1)
self.rect = Rectangle(pos=self.pos, size=self.size)
self.bind(size=self.update_rect)
def update_rect(self, instance, value):
self.rect.pos = self.pos
self.rect.size = self.size
class MyApp(App):
def build(self):
...
正如上面代码的输出所示,您的小部件占据了整个窗口的大小。但是,这并不能解决您的问题,而且子布局仍然保持在原来的位置和原来的大小。这是因为小部件不能像上面所说的那样控制其子部件的大小。
这里有两个选择,要么像更新rect那样更新小部件的子部件的大小和位置(很快会与多个子部件复杂化),要么使用其中一个布局作为根小部件。
这也可以用千伏来实现,就像这样:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
Builder.load_string('''
# this is the rule for MyWidget that defines
# what MyWidget looks like i.e.drawing
# instructions and widgets etc
<MyWidget>:
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
# this implicitly binds the size of the
# rect to the size of the widget
size: self.size
# self here still refers to the widget as Rectangle is only a
# graphics instruction and not a widget
pos: self.pos
GridLayout:
cols: 3
# root here refers to the `MyWidget`, bind the size of the
# GridLayout to the size of your root widget
size: root.size
Button:
text: 'A'
Button:
text: 'B'
Label:
text: 'text'
Label:
text: 'other'
Button:
text: 'text'
''')
class MyWidget(Widget):
pass
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
上面的示例将子窗口小部件的大小绑定到其父窗口小部件的大小。我仍然建议使用布局作为根小部件,不要犹豫嵌套布局。
关于python - 为什么根窗口小部件的窗口大小不同?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14029010/