kivy adding attribute manager to a tabbedpanelitem - python

I'm trying to have a a screen inside a tabbed panels "space".
When i try to switch between screens, i get an AttributeError:
"AttributeError: 'TabbedTest' object has no attribute 'manager'"
I'm not sure how to add the screenmanager to the tabbedpanels attributes.
I'm unsure of how i create a reference to the tabbedpanel in the screenmanager or how i add the property.
Pythonfile
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.floatlayout import FloatLayout
class TabbedTest(TabbedPanel):
pass
class MainScreen(Screen):
pass
class Firstscreen(Screen):
pass
class myapp(App):
def build(self):
root = FloatLayout()
self.tabbedtest = TabbedTest()
root.add_widget(self.tabbedtest)
# Create the screen manager
self.sm = ScreenManager()
self.sm.add_widget(MainScreen(name='main'))
self.sm.add_widget(Firstscreen(name='first'))
root.add_widget(self.sm)
return root
if __name__ == '__main__':
myapp().run()
my.kv
<TabbedTest>
do_default_tab: False
TabbedPanelItem:
text:"test"
MainScreen:
Button:
text: 'first'
on_press: root.manager.current = 'first' #Problemarea
<Firstscreen>:
BoxLayout:
Label:
text:"first"
Button:
text: 'Back to main'
on_press: root.manager.current = 'main'

If you want the Screens inside the TabbedPanelItem, then you should put the ScreenManager inside the TabbedPanelItem. Here is a modified version of your kv that does that:
<TabbedTest>
do_default_tab: False
TabbedPanelItem:
text:"test"
ScreenManager:
id: manager # for easy access
MainScreen:
name: 'main'
Button:
text: 'first'
on_press: manager.current = 'first' # use manager id
Firstscreen:
name: 'first'
<Firstscreen>:
BoxLayout:
Label:
text:"first"
Button:
text: 'Back to main'
on_press: root.manager.current = 'main'
Then your build() method can be simply:
def build(self):
return TabbedTest()

Related

kivy button calls method of another class

I have a simple problem which keeps me busy in the last days.
In Kivy I have two Windows.
FirstWindow has a method update(), which is triggered by a button press.
On SecondWindow I have only one button, which sends me back to FirsWindow, but I want it to trigger the update() method from FirstWindow and change the label, just like the "update label" button does on FirstWindow, without previously pressing the "update label" button.
Any help, please?
file.py
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, ReferenceListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
my_button = ObjectProperty(None)
my_label = ObjectProperty(None)
def update(self):
self.my_label.text = 'UPDATED'
class SecondWindow(Screen):
def go_first(self):
FirstWindow().update()
class WindowManager(ScreenManager):
pass
class MyTestApp(App):
def build(self):
return Builder.load_file('my_test.kv')
MyTestApp().run()
my_test.kv
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
my_label: my_label_id
BoxLayout:
Label:
id: my_label_id
text:"Label"
font_size:self.width / 5
BoxLayout:
orientation: "vertical"
Button:
text: "next screen"
on_press: root.manager.current = 'second'
Button:
text: "update label"
on_press: root.update()
<SecondWindow>:
name:"second"
Button:
text: "go back and update"
on_press:
root.manager.current = 'first'
root.go_first()
I think critical is this method, whitch needs to be remake, but I have no idea how
def go_first(self):
FirstWindow().update()
You can't directly access another screen which is defined as another class. First, you have to access the ScreenManager i.e. Parent class and then from it get the screen FirstScreen
So the go_first function in your code will look like this:
def go_first(self):
self.parent.get_screen('first').update()
EDIT:
Here's full code:
main.py:
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, ReferenceListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
my_button = ObjectProperty(None)
my_label = ObjectProperty(None)
def update(self):
self.my_label.text = 'UPDATED'
class SecondWindow(Screen):
def go_first(self):
self.parent.get_screen('first').update()
class WindowManager(ScreenManager):
pass
class MyTestApp(App):
def build(self):
return Builder.load_file('my.kv')
MyTestApp().run()
my.kv:
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
my_label: my_label_id
BoxLayout:
Label:
id: my_label_id
text:"Label"
font_size:self.width / 5
BoxLayout:
orientation: "vertical"
Button:
text: "next screen"
on_press: root.manager.current = 'second'
Button:
text: "update label"
on_press: root.update()
<SecondWindow>:
name:"second"
Button:
text: "go back and update"
on_press:
root.manager.current = 'first'
root.go_first()

