2

I want to implement the transition to a new Screen after clicking on the button and I want to do this through the function. I have this kv code

<ScreenFrame@BoxLayout>:
    orientation: 'vertical'
    cols: 3

    ActionBar:
        ActionView:
            pos_hint: {'top':1}
            use_separator: True
            ActionPrevious:
                title: "Title"
                with_previous: False
            ActionButton:
                text: "+"


    Label:
        text: "Content"


    BoxLayout:
        orientation: 'horizontal'
        cols: 4
        size_hint: 1, 0.15

        Button:
            text: "Notes"
            #don't work
            on_press: root.manager.current = 'nts'
        Button:
            text: "Docs"
            #don't work
            on_release: root.go_to_dcs()

        Button:
            text: "Videos"
            #don't work
            on_release: root.manager.current = "vds"
        Button:
            text: "Pictures"
            # don't work
            on_release: root.manager.current = 'pctrs'

<NtsScreen>:
    BoxLayout:
        orientation: "vertical"
        cols: 2

        ScreenFrame:
        Button:
            text: "f"
            #work, but me need implementaion through function
            on_press: root.manager.current = "vds"

<DocsScreen>:
    ScreenFrame:

<VdsScreen>:
    ScreenFrame:

<PctrsScreen>:
    ScreenFrame:

and this file

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.properties import StringProperty
from kivy.uix.widget import Widget


Builder.load_file("main.kv")

class ScreenFrame():
    def go_to_dcs(self):
        sm.current = "dcs"

class NtsScreen(Screen):
    pass

class DcsScreen(Screen):
    def go_to_dcs(self):
        sm.current = 'dcs'

class VdsScreen(Screen):
    pass

class PctrsScreen(Screen):
    pass


# Create the screen manager
sm = ScreenManager()
sm.add_widget(NtsScreen(name='nts'))
sm.add_widget(DcsScreen(name='dcs'))
sm.add_widget(VdsScreen(name='vds'))
sm.add_widget(PctrsScreen(name='pctrs'))


class MainApp(App):
    def build(self):
        return sm

if __name__ == "__main__":
    MainApp().run()

, but when i run and press Docs Button i have this error

 Traceback (most recent call last):
   File "main.py", line 45, in <module>
     MainApp().run()
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/app.py", line 826, in run
     runTouchApp()
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 502, in runTouchApp
     EventLoop.window.mainloop()
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/core/window/window_pygame.py", line 403, in mainloop
     self._mainloop()
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/core/window/window_pygame.py", line 289, in _mainloop
     EventLoop.idle()
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 340, in idle
     self.dispatch_input()
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 325, in dispatch_input
     post_dispatch_input(*pop(0))
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/base.py", line 291, in post_dispatch_input
     wid.dispatch('on_touch_up', me)
   File "kivy/_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/uix/behaviors/button.py", line 179, in on_touch_up
     self.dispatch('on_release')
   File "kivy/_event.pyx", line 703, in kivy._event.EventDispatcher.dispatch
   File "kivy/_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
   File "kivy/_event.pyx", line 1098, in kivy._event.EventObservers._dispatch
   File "/home/parvektor228/TAOKF/lib/python3.6/site-packages/kivy/lang/builder.py", line 64, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "/home/parvektor228/TAOKF/KivyApp/memfier/main.kv", line 32, in <module>
     on_release: root.go_to_dcs()
   File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
 AttributeError: 'ScreenFrame' object has no attribute 'go_to_dcs'

where is the error or can I something I do not understand?

A few more details so that the bug notification disappears. A few more details so that the bug notification disappears. A few more details so that the bug notification disappears.

2 Answers2

1

Your issue is occurring because ScreenFrame is a BoxLayout (according to your kv file), not a Screen. Therefore, the root that you call (in this case, ScreenFrame) does not have a manager associated with it. The manager is associated with the Screen itself.

You will have to reference the parent widget of the ScreenFrame widget in order to be referencing the current Screen, and it's associated manager. I would suggest restructuring your Python code and kv file as follows, for clarity:

Python code:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.widget import Widget

Builder.load_file("testthis.kv")

class ScreenFrame(BoxLayout):

    def go_to_screen(self, val):
        self.parent.manager.current = val

class NtsScreen(Screen):
    pass

class DcsScreen(Screen):
    pass

class VdsScreen(Screen):
    pass

class PctrsScreen(Screen):
    pass

class MyScreenManager(ScreenManager):
    pass

class MainApp(App):

    def build(self):
        self.sm = MyScreenManager()
        return self.sm

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

kv file:

<MyScreenManager>:
    NtsScreen:
        name: 'nts'
    DcsScreen:
        name: 'dcs'
    VdsScreen:
        name: 'vds'
    PctrsScreen:
        name: 'pctrs'

<NtsScreen>:
    ScreenFrame:

<DocsScreen>:
    ScreenFrame:

<VdsScreen>:
    ScreenFrame:

<PctrsScreen>:
    ScreenFrame:

