Kivy:GridLayout 总是从左到右然后向下,你能从上到下然后从左到右吗?

Kivy: GridLayout always goes left to right then down, can you go top to bottom then left to right?

我正在 Kivy 中做一个相对简单的布局,我想显示一系列从屏幕顶部到底部填充的按钮,然后当它们到达底部时,从顶部开始一个新列.

GridLayout 似乎做我想做的事,但它似乎总是先从左到右,而不是从上到下。我已经查看了官方文档和 Google,但似乎找不到解决方案。

StackLayout 使用 "orientation: "tb-lr" 命令执行我想要的操作,但是当 GridLayout 只有一列时,按钮宽度不会完全缩放以适合容器这个应用程序。

感谢您的帮助。

如果我没记错的话,这个功能没有实现。但是,您可以使用 Layout class (kivy.uix.layout).

自由实现自己的布局

另一种可能性是 subclassify GridLayout 并覆盖几个方法以从上到下添加 witgets:

Warning

The GridLayout class has major changes between Kivy 1.9 and Kivy 1.10. For this reason, the code works correctly on Kivy 1.10.0 but not in previous versions (See comments).

You must always specify the number of rows of the Layout.

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


def nmax(*args):
    # merge into one list
    args = [x for x in args if x is not None]
    return max(args)


def nmin(*args):
    # merge into one list
    args = [x for x in args if x is not None]
    return min(args)

class TBGridLayout(GridLayout):
    
    def _fill_rows_cols_sizes(self):
        cols, rows = self._cols, self._rows
        cols_sh, rows_sh = self._cols_sh, self._rows_sh
        cols_sh_min, rows_sh_min = self._cols_sh_min, self._rows_sh_min
        cols_sh_max, rows_sh_max = self._cols_sh_max, self._rows_sh_max

        # calculate minimum size for each columns and rows
        n_rows = len(rows)
        has_bound_y = has_bound_x = False
        for i, child in enumerate(reversed(self.children)):
            (shw, shh), (w, h) = child.size_hint, child.size
            shw_min, shh_min = child.size_hint_min
            shw_max, shh_max = child.size_hint_max
            col,  row = divmod(i, n_rows)

            # compute minimum size / maximum stretch needed
            if shw is None:
                cols[col] = nmax(cols[col], w)
            else:
                cols_sh[col] = nmax(cols_sh[col], shw)
                if shw_min is not None:
                    has_bound_x = True
                    cols_sh_min[col] = nmax(cols_sh_min[col], shw_min)
                if shw_max is not None:
                    has_bound_x = True
                    cols_sh_max[col] = nmin(cols_sh_max[col], shw_max)

            if shh is None:
                rows[row] = nmax(rows[row], h)
            else:
                rows_sh[row] = nmax(rows_sh[row], shh)
                if shh_min is not None:
                    has_bound_y = True
                    rows_sh_min[col] = nmax(rows_sh_min[col], shh_min)
                if shh_max is not None:
                    has_bound_y = True
                    rows_sh_max[col] = nmin(rows_sh_max[col], shh_max)
        self._has_hint_bound_x = has_bound_x
        self._has_hint_bound_y = has_bound_y
       
    def _iterate_layout(self, count):
        selfx = self.x
        padding_left = self.padding[0]
        padding_top = self.padding[1]
        spacing_x, spacing_y = self.spacing

        i = count - 1
        x = selfx + padding_left
        
        for col_width in self._cols:
            y = self.top - padding_top
            for row_height in self._rows:
                if i < 0:
                    break
                yield i, x, y - row_height, col_width, row_height
                i -=  1
                y -=  spacing_y + row_height
            x += col_width + spacing_x
            
# EXAMPLE OF USE    
class MainWindow(BoxLayout):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.orientation = 'vertical'
        self.layout = TBGridLayout(rows=5)
        self.add_widget(self.layout)
        
        self.cont = 0
        self.add_widget(Button(text='Add Button',
                               size_hint = (1,  0.15),  
                               on_press= self.add_button))

        
    def add_button(self,  instance):
        self.cont += 1
        self.layout.add_widget(Button(text = 'Button' + str(self.cont)))

class ExampleApp(App):
    def build(self):
        return MainWindow()

if __name__ == "__main__":
    ExampleApp().run()

运行 示例:

PD:该代码只是一个简单示例,它已经过测试但可能包含错误。

使用 GridLayout,但使用 BoxLayouts 而不是按钮来填充它。垂直定位这些 BoxLayout 中的每一个并填充其中的按钮。