Changing the screen and running a function on kivyMD?

I am learning Kivy, but I do not kown how to change a screen and running a funtion at the same time.
Where should I declare my funtion so the button have access to the code and can run the function?
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
screen_helper = """
ScreenManager:
MenuScreen:
FunctionScreen:
<MenuScreen>:
name: 'menu'
MDRectangleFlatButton:
text: 'Function'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press: root.manager.current = 'function screen'
<FunctionScreen>:
name: 'function screen'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class FunctionScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(FunctionScreen(name='function'))
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(screen_helper)
return screen
# def funtion(self):
# do stuff and then go to menu screen
DemoApp().run()
Should I try maybe, add the on_opress atribute in the build function?
Can you guys help me?
There are several convenient places to place the function(). One is in the MenuScreen, and in that case, it would be referenced in the kv files as:
root.function()
Another convenient place is in the DemoApp, and in that case, the reference would be:
app.function()
So, here is a version of your code tht puts the function() in the App:
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
screen_helper = """
ScreenManager:
MenuScreen:
FunctionScreen:
<MenuScreen>:
name: 'menu'
MDRectangleFlatButton:
text: 'Function'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press:
root.manager.current = 'function screen'
app.function()
<FunctionScreen>:
name: 'function screen'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class FunctionScreen(Screen):
pass
class DemoApp(MDApp):
def build(self):
sm = Builder.load_string(screen_helper)
return sm
def function(self):
# do stuff and then go to menu screen
print('in function')
DemoApp().run()
Note that the lines of your code that built a ScreenManager have been deleted as they are unnecessary.

Switching between kivy classes inside one screen

