在Kivy中动态控制TabbedPanel

时间:2018-10-17 00:21:33

标签: python kivy

我想一开始就不显示TabbedPannel,

然后当完成某些任务时,我想在此之后显示选项卡。

enter image description here

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder

Builder.load_string("""

<Test>:
    size_hint: .5, .5
    pos_hint: {'center_x': .5, 'center_y': .5}
    do_default_tab: False

    TabbedPanelItem:
        text: 'first tab'
        Label:
            text: 'First tab content area'
    TabbedPanelItem:
        text: 'tab2'
        BoxLayout:
            Label:
                text: 'Second tab content area'
            Button:
                text: 'Button that does nothing'
    TabbedPanelItem:
        text: 'tab3'
        RstDocument:
            text:
                '\\n'.join(("Hello world", "-----------",
                "You are in the third tab."))

""")


class Test(TabbedPanel):
    pass


class TabbedPanelApp(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    TabbedPanelApp().run()

上面的代码来自Kivy Document

我想做的是

  1. 隐藏标签页(也可以防止移动标签页)
  2. 完成某些操作后,将选项卡从屏幕外部向下滑动。

有什么主意吗?

1 个答案:

答案 0 :(得分:1)

听起来像是一个有趣的小挑战,所以这就是我想出的:

'''
TabbedPanel
============

Test of the widget TabbedPanel.
'''
from kivy.animation import Animation
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelStrip
from kivy.lang import Builder


class Test(TabbedPanel):

    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)
        self.initialTabHeight = None
        self.myTabsList = None
        self.start_top = None
        self.tabs_showing = True

        # this TabbedPanelStrip will be a copy of the real one (self._tab_strip)
        self.tmp_tab_strip = TabbedPanelStrip(
            tabbed_panel=self,
            rows=1, size_hint=(None, None),
            height=self.tab_height, width=self.tab_width)

        # this is the movable Widget that contains the tabs
        self.movable_tab_strip = ScrollView(size_hint=(None, None), height=self.tab_height)

        # These value are needed to set the width of self.movable_tab_strip, but
        # they aren't always available when self.first is called below
        self._tab_strip.bind(width=self.tab_strip_width_changed)
        self.bind(width=self.panel_width_changed)

        Clock.schedule_once(self.first)

    def tab_strip_width_changed(self, instance, new_width):
        self.movable_tab_strip.width = min(self.tmp_tab_strip.width, self.width)

    def panel_width_changed(self, instance, new_width):
        self.movable_tab_strip.width = min(self.tmp_tab_strip.width, self.width)

    def first(self, *args):
        # show tab2, so that the Button will be available
        self.switch_to(self.parent.ids.tab2)

        # save some info
        self.initialTabHeight = self.tab_height
        self.myTabsList = self.tab_list.copy()

        tsw = 0
        for tab in self.myTabsList:
            if tab.size_hint_x:
                tsw += 100
            else:
                tsw += tab.width
        self.tmp_tab_strip.width = tsw
        self.movable_tab_strip.add_widget(self.tmp_tab_strip)

        # actually remove the tabs
        self.do_clear_widgets()

    def do_clear_widgets(self, *args):
        # eliminate the tabs and populate the moveable_tab_strip
        #self.movable_tab_strip.width = min(self.tmp_tab_strip.width, self.width)
        self.tab_height = 0
        self.clear_tabs()
        for tab in reversed(self.myTabsList):
            self.tmp_tab_strip.add_widget(tab)
        self.tabs_showing = False

    def do_progress(self, animation, widget, progression):
        # grow the tab height when the moveable_tab_strip impinges on the TabbedPanel
        # this has the effect of appearing to shrink the TappedPanel to the size it will have when the tabs are replaced
        if self.start_top > self.movable_tab_strip.y:
            self.tab_height = self.start_top - self.movable_tab_strip.y

    def do_replace_tabs(self, *args):
        # replace the moveable_tab_trip with the actual tabs
        self.tmp_tab_strip.clear_widgets()
        for tab in reversed(self.myTabsList):
            self.add_widget(tab)
        self.tab_height = self.initialTabHeight
        self.parent.remove_widget(self.movable_tab_strip)

    def do_tab_toggle(self, *args):
        if self.tabs_showing:
            self.do_clear_widgets()
        else:
            self.anim = Animation(pos=(self.x+2, self.y + self.height - self.movable_tab_strip.height))
            self.movable_tab_strip.pos = (self.x + 2, App.get_running_app().root_window.height)
            self.start_top = self.top
            self.parent.add_widget(self.movable_tab_strip)
            self.anim.bind(on_progress=self.do_progress)
            self.anim.bind(on_complete=self.do_replace_tabs)
            self.anim.start(self.movable_tab_strip)
            self.tabs_showing = True


class MyLayout(FloatLayout):
    pass


theRoot = Builder.load_string("""

MyLayout:
    Test:
        id: thePanel
        size_hint: .5, .5
        pos_hint: {'center_x': .5, 'center_y': .5}
        do_default_tab: False

        TabbedPanelItem:
            text: 'first tab'
            Label:
                id: theLabel
                text: 'First tab content area'
        TabbedPanelItem:
            id: tab2
            text: 'tab2'
            BoxLayout:
                Label:
                    text: 'Second tab content area'
                Button:
                    text: 'Button that does something'
                    on_press: thePanel.do_tab_toggle()
        TabbedPanelItem:
            id: tab3
            text: 'tab3'
            RstDocument:
                text:
                    '\\n'.join(("Hello world", "-----------",
                    "You are in the third tab."))
        TabbedPanelItem:
            text: 'tab4'
            Label:
                text: 'This is Tab4'
        TabbedPanelItem:
            id:tab5
            text: 'tab5'
            Label:
                text: 'This is Tab5'

""")


class TabbedPanelApp(App):
    def build(self):
        return theRoot

if __name__ == '__main__':
    TabbedPanelApp().run()

这个想法是创建一个“可移动的”标签栏,并用TabbedPanel中的实际标签填充它,然后对该标签栏进行动画处理。我更改了kv语言字符串,将整个内容放入FloatLayout中(我认为这使Animation更加容易)。以前没有执行任何操作的Button现在可以切换选项卡。在do_tab_toggle()方法中,我将可移动的标签条的x位置设置为TabbedPanel的x位置加2。2是一个软键,我无法确定为什么。是必需的,对于其他TabbedPanel实例可能有所不同。 do_tab_toggle()的“删除”部分也可以设置动画,但这留给读者练习:-)

其他选项是简单地使用clear_tabs()方法清除选项卡,或为tab_height的{​​{1}}属性设置动画(将高度设置为零以隐藏选项卡)。 / p>

编辑:添加了一对绑定来捕获在调用TabbedPanel方法时无法可靠获得的数据。