python - 为什么根窗口小部件与窗口的大小不同?

标签 python kivy

我尝试使用带有 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_hint 是布局使用的值元组来管理其子级的大小”。

您的根小部件确实占据了窗口的整个空间。您可以通过向 MyWidget 的 Canvas 添加一个矩形来测试这一点,如下所示::

with self.canvas.before:
    Color(1,0,0,1)
    Rectangle(pos=self.pos, size=self.size)

您应该熟悉 Canvas ,canvas.before and canvas.after 。它们基本上是指令组,之前组在小部件的 Canvas 指令之前绘制,之后组在之后绘制。

Kivy 中一个关键的不同之处是小部件的大小调整/布局会延迟到下一帧,因此如果您只是将上面的代码片段添加到代码中,如下所示::

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()

这只会在小部件的初始位置和大小处显示一个红色矩形,当时它的默认位置和大小分别为 (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):
...

正如上面代码的输出所示,您的小部件占据了整个窗口的大小。但是,这并不能解决您的问题,子布局仍然保持其原始位置和原始大小。这是因为小部件无法控制其子级的大小,如上所述。

这里有两种选择,要么更新小部件的子部件的大小和位置,就像更新矩形一样(多个子部件很快就会变得复杂),要么使用其中一个布局作为根小部件。

这也可以在 kv 中完成,如下所示::

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()

上面的示例将子窗口小部件的大小绑定(bind)到其父窗口小部件的大小。我仍然建议使用布局作为根小部件,并且不要对嵌套布局犹豫不决。

关于python - 为什么根窗口小部件与窗口的大小不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14029010/

相关文章:

Python 记录器未选择配置时间格式。

python - Kivy:获取固定大小的小部件以显示在窗口中央

python - Kivy:GridLayout 内的水平滚动标签

python - Kivy 属性错误 - 对象没有属性 - 尝试用 kv 语言连接小部件

python - 使用python将arduino中的字符串存储到文本文件

javascript - 用于渲染 HTML 和 javascript 的 Python 库

python - RabbitMQ Python Pika - 多个消息的连接处理

python - 无法从使用 PyInstaller 构建的 Kivy 应用程序中获取 lexers.PythonLexer()

python - 游戏中的菜单 : Is Screenmanager the way to do it?

Python进程间通信