<ScreenFrame>:

    orientation: 'vertical'
    rows: 3

    ActionBar:
        ActionView:
            pos_hint: {'top':1}
            use_separator: True
            ActionPrevious:
                title: "Title"
                with_previous: False
            ActionButton:
                text: "+"

    Label:
        text: "Content"

    BoxLayout:
        orientation: 'horizontal'
        cols: 4
        size_hint: 1, 0.15

        Button:
            text: "Notes"
            on_press: root.go_to_screen('nts')
        Button:
            text: "Docs"
            on_release: root.go_to_screen('dcs')
        Button:
            text: "Videos"
            on_release: root.go_to_screen('vds')
        Button:
            text: "Pictures"
            on_release: root.go_to_screen('pctrs')
rahlf23
  • 8,869
  • 4
  • 24
  • 54
1

Problem - AttributeErrors

There were two AttributeErrors and they are as follow:

AttributeError: go_to_dcs() method

     on_release: root.go_to_dcs()
   File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
 AttributeError: 'ScreenFrame' object has no attribute 'go_to_dcs'

In the kv file, a dynamic class, <ScreenFrame@BoxLayout>: was defined which does not have go_to_dcs() method implemented.

AttributeError: manager

     on_press: root.manager.current = 'nts'
   File "kivy/weakproxy.pyx", line 30, in kivy.weakproxy.WeakProxy.__getattr__
 AttributeError: 'ScreenFrame' object has no attribute 'manager'

The dynamic class, <ScreenFrame@BoxLayout>: has a BoxLayout inheritance but not a Screen inheritance. Therefore, it does not have a property called, manager.

Solution

kv file

  1. Replace dynamic class, <ScreenFrame@BoxLayout>: with class rule, <ScreenFrame>:
  2. In class rule, <ScreenFrame>: - Replace root.manager.current with app.root.current

Snippet

<ScreenFrame>:

        Button:
            text: "Notes"
            on_press: app.root.current = 'nts'
        Button:
            text: "Docs"
            on_release: root.go_to_dcs()    
        Button:
            text: "Videos"
            on_press: app.root.current = 'vds'
        Button:
            text: "Pictures"
            on_press: app.root.current = 'pctrs'

Kv language » Three Keywords

There are three keywords specific to Kv language:

app: always refers to the instance of your application.

root: refers to the base widget/template in the current rule

self: always refer to the current widget

Python Code

  1. Add import statement, from kivy.uix.boxlayout import BoxLayout
  2. Replace class ScreenFrame(): with class ScreenFrame(BoxLayout):

Example

main.py

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder


Builder.load_file("main.kv")


class ScreenFrame(BoxLayout):
    def go_to_dcs(self):
        print("\nScreenFrame.go_to_dcs")
        sm.current = "dcs"


class NtsScreen(Screen):
    pass


class DcsScreen(Screen):
    def go_to_dcs(self):
        sm.current = 'dcs'


class VdsScreen(Screen):
    pass


class PctrsScreen(Screen):
    pass


# Create the screen manager
sm = ScreenManager()
sm.add_widget(NtsScreen(name='nts'))
sm.add_widget(DcsScreen(name='dcs'))
sm.add_widget(VdsScreen(name='vds'))
sm.add_widget(PctrsScreen(name='pctrs'))


class MainApp(App):
    def build(self):
        return sm


if __name__ == "__main__":
    MainApp().run()

main.kv

#:kivy 1.11.0

<ScreenFrame>:
    orientation: 'vertical'
    cols: 3

    ActionBar:
        ActionView:
            pos_hint: {'top':1}
            use_separator: True
            ActionPrevious:
                title: "Title"
                with_previous: False
            ActionButton:
                text: "+"


    Label:
        text: "Content"


    BoxLayout:
        orientation: 'horizontal'
        cols: 4
        size_hint: 1, 0.15

        Button:
            text: "Notes"
            on_press: app.root.current = 'nts'

        Button:
            text: "Docs"
            on_release: root.go_to_dcs()

        Button:
            text: "Videos"
            on_press: app.root.current = 'vds'

        Button:
            text: "Pictures"
            on_press: app.root.current = 'pctrs'

<NtsScreen>:
    BoxLayout:
        orientation: "vertical"
        cols: 2

        ScreenFrame:
        Button:
            text: "f"
            #work, but me need implementaion through function
            on_press: root.manager.current = "vds"

<DcsScreen>:
    ScreenFrame:

<VdsScreen>:
    ScreenFrame:

<PctrsScreen>:
    ScreenFrame:

Output

Img01 - App Startup Img02 - Videos Screen Img03 - Dcs Screen

ikolim
  • 15,721
  • 2
  • 19
  • 29
  • hi, you know why is black window when press on Docs Button? –  Aug 01 '18 at 14:26
  • The black screen for ***screen name="dcs"*** was due to class name mismatched. In Python code, it is `class DcsScreen(Screen)` but in kv file, it is `:`. Updated post by replacing class rule, `:` with `:` in kv file. – ikolim Aug 01 '18 at 16:46