Kivy:如何停止分散小部件重叠选项卡 headers
Kivy: How do I stop a scatter widget overlapping tab headers
Scatter 小部件位于 TabbedPanelItem 内容中。移动散点图 object 时,它会移动到所有选项卡 headers 上。我如何确保它移动到选项卡 headers 下?我知道小部件深度索引遵循添加小部件的顺序,但不明白如何在 Tab 小部件之前添加 Scatter 以避免这种情况?
问题图片:
分散小部件重叠选项卡headers
说明问题的代码(分散项为红色,在选项卡 1 上):
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
Builder.load_string("""
<TabbedTestScreen>:
TabbedPanel:
id: tab_panel
do_default_tab: False
tab_pos: 'left_top'
tab_height: 90
tab_width: 90
TabbedPanelItem:
text: '1'
BoxLayout:
size: self.size
pos: self.pos
Scatter:
canvas.after:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
auto_bring_to_front: False # this doesn't make any difference
center: self.parent.center
size: self.parent.size
do_rotation: False
do_translation: True
do_scale: True
Label:
text: 'Tab 1 scatter widget'
font_size: 20
center: self.parent.center
size: self.parent.size
TabbedPanelItem:
text: '2'
Label:
text: '2'
TabbedPanelItem:
text: '3'
id: home_tab
Label:
text: '3'
""")
class TabbedTestScreen(Screen):
def __init__(self, **kwargs):
super(TabbedTestScreen, self).__init__(**kwargs)
runTouchApp(TabbedTestScreen())
这不是一个完整的答案,但对于可以更进一步的人来说可能是一个开始。如果您使用自定义 Scatter
,例如:
class MyScatter(Scatter):
def on_pos(self, *args):
parent = self.parent
gparent = parent.parent
if gparent is None:
return
ggparent = gparent.parent
if ggparent is None:
return
num_children = len(ggparent.children)
ggparent.remove_widget(gparent)
ggparent.add_widget(gparent, num_children)
非常难看,还有一个我不明白的副作用(标签出现在右边)。但是 MyScatter
对象留在选项卡后面。
我认为问题与小部件排序有关。
Kivy 使用 widget 插入树的顺序为 z-index,(你总是默认添加 "on top"),布局和复杂的 widgets 也使用这个顺序作为位置指示,大多数时候这一切都很好,但有时不是,然后你有时需要奇怪的解决方法。
这就是这里发生的事情,TabbedPanel 有点神奇,headers 实际上都是 "before"(在下面)容器,并且由于您的内容可以超出预期区域,效果出乎你的意料。
我在这里建议的解决方案是使用 Stencil 实际上防止内容在其位置之外绘制任何东西。
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
Builder.load_string("""
<TabbedTestScreen>:
TabbedPanel:
id: tab_panel
do_default_tab: False
tab_pos: 'left_top'
tab_height: 90
tab_width: 90
TabbedPanelItem:
text: '1'
BoxLayout:
size: self.size
pos: self.pos
canvas.before:
StencilPush
Rectangle:
pos: self.pos
size: self.size
StencilUse
canvas.after:
StencilUnUse
Rectangle:
pos: self.pos
size: self.size
StencilPop
Scatter:
canvas.after:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
auto_bring_to_front: False # this doesn't make any difference
center: self.parent.center
size: self.parent.size
do_rotation: False
do_translation: True
do_scale: True
Label:
text: 'Tab 1 scatter widget'
font_size: 20
center: self.parent.width / 2, self.parent.height / 2
size: self.parent.size
TabbedPanelItem:
text: '2'
Label:
text: '2'
TabbedPanelItem:
text: '3'
id: home_tab
Label:
text: '3'
""")
class TabbedTestScreen(Screen):
def __init__(self, **kwargs):
super(TabbedTestScreen, self).__init__(**kwargs)
runTouchApp(TabbedTestScreen())
但是你仍然有一个问题,虽然它在相关地方正确地不可见,但散点图仍然处于活动状态并且可以被抓取,这使得界面混乱。
因此您还希望 BoxLayout 不关心其位置之外的触摸。
人们会认为像 StencilView 这样的东西可以做到这一点,但事实并非如此,所以您需要做一些工作。
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
from kivy.uix.stencilview import StencilView
from kivy.uix.boxlayout import BoxLayout
class StencilBox(StencilView, BoxLayout):
def on_touch_down(self, touch):
if not self.collide_point(*touch.pos):
return
return super(StencilBox, self).on_touch_down(touch)
def on_touch_move(self, touch):
if not self.collide_point(*touch.pos):
return
return super(StencilBox, self).on_touch_move(touch)
def on_touch_up(self, touch):
if not self.collide_point(*touch.pos):
return
return super(StencilBox, self).on_touch_up(touch)
Builder.load_string("""
<TabbedTestScreen>:
TabbedPanel:
id: tab_panel
do_default_tab: False
tab_pos: 'left_top'
tab_height: 90
tab_width: 90
TabbedPanelItem:
text: '1'
StencilBox:
size: self.size
pos: self.pos
Scatter:
canvas.after:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
auto_bring_to_front: False # this doesn't make any difference
center: self.parent.center
size: self.parent.size
do_rotation: False
do_translation: True
do_scale: True
Label:
text: 'Tab 1 scatter widget'
font_size: 20
center: self.parent.width / 2, self.parent.height / 2
size: self.parent.size
TabbedPanelItem:
text: '2'
Label:
text: '2'
TabbedPanelItem:
text: '3'
id: home_tab
Label:
text: '3'
""")
class TabbedTestScreen(Screen):
def __init__(self, **kwargs):
super(TabbedTestScreen, self).__init__(**kwargs)
runTouchApp(TabbedTestScreen())
(我还修复了一个标签位置不是相对的小问题,因为你在一个散点中,你需要使用相对于散点的坐标,而不是整个屏幕)。
希望对您有所帮助。
Scatter 小部件位于 TabbedPanelItem 内容中。移动散点图 object 时,它会移动到所有选项卡 headers 上。我如何确保它移动到选项卡 headers 下?我知道小部件深度索引遵循添加小部件的顺序,但不明白如何在 Tab 小部件之前添加 Scatter 以避免这种情况?
问题图片:
分散小部件重叠选项卡headers
说明问题的代码(分散项为红色,在选项卡 1 上):
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
Builder.load_string("""
<TabbedTestScreen>:
TabbedPanel:
id: tab_panel
do_default_tab: False
tab_pos: 'left_top'
tab_height: 90
tab_width: 90
TabbedPanelItem:
text: '1'
BoxLayout:
size: self.size
pos: self.pos
Scatter:
canvas.after:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
auto_bring_to_front: False # this doesn't make any difference
center: self.parent.center
size: self.parent.size
do_rotation: False
do_translation: True
do_scale: True
Label:
text: 'Tab 1 scatter widget'
font_size: 20
center: self.parent.center
size: self.parent.size
TabbedPanelItem:
text: '2'
Label:
text: '2'
TabbedPanelItem:
text: '3'
id: home_tab
Label:
text: '3'
""")
class TabbedTestScreen(Screen):
def __init__(self, **kwargs):
super(TabbedTestScreen, self).__init__(**kwargs)
runTouchApp(TabbedTestScreen())
这不是一个完整的答案,但对于可以更进一步的人来说可能是一个开始。如果您使用自定义 Scatter
,例如:
class MyScatter(Scatter):
def on_pos(self, *args):
parent = self.parent
gparent = parent.parent
if gparent is None:
return
ggparent = gparent.parent
if ggparent is None:
return
num_children = len(ggparent.children)
ggparent.remove_widget(gparent)
ggparent.add_widget(gparent, num_children)
非常难看,还有一个我不明白的副作用(标签出现在右边)。但是 MyScatter
对象留在选项卡后面。
我认为问题与小部件排序有关。
Kivy 使用 widget 插入树的顺序为 z-index,(你总是默认添加 "on top"),布局和复杂的 widgets 也使用这个顺序作为位置指示,大多数时候这一切都很好,但有时不是,然后你有时需要奇怪的解决方法。
这就是这里发生的事情,TabbedPanel 有点神奇,headers 实际上都是 "before"(在下面)容器,并且由于您的内容可以超出预期区域,效果出乎你的意料。
我在这里建议的解决方案是使用 Stencil 实际上防止内容在其位置之外绘制任何东西。
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
Builder.load_string("""
<TabbedTestScreen>:
TabbedPanel:
id: tab_panel
do_default_tab: False
tab_pos: 'left_top'
tab_height: 90
tab_width: 90
TabbedPanelItem:
text: '1'
BoxLayout:
size: self.size
pos: self.pos
canvas.before:
StencilPush
Rectangle:
pos: self.pos
size: self.size
StencilUse
canvas.after:
StencilUnUse
Rectangle:
pos: self.pos
size: self.size
StencilPop
Scatter:
canvas.after:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
auto_bring_to_front: False # this doesn't make any difference
center: self.parent.center
size: self.parent.size
do_rotation: False
do_translation: True
do_scale: True
Label:
text: 'Tab 1 scatter widget'
font_size: 20
center: self.parent.width / 2, self.parent.height / 2
size: self.parent.size
TabbedPanelItem:
text: '2'
Label:
text: '2'
TabbedPanelItem:
text: '3'
id: home_tab
Label:
text: '3'
""")
class TabbedTestScreen(Screen):
def __init__(self, **kwargs):
super(TabbedTestScreen, self).__init__(**kwargs)
runTouchApp(TabbedTestScreen())
但是你仍然有一个问题,虽然它在相关地方正确地不可见,但散点图仍然处于活动状态并且可以被抓取,这使得界面混乱。
因此您还希望 BoxLayout 不关心其位置之外的触摸。
人们会认为像 StencilView 这样的东西可以做到这一点,但事实并非如此,所以您需要做一些工作。
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
from kivy.uix.stencilview import StencilView
from kivy.uix.boxlayout import BoxLayout
class StencilBox(StencilView, BoxLayout):
def on_touch_down(self, touch):
if not self.collide_point(*touch.pos):
return
return super(StencilBox, self).on_touch_down(touch)
def on_touch_move(self, touch):
if not self.collide_point(*touch.pos):
return
return super(StencilBox, self).on_touch_move(touch)
def on_touch_up(self, touch):
if not self.collide_point(*touch.pos):
return
return super(StencilBox, self).on_touch_up(touch)
Builder.load_string("""
<TabbedTestScreen>:
TabbedPanel:
id: tab_panel
do_default_tab: False
tab_pos: 'left_top'
tab_height: 90
tab_width: 90
TabbedPanelItem:
text: '1'
StencilBox:
size: self.size
pos: self.pos
Scatter:
canvas.after:
Color:
rgba: 1,0,0,0.5
Rectangle:
size: self.size
pos: self.pos
auto_bring_to_front: False # this doesn't make any difference
center: self.parent.center
size: self.parent.size
do_rotation: False
do_translation: True
do_scale: True
Label:
text: 'Tab 1 scatter widget'
font_size: 20
center: self.parent.width / 2, self.parent.height / 2
size: self.parent.size
TabbedPanelItem:
text: '2'
Label:
text: '2'
TabbedPanelItem:
text: '3'
id: home_tab
Label:
text: '3'
""")
class TabbedTestScreen(Screen):
def __init__(self, **kwargs):
super(TabbedTestScreen, self).__init__(**kwargs)
runTouchApp(TabbedTestScreen())
(我还修复了一个标签位置不是相对的小问题,因为你在一个散点中,你需要使用相对于散点的坐标,而不是整个屏幕)。
希望对您有所帮助。