Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add for each screen an own .py and .kv file?

Tags:

python

kivy

I want to have a seperate .py and .kv file for each sreen. Over the ScreenManager in main.py/main.kv the screen should be selected. The design should be loaded from the file screen_X.kv and the classes etc. should be loaded from the file screen_X.py.

Screens:

  • Screen 1
  • Screen 2
  • Screen 3

Files:

  • (main.py)
  • (showcase.kv)
  • screen_1.py
  • screen_1.kv
  • screen_2.py
  • screen_2.kv
  • screen_3.py
  • screen_3.kv

This makes the program can be easily extended. How can I achieve this?


With this code I have seperated .kv files. But I need also separated .py files.

main.py

from time import time
from kivy.app import App
from os.path import dirname, join
from kivy.lang import Builder
from kivy.properties import NumericProperty, BooleanProperty, ListProperty
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen


class ShowcaseScreen(Screen):
    fullscreen = BooleanProperty(False)

    def add_widget(self, *args):
        if 'content' in self.ids:
            return self.ids.content.add_widget(*args)
        return super(ShowcaseScreen, self).add_widget(*args)


class ShowcaseApp(App):
    time = NumericProperty(0)
    screen_names = ListProperty([])
    bool_menu = BooleanProperty(False)

    def build(self):
        self.title = 'hello world'
        Clock.schedule_interval(self._update_clock, 1 / 60.)
        self.available_screens = [
            'Buttons', 'CheckBoxes', 'ProgressBar', 'Switches', 'ToggleButton',
        ]
        self.screen_names = self.available_screens
        curdir = dirname(__file__)
        self.available_screens = [join(curdir, 'data', 'screens', '{}.kv'.format(fn)) for fn in self.available_screens]

        self.menu_screen = join(curdir, 'data', 'screens', '{}.kv'.format('Menu'))

        self.go_menu()

    def go_screen(self, idx):
        screen = Builder.load_file(self.available_screens[idx])
        self.root.ids.sm.switch_to(screen, direction='left')

    def go_menu(self):
        if not self.bool_menu:
            screen = Builder.load_file(self.menu_screen)
            self.root.ids.sm.switch_to(screen, direction='right')

    def _update_clock(self, dt):
        self.time = time()

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

showcase.kv

#:kivy 1.8.0
#:import KivyLexer kivy.extras.highlight.KivyLexer
#:import Factory kivy.factory.Factory

<ActionSpinnerOptions@SpinnerOption>
    background_color: .4, .4, .4, 1

<ActionSpinner@Spinner+ActionItem>
    canvas.before:
        Color:
            rgba: 0.128, 0.128, 0.128, 1
        Rectangle:
            size: self.size
            pos: self.pos
    border: 27, 20, 12, 12
    background_normal: 'atlas://data/images/defaulttheme/action_group'
    option_cls: Factory.ActionSpinnerOptions

<ActionDropdown>:
    on_size: self.width = '220dp'

<ShowcaseScreen>:
    ScrollView:
        do_scroll_x: False
        do_scroll_y: False if root.fullscreen else (content.height > root.height - dp(16))
        AnchorLayout:
            size_hint_y: None
            height: root.height if root.fullscreen else max(root.height, content.height)
            GridLayout:
                id: content
                cols: 1
                spacing: '8dp'
                padding: '8dp'
                size_hint: (1, 1) if root.fullscreen else (.8, None)
                height: self.height if root.fullscreen else self.minimum_height


BoxLayout:
    orientation: 'vertical'

    canvas.before:
        Color:
            rgb: .6, .6, .6
        Rectangle:
            size: self.size
            source: 'data/background.png'

    ActionBar:

        ActionView:
            id: av
            ActionPrevious:
                with_previous: (False if app.bool_menu == True else True) if not app.bool_menu else False
                title: 'Menu'
                on_release: app.go_menu()

            ActionSpinner:
                id: spnr
                important: True
                text: 'Select Program'
                values: app.screen_names
                on_text:
                    if (spnr.text != 'Select Program') and (sm.current != args[1]):\
                    idx = app.screen_names.index(args[1]);\
                    app.go_screen(idx)

    ScreenManager:
        id: sm
        on_current_screen:
            screen_name = args[1].name

            spnr.text = 'Select Program' if screen_name == 'Menu' else screen_name

            if screen_name == 'Menu': app.bool_menu = True
            else: app.bool_menu = False
like image 228
user2534685 Avatar asked Aug 19 '15 18:08

user2534685


1 Answers

First of all, you haven't mentioned whether you know how to set up different screens the usual way, and I'm not sure that I see it in the code above. In case you don't, there is a fairly simple tutorial here on creating a simple multi-screen setup.

Each screen being a class that inherits from Screen, it isn't a difficult thing to just define those screen classes in seperate .py files and then import them into your main.py file. I have done this before. For instance, I had my main.py(which you need), and I had all my various screens defined in a py file called 'game_screen.py', and simply imported from there.

I haven't seen much use of multiple kv files myself, but I know you can add kv rules to your main(default) kv files rules using similar code to the below. Though these rules, I believe, must be loaded before the widgets they will effect in order to work correctly.

from kivy.lang import Builder
Builder.load_file('screen1.kv')
Builder.load_file('screen2.kv')
Builder.load_file('screen3.kv')

So by importing your screen classes to your main.py and using the above method of adding kv files, you could probably achieve what you are asking for.. and then decide if that's a good way to go.

like image 61
Totem Avatar answered Nov 11 '22 16:11

Totem