带有 FloatLayout 的 Kivy Scrollview 将自身定位在屏幕底部
Kivy Scrollview with FloatLayout Is Positioning itself at the bottom of the screen
总而言之,该程序获取了一堆列表数据并填充了一行来描述一个带有一些附加操作的任务。
经过大量工作后,我让 scrollview 在某种程度上使用了 Floatlayout。问题是标签行列表卡在屏幕底部,如屏幕截图所示。当您 运行 代码时,将光标放在屏幕的最底部并向下滚动。小部件将出现并滚动(耶)。然后你就会遇到我的两个问题
- 为什么小部件在视图之外启动
- 为什么布局卡在底部。
我正在研究如何使浮动布局距屏幕顶部 12/15,并使小部件从一开始就在框架中。
enter image description here
import kivy
kivy.require('2.1.0') # replace with your current kivy version !
from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'systemanddock')
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ListProperty, ObjectProperty
from kivy.factory import Factory
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from os import path, getcwd
from datetime import date, timedelta, datetime
from calendar import monthrange
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta
class MainScreen(Screen):
headings = ['Bucket', 'Description', 'Due Date', 'Priority', 'Repeat', 'Person', 'Complete']
lst = [['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None']]
#all
lst_widgets = []
filtercomplete = 0
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
def on_enter(self):
self.InitialiseWidgets()
# Draw all widgets on screen
def InitialiseWidgets(self):
self.clear_widgets()
self.WidgetScroller()
self.WidgetTable()
def WidgetScroller(self):
scrlv = ScrollView(size_hint=(1,None), do_scroll_x = False)
self.layout = FloatLayout(size_hint=(1, None), size=(Window.width, Window.height))
scrlv.add_widget(self.layout)
self.add_widget(scrlv)
def WidgetTable(self):
num_headings = len(self.headings)
row_data = []
self.tabledata = []
y_pos = 12/15
if len(self.lst) != 0: # if list is not empty
for x in range(len(self.lst)): # for each task in list
x_pos = 0/10
for y in range(num_headings): # for each property of task
if y == self.headings.index('Complete'):
if self.filtercomplete == 1: # if filtering by completed,
row_data.append(Label(text = " ", size_hint = (1/20, 1/15), pos_hint = {'x':8/10, 'top':y_pos})) # do not add finish button
else:
row_data.append(Button(text = "FINISH", size_hint = (1/20, 1/15), pos_hint = {'x':8/10, 'top':y_pos})) # else add finish button
else:
print(self.lst[x][y])
row_data.append(Label(text = self.lst[x][y], size_hint = (1/10, 1/15), pos_hint = {'x':x_pos, 'top':y_pos})) # create label for task properties
if y == 1:
x_pos = x_pos + 3/10
else:
x_pos = x_pos + 1/10
row_data.append(Button(text = "PUSH", size_hint = (1/20, 1/15), pos_hint = {'x':8.5/10, 'top':y_pos})) # Action buttons
row_data.append(Button(text = "EDIT", size_hint = (1/20, 1/15), pos_hint = {'x':9/10, 'top':y_pos}))
row_data.append(Button(text = "DEL", size_hint = (1/20, 1/15), pos_hint = {'x':9.5/10, 'top':y_pos}))
y_pos = y_pos - 1/15
self.tabledata.append(row_data.copy())
row_data *= 0
# Draw widgets
for widget_row in self.tabledata:
for widget in widget_row:
self.layout.add_widget(widget)
class MyApp(App):
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
return sm
if __name__ == '__main__':
MyApp().run()
您的问题:
- 小部件位于初始视图之外,因为您开始使用
pos_hint
或 {'y': 12/15}
定位小部件。这将最大的 y
pos_hint
设置为 0.8
,然后从那里减少它。所以 0.8
上面的布局是空的。此外,您的 ScrollView
已针对 y
将 size_hint
设置为 None
。这导致 100
的默认值用作其 height
,因此只有布局的顶部 100
像素可以适合。
- wigets 的默认
pos
是 [0,0]
。由于您没有设置 ScrollView
的位置,它将获得默认的 pos
.
我建议使用 Layout
,它可以为您完成很多工作。也许 GridLayout
。您可以使用 kv
定义 MainScreen
的外观。这里有一个 kv
可以做到这一点:
<MainScreen>:
ScrollView:
do_scroll_x: False
pos_hint: {'top': 0.75}
size_hint: 1, 0.5
GridLayout:
id: grid
cols: 10
size_hint_y: None # required to allow automatice size adjustment
row_default_height: 50 # each row in the GridLayout will be given at least 50 pixels
height: self.minimum_height # the GridLayout will adjust its size as needed
如果您在创建 MainScreen()
之前加载上面的 kv
,那么您可以简化 MainScreen
class 的 py
代码:
class MainScreen(Screen):
headings = ['Bucket', 'Description', 'Due Date', 'Priority', 'Repeat', 'Person', 'Complete']
lst = [['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None']]
#all
lst_widgets = []
filtercomplete = 0
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.widgets_drawn = False
def on_enter(self):
if not self.widgets_drawn:
self.InitialiseWidgets()
self.widgets_drawn = True
# Draw all widgets on screen
def InitialiseWidgets(self):
# self.clear_widgets()
# self.WidgetScroller()
self.WidgetTable()
# def WidgetScroller(self):
#
# self.scrlv = ScrollView(size_hint=(1,None), do_scroll_x = False, pos_hint={'top': 0.75})
# self.layout = FloatLayout(size_hint=(1, None), size=(Window.width, Window.height))
# self.scrlv.add_widget(self.layout)
# self.add_widget(self.scrlv)
def WidgetTable(self):
self.layout = self.ids.grid # this is the GridLayout
num_headings = len(self.headings)
row_data = []
self.tabledata = []
if len(self.lst) != 0: # if list is not empty
for x in range(len(self.lst)): # for each task in list
for y in range(num_headings): # for each property of task
if y == self.headings.index('Complete'):
if self.filtercomplete == 1: # if filtering by completed,
row_data.append(Label(text = " ", size_hint = (1/20, None))) # do not add finish button
else:
row_data.append(Button(text = "FINISH", size_hint = (1/20, None))) # else add finish button
else:
print(self.lst[x][y])
row_data.append(Label(text = self.lst[x][y], size_hint = (1/10, None))) # create label for task properties
row_data.append(Button(text = "PUSH", size_hint = (1/20, None))) # Action buttons
row_data.append(Button(text = "EDIT", size_hint = (1/20, None)))
row_data.append(Button(text = "DEL", size_hint = (1/20, None)))
self.tabledata.append(row_data.copy())
row_data *= 0
# Draw widgets
for widget_row in self.tabledata:
for widget in widget_row:
self.layout.add_widget(widget)
请注意,所有位置信息都已从创建的 Buttons
和 Labels
中删除,因为 GridLayout
会处理这些信息。
另一件需要注意的事情是,您正在使用 on_enter()
来触发小部件绘制。每次你 enter
MainScreen
时都会触发,所以我添加了一个 widgets_drawn
属性以避免每次输入 MainScreen
时添加相同的小部件。
总而言之,该程序获取了一堆列表数据并填充了一行来描述一个带有一些附加操作的任务。
经过大量工作后,我让 scrollview 在某种程度上使用了 Floatlayout。问题是标签行列表卡在屏幕底部,如屏幕截图所示。当您 运行 代码时,将光标放在屏幕的最底部并向下滚动。小部件将出现并滚动(耶)。然后你就会遇到我的两个问题
- 为什么小部件在视图之外启动
- 为什么布局卡在底部。
我正在研究如何使浮动布局距屏幕顶部 12/15,并使小部件从一开始就在框架中。
enter image description here
import kivy
kivy.require('2.1.0') # replace with your current kivy version !
from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'systemanddock')
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ListProperty, ObjectProperty
from kivy.factory import Factory
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from os import path, getcwd
from datetime import date, timedelta, datetime
from calendar import monthrange
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta
class MainScreen(Screen):
headings = ['Bucket', 'Description', 'Due Date', 'Priority', 'Repeat', 'Person', 'Complete']
lst = [['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None']]
#all
lst_widgets = []
filtercomplete = 0
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
def on_enter(self):
self.InitialiseWidgets()
# Draw all widgets on screen
def InitialiseWidgets(self):
self.clear_widgets()
self.WidgetScroller()
self.WidgetTable()
def WidgetScroller(self):
scrlv = ScrollView(size_hint=(1,None), do_scroll_x = False)
self.layout = FloatLayout(size_hint=(1, None), size=(Window.width, Window.height))
scrlv.add_widget(self.layout)
self.add_widget(scrlv)
def WidgetTable(self):
num_headings = len(self.headings)
row_data = []
self.tabledata = []
y_pos = 12/15
if len(self.lst) != 0: # if list is not empty
for x in range(len(self.lst)): # for each task in list
x_pos = 0/10
for y in range(num_headings): # for each property of task
if y == self.headings.index('Complete'):
if self.filtercomplete == 1: # if filtering by completed,
row_data.append(Label(text = " ", size_hint = (1/20, 1/15), pos_hint = {'x':8/10, 'top':y_pos})) # do not add finish button
else:
row_data.append(Button(text = "FINISH", size_hint = (1/20, 1/15), pos_hint = {'x':8/10, 'top':y_pos})) # else add finish button
else:
print(self.lst[x][y])
row_data.append(Label(text = self.lst[x][y], size_hint = (1/10, 1/15), pos_hint = {'x':x_pos, 'top':y_pos})) # create label for task properties
if y == 1:
x_pos = x_pos + 3/10
else:
x_pos = x_pos + 1/10
row_data.append(Button(text = "PUSH", size_hint = (1/20, 1/15), pos_hint = {'x':8.5/10, 'top':y_pos})) # Action buttons
row_data.append(Button(text = "EDIT", size_hint = (1/20, 1/15), pos_hint = {'x':9/10, 'top':y_pos}))
row_data.append(Button(text = "DEL", size_hint = (1/20, 1/15), pos_hint = {'x':9.5/10, 'top':y_pos}))
y_pos = y_pos - 1/15
self.tabledata.append(row_data.copy())
row_data *= 0
# Draw widgets
for widget_row in self.tabledata:
for widget in widget_row:
self.layout.add_widget(widget)
class MyApp(App):
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
return sm
if __name__ == '__main__':
MyApp().run()
您的问题:
- 小部件位于初始视图之外,因为您开始使用
pos_hint
或{'y': 12/15}
定位小部件。这将最大的y
pos_hint
设置为0.8
,然后从那里减少它。所以0.8
上面的布局是空的。此外,您的ScrollView
已针对y
将size_hint
设置为None
。这导致100
的默认值用作其height
,因此只有布局的顶部100
像素可以适合。 - wigets 的默认
pos
是[0,0]
。由于您没有设置ScrollView
的位置,它将获得默认的pos
.
我建议使用 Layout
,它可以为您完成很多工作。也许 GridLayout
。您可以使用 kv
定义 MainScreen
的外观。这里有一个 kv
可以做到这一点:
<MainScreen>:
ScrollView:
do_scroll_x: False
pos_hint: {'top': 0.75}
size_hint: 1, 0.5
GridLayout:
id: grid
cols: 10
size_hint_y: None # required to allow automatice size adjustment
row_default_height: 50 # each row in the GridLayout will be given at least 50 pixels
height: self.minimum_height # the GridLayout will adjust its size as needed
如果您在创建 MainScreen()
之前加载上面的 kv
,那么您可以简化 MainScreen
class 的 py
代码:
class MainScreen(Screen):
headings = ['Bucket', 'Description', 'Due Date', 'Priority', 'Repeat', 'Person', 'Complete']
lst = [['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None'],
['None','','29-May-2022','Low','None','None']]
#all
lst_widgets = []
filtercomplete = 0
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.widgets_drawn = False
def on_enter(self):
if not self.widgets_drawn:
self.InitialiseWidgets()
self.widgets_drawn = True
# Draw all widgets on screen
def InitialiseWidgets(self):
# self.clear_widgets()
# self.WidgetScroller()
self.WidgetTable()
# def WidgetScroller(self):
#
# self.scrlv = ScrollView(size_hint=(1,None), do_scroll_x = False, pos_hint={'top': 0.75})
# self.layout = FloatLayout(size_hint=(1, None), size=(Window.width, Window.height))
# self.scrlv.add_widget(self.layout)
# self.add_widget(self.scrlv)
def WidgetTable(self):
self.layout = self.ids.grid # this is the GridLayout
num_headings = len(self.headings)
row_data = []
self.tabledata = []
if len(self.lst) != 0: # if list is not empty
for x in range(len(self.lst)): # for each task in list
for y in range(num_headings): # for each property of task
if y == self.headings.index('Complete'):
if self.filtercomplete == 1: # if filtering by completed,
row_data.append(Label(text = " ", size_hint = (1/20, None))) # do not add finish button
else:
row_data.append(Button(text = "FINISH", size_hint = (1/20, None))) # else add finish button
else:
print(self.lst[x][y])
row_data.append(Label(text = self.lst[x][y], size_hint = (1/10, None))) # create label for task properties
row_data.append(Button(text = "PUSH", size_hint = (1/20, None))) # Action buttons
row_data.append(Button(text = "EDIT", size_hint = (1/20, None)))
row_data.append(Button(text = "DEL", size_hint = (1/20, None)))
self.tabledata.append(row_data.copy())
row_data *= 0
# Draw widgets
for widget_row in self.tabledata:
for widget in widget_row:
self.layout.add_widget(widget)
请注意,所有位置信息都已从创建的 Buttons
和 Labels
中删除,因为 GridLayout
会处理这些信息。
另一件需要注意的事情是,您正在使用 on_enter()
来触发小部件绘制。每次你 enter
MainScreen
时都会触发,所以我添加了一个 widgets_drawn
属性以避免每次输入 MainScreen
时添加相同的小部件。