I'm looking for a way to change a part of a screen between 'DownPanel1' and 'DownPanel1' but I would like to avoide creating nex screen class 'ToAvoid'. Is it possible?
from kivy.config import Config
Config.set('graphics', 'multisamples', '0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
kv = '''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
SomeScreen:
ToAvoid:
<Menu#RelativeLayout>
id: main_menu
size_hint_x: None
width: 120
Button:
size_hint_y: None
pos: root.x, root.top - self.height
text: 'SomeScreen'
on_press: app.root.current = "SomeScreen"
<UpScreen>:
BoxLayout:
Button:
text: 'switch'
on_press: app.root.current = "ToAvoid"
<DownPanel1>:
Button:
text: 'DownPanel1'
#on_press:
<DownPanel2>:
Button:
text: 'DownPanel2'
#on_press:
<SomeScreen>:
name: 'SomeScreen'
BoxLayout:
orientation: 'horizontal'
Menu:
BoxLayout:
orientation: 'vertical'
UpScreen:
DownPanel1:
<ToAvoid>:
name: 'ToAvoid'
BoxLayout:
orientation: 'horizontal'
Menu:
BoxLayout:
orientation: 'vertical'
UpScreen:
DownPanel2:
'''
class DownPanel1(BoxLayout):
pass
class DownPanel2(BoxLayout):
pass
class UpScreen(Screen):
pass
class SomeScreen(Screen):
pass
class ToAvoid(Screen):
pass
class ScreenManagement(ScreenManager):
pass
sm = Builder.load_string(kv)
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
How about some inception? Just put another ScreenManager inside of the other.
Try this example:
from kivy.app import App
from kivy.lang import Builder
KV = """
ScreenManager:
Screen:
name: "1st"
Button:
text: "next"
on_release:
root.current = "2nd"
Screen:
name: "2nd"
BoxLayout:
Button:
text: "3rd to avoid"
on_release:
root.current = "3rd"
ScreenManager:
id: sm2
Screen:
name: "inner1"
Button:
text: "go to inner 2"
on_release:
sm2.current = "inner2"
Screen:
name: "inner2"
Label:
text: "This is inner 2!"
Screen:
name: "3rd"
Label:
text: "To Avoid!"
"""
class MyApp(App):
def build(self):
return Builder.load_string(KV)
if __name__ == "__main__":
MyApp().run()

Screen Manager in kivy with kv file

this is the first question I am posting so sorry if the question is not complete.
I tried the example on kivy's official page for Screen Manager and it works, but if I try using a kv file instead of the Builder, I get a black page.
Test.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
Test.kv
<MenuScreen>:
BoxLayout:
Button:
text: 'Goto settings'
on_press: root.manager.current = 'settings'
Button:
text: 'Quit'
<SettingsScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
Your test.py should look like:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
# Declare both screens
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class TestApp(App):
pass
if __name__ == '__main__':
TestApp().run()
And your test.kv file should be:
#: kivy 1.10.0
ScreenManager:
id: screen_manager
MenuScreen:
id: menu_screen
name: 'menu'
manager: 'screen_manager'
SettingsScreen:
id: settings_screen
name: 'settings'
manager: 'screen_manager'
<MenuScreen>:
BoxLayout:
Button:
text: 'Goto settings'
on_press: app.root.current = 'settings'
Button:
text: 'Quit'
<SettingsScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: app.root.current = 'menu'

Only one root object is allowed by .kv

I am doing an online kivy tutorial. Below is the code that I have written. It is exactly as was in the tutorial video.
But when I run the code I get the following error:
...
1:import FadeTransition kivy.uix.screenmanager.FadeTransition
2:
>> 3:ScreenManagement:
4: transition: FadeTransition()
5:
...
Only one root object is allowed by .kv
I think the error is with the FadeTransition because I have two instances-MainScreen and AnotherScreen but I do not know how to rectify it. And in the tutorial video the code ran properly. So why isn't it executing in my computer?
Below is the code that I have written
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_string('''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
text: "Next Screen"
font_size: 50
on_release: root.app.current = "other"
<AnotherScreen>:
name: "other"
Button:
text: "Back Home"
font_size: 50
on_release: root.app.current = "main"
''')
class MainApp(App):
def build(self):
return presentation()
if __name__=="__main__":
MainApp().run()
Thanks in advance.
Try this code it might help a bit took a long time for me to figure it out:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = ('''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
text: "Next Screen"
font_size: 50
on_release: root.app.current = "other"
<AnotherScreen>:
name: "other"
Button:
text: "Back Home"
font_size: 50
on_release: root.app.current = "main"
''')
class MainApp(App):
def build(self):
return Builder.load_string(presentation)
if __name__=="__main__":
MainApp().run()
I came across the exact issue as you while watching the same video. You will need to do this instead (assuming you want a fade transition):
Main.py file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager): #here you are creating a screen manager called ScreenManagement
pass
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
presentation = Builder.load_file("Main2.kv") #telling the app which .kv file to use
class MainApp(App):
def build(self):
return presentation
runMain = MainApp()
runMain.run()
Now over to your Main2.kv file:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition() #telling the screen manager to use a fade transition
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main" #this name is what the screen manager uses to distinguish which screen to go to
Button:
text: "Go To Next Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "another" #the screen that the screen manager is told to go to
<AnotherScreen>:
name: "another"
Button:
text: "Go To Main Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "main"
Hope that helped.
In your kv file, you need to surround ScreenManagement class with "<" and ">" as shown in the example below.
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
class ScreenManagement(ScreenManager):
pass
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class MainApp(App):
def build(self):
return ScreenManagement()
if __name__ == "__main__":
MainApp().run()
main.kv
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
<ScreenManagement>:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
text: "Go To Next Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "another"
<AnotherScreen>:
name: "another"
Button:
text: "Go To Main Screen"
color:0,0,0,1
background_color: 1,1,1,1
size_hint: 1,0.10
pos:0,200
font_size: 30
on_release: app.root.current = "main"
Output

Categories

Resources