Я пытаюсь сделать что-то вроде макета «Bing images».
Это:
Я не нашел способа сделать это с помощью Stack Layout, поэтому решил создать свой собственный макет.
Я остановился здесь:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.properties import NumericProperty
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
KV = '''
#:import Window kivy.core.window.Window
ScrollView
size_hint: (1, None)
size: Window.size
MyLayout
id:my_l
Button
text:'1'
Button
size_hint_y: None
height: 900
text:'2'
Button
text:'3'
Button
text:'4'
Button
text:'5'
size_hint_y: None
height: 900
<MyLayout>:
#height: self.minimum_height
cols: 3
spacing: 10
size_hint_y:None
row_width: 300
'''
class MyLayout(FloatLayout):
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
cols = NumericProperty(3)
row_width = NumericProperty(300)
spacing = NumericProperty(0)
def do_layout(self, *args):
self.i = 0
self.last_x = [self.height]*self.cols
for child in self.children[::-1]:
child.width = self.row_width
if isinstance(child, Image):
child.height = child.width / child.image_ratio
child.size_hint_y= None
child.size_hint_x= None
self.i+=1
if self.i == self.cols+1: self.i = 1
child.x = self.x+(self.i-1)*(self.row_width+self.spacing)
child.y = self.last_x[self.i-1]-child.height
self.last_x[self.i-1]-=child.height+self.spacing
def on_pos(self, *args):
self.do_layout()
def on_size(self, *args):
self.do_layout()
def add_widget(self, widget):
super(SuperGrid, self).add_widget(widget)
self.do_layout()
def remove_widget(self, widget):
super(SuperGrid, self).remove_widget(widget)
self.do_layout()
class MyApp(App):
def build(self):
self.root = Builder.load_string(KV)
Window.bind(on_dropfile=self.add)
def add(self, *args):
name= list(args)[1]
self.root.ids.my_l.add_widget(Image(source=name))
MyApp().run()
Он уже частично работает (вы можете запустить его и перетащить некоторые изображения из своих папок, чтобы увидеть, о чем я), но проблема в том, что я не понимаю, как подключить к нему ScrollView.
Похоже, мне нужно добавить строку с чем-то вроде height: self.minimum_height в строку KV.
но непонятно, где в классе макета мне нужно рассчитывать minimum_height.
Как заставить код работать со ScrollView?
Кнопки только для примера. Не могли бы вы попробовать перетащить несколько изображений в приложение (и, возможно, удалить эти кнопки из строки KV), и станет ясно, как должен работать макет. Основная проблема в моем коде заключается в том, что я не знаю, как подключить этот макет к макету просмотра прокрутки, чтобы я мог прокручивать изображения.






Вам просто нужно рассчитать height вашего экземпляра MyLayout. В вашем файле kv добавьте:
size_hint: (1, None)
в вашем разделе MyLayout
Затем с помощью метода do_layout вычислите height вашего MyLayout. Сделайте self.height = только один раз в конце do_layout (чтобы избежать бесконечного цикла из-за метода on_size). Например, вот модифицированная версия вашего do_layout:
def do_layout(self, *args):
self.i = 0
col_heights = [0] * self.cols # keeps track of the height of each column
self.last_x = [self.height]*self.cols
for child in self.children[::-1]:
child.width = self.row_width
if isinstance(child, Image):
child.height = child.width / child.image_ratio
child.size_hint_y= None
child.size_hint_x= None
self.i+=1
if self.i == self.cols+1:
self.i = 1
col_heights[self.i-1] += child.height + self.spacing
child.x = self.x+(self.i-1)*(self.row_width+self.spacing)
child.y = self.last_x[self.i-1]-child.height
self.last_x[self.i-1]-=child.height+self.spacing
if len(self.children) > 0:
self.height = max(col_heights)
Я пробовал self.height = self.last_x [self.i-1] в конце метода do_layout, это вызывает критическое значение: слишком много итераций. Не могли бы вы проверить это в своей системе? Что случилось? size_hint: (1, None) уже используется, потому что у меня size_hint_y: None.
Я не понимаю, что такое ваш массив self.last_x, но оператор self.height = self.last_x[self.i-1] устанавливает высоту на отрицательное число. Установка self.height будет запускать метод on_size всякий раз, когда размер отличается от текущего размера. Ваш оператор запускает тот on_size, который вызывает do_layout, который вычисляет другой self.height, который запускает on_size ... до бесконечности. Я добавлю информацию к своему ответу выше.
Кроме того, size_hint_y: None или size_hint: (1, None) должны находиться непосредственно под MyLayout, а не под Button.
Для чего нужны все эти кнопки? Следует ли расположить изображения вокруг этих кнопок? Похоже на чехол для
GridLayout.