如何在Kivy设置中禁用某个部分?

时间:2018-05-31 14:31:17

标签: python-3.x kivy settings

我有一个带有设置的kivy应用,我希望为某些用户禁用某些设置(例如' General')。我试着走路了#39;通过设置的孩子(使用禁用的设置),但我似乎无法这样做。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.settings import SettingsWithSidebar
import json

settings_general = json.dumps([
    {'type': 'title',
     'title': 'Set general preferences'},
    {'type': 'bool',
     'title': 'Use widgets',
     'desc': 'Allow the use of widgets in the application',
     'section': 'general',
     'key': 'use widgets'},
    {'type': 'bool',
     'title': 'Print log',
     'desc': 'Print log on closing application',
     'section': 'general',
     'key': 'print log'}
     ])

settings_appearance = json.dumps([
    {'type': 'title',
     'title': 'Appearance preferences'},
    {'type': 'bool',
     'title': 'Use colour',
     'desc': 'Allow the use of colour in the application',
     'section': 'appearance',
     'key': 'use colour'}
     ])

class MainFrame(Screen):
    def __init__(self, **kwargs):
        super(MainFrame, self).__init__(**kwargs)
        pass

    def on_settings_button_click(self):
        settings = self.app.settings_cls
        print('type settings', type(settings))
        print('is SettingsWithSidebar', isinstance(settings, 
                                                   SettingsWithSidebar))
        self.app.open_settings()

    def on_quit_button_click(self):
        quit()

class Settings(object):
    def build_config(self, config):
        config.setdefaults('general',
            {
            'use widgets': 0,
            'print log': 0
            })
        config.setdefaults('appearance',
            {
            'use colour': 0
            })

    def build_settings(self, parent, settings):
        settings.add_json_panel('General',
                                parent.config,
                                data=settings_general)
        settings.add_json_panel('Appearance',
                                parent.config,
                                data=settings_appearance)

class BasicApp(App):
    def build(self):
        main_frame = MainFrame()
        main_frame.app = self
        self.settings_cls = SettingsWithSidebar
        self.use_kivy_settings = False
        return main_frame

    def build_config(self, config):
        self.settings = Settings()
        self.settings.build_config(config)

    def build_settings(self, settings):
        self.settings.build_settings(self, settings)

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

我的kv文件是:

<MainFrame>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: 'Settings'
            on_press: root.on_settings_button_click()
        Button:
            text: 'Click to close'
            on_press: root.on_quit_button_click()

有人可以建议我可以使用的方法吗?

[本节不需要阅读] 在我被允许发布之前我必须输入更多文本(我认为代码与文本的比例)。这似乎很遗憾,因为这个问题很简单,我想提供一个应用程序的基本工作示例,这个示例必然非常冗长。 [额外文字的结尾]

1 个答案:

答案 0 :(得分:1)

您可以使用disabled属性禁用面板中的项目。

settings_general = json.dumps([
    {'type': 'title',
     'title': 'Set general preferences'},
    {'type': 'bool',
     'disabled': True,
     'title': 'Use widgets',
     'desc': 'Allow the use of widgets in the application',
     'section': 'general',
     'key': 'use widgets'}])

此示例中禁用了第二项。

但是,我没有找到一种直观的方法来禁用整个Appearance部分。例如 所以我选择了一种hackery方法 首先是走settings小部件树,找到那个标签。

tab = list(self.app.settings.walk(loopback=True))[5]

在这种情况下,我发现标签是第6个元素 但仅将disable属性设置为True是不够的。它会标记掉标签,但它仍然可以点击它,因为它们使用了on_touch_down方法 所以我们可以覆盖on_touch_down方法 我在应用程序类中添加了一个切换到大型机和切换方法,以测试它。

<MainFrame>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: 'Settings'
            on_press: root.on_settings_button_click()
        Switch:
            on_active: app.toggle_setting(self.active)
        Button:
            text: 'Click to close'
            on_press: root.on_quit_button_click()

I found the original on_touch_down method here

def on_touch_down(touch, self):
        # we need to write this method to override back to the original method
        # the original method was found in kivy/uix/settings.py.
        # look at the link above
        if not self.collide_point(*touch.pos):
            return
        self.selected = True
        self.menu.selected_uid = self.uid

class MainFrame(Screen):

    def on_settings_button_click(self):
        self.app.open_settings()
        tab = list(self.app.settings.walk(loopback=True))[5]
        if not self.app.toggle:  # if switch is inactive
            tab.disabled = True
            tab.on_touch_down = lambda x: False
        else:
            tab.disabled = False
            # we need partial from functools, so we can pass the tab as self
            tab.on_touch_down  = partial(on_touch_down,self=tab)


    def on_quit_button_click(self):
        quit()

完整的代码:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.settings import SettingsWithSidebar
from kivy.lang import Builder
import json
from functools import partial

settings_general = json.dumps([
    {'type': 'title',
     'title': 'Set general preferences'},
    {'type': 'bool',
     'disabled': True,
     'title': 'Use widgets',
     'section': 'general',
     'key': 'use widgets'}
     ])

settings_appearance = json.dumps([
    {'type': 'title',
     'title': 'Appearance preferences'},
    {'type': 'bool',
     'title': 'Use colour',
     'section': 'appearance',
     'key': 'use colour'}
     ])


def on_touch_down(touch, self):
        if not self.collide_point(*touch.pos):
            return
        self.selected = True
        self.menu.selected_uid = self.uid

class MainFrame(Screen):

    def on_settings_button_click(self):
        self.app.open_settings()
        tab = list(self.app.settings.walk(loopback=True))[5]
        if not self.app.toggle:
            tab.disabled = True
            tab.on_touch_down = lambda x: False
        else:
            tab.disabled = False
            tab.on_touch_down  = partial(on_touch_down,self=tab)


    def on_quit_button_click(self):
        quit()


Builder.load_string("""
<MainFrame>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: 'Settings'
            on_press: root.on_settings_button_click()
        Switch:
            on_active: app.toggle_setting(self.active)
        Button:
            text: 'Click to close'
            on_press: root.on_quit_button_click()
""")

class BasicApp(App):
    toggle = False

    def build(self):
        self.main = MainFrame()
        self.main.app = self
        self.settings_cls = SettingsWithSidebar
        self.use_kivy_settings = False
        return self.main

    def build_config(self, config):
        self.config = config
        self.config.setdefaults('general',{'use widgets': 0,'print log': 0})
        self.config.setdefaults('appearance',{'use colour': 0})

    def build_settings(self, settings):
        self.settings = settings
        self.settings.add_json_panel('General', self.config, data=settings_general)
        self.settings.add_json_panel('Appearance', self.config, data = settings_appearance)

    def toggle_setting(self, active):
        self.toggle = active


BasicApp().run()