So i have created some screens and added some properties to them (layouts, buttons, name etc) but everything is on the kivy file. Now, i want to make a function in the python main file which will take me from the starting screen to the next one after a brief time. Though nothing seems to work without me having to move everything from the kivy file to the python file. Any ideas?
.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.behaviors import ButtonBehavior
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class AndAnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class BackgroundLabel(Label):
pass
class CompanyImage(Image):
pass
class LoadingScreen(Screen):
def __init__(self, **kwargs):
super(LoadingScreen, self).__init__(**kwargs)
def ChangeScreen(self):
ScreenManager().current = MainScreen().name
presentation = Builder.load_file("tsalapp.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
.kv
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import Clock kivy.clock.Clock
#: import Color kivy.graphics
#: import Rectangle kivy.graphics
ScreenManagement:
transition: FadeTransition()
LoadingScreen:
MainScreen:
AnotherScreen:
AndAnotherScreen:
<BackgroundLabel>:
background_color: 30,144,255,1
canvas.before:
Color:
rgba: self.background_color
Rectangle:
pos: self.pos
size: self.size
<LoadingScreen>:
name: "main"
id: "yolo"
on_enter: Clock.schedule_once(none, 3)
#app.root.current: "menu"
Image:
source: 'Untitled.png'
height: root.height
width: root.width
allow_stretch: True
keep_ratio: False
AnchorLayout:
Label:
text: "Tsala Inc."
anchor_x: 'center'
anchor_y: 'center'
font_size: root.height/15
<MainScreen>:
name: "menu"
id: "swag"
BoxLayout:
orientation: "vertical"
Button:
text: "Next Page"
background_color: 1,1,4,1
size_hint: (0.5, 0.5)
on_release:
app.root.current= "Another Screen"
Button:
text: "Previous Page"
background_color: 1,4,1,1
size_hint: (0.5, 0.5)
on_release:
app.root.current= "And Another Screen"
<AnotherScreen>:
name: "Another Screen"
GridLayout:
cols: 2
Button:
text: "Previous Page"
background_color: 0,0,1,1
size_hint: (0.25,1)
on_release:
app.root.current = "menu"
Button:
text: "Exit"
background_color: 1,0,0,1
size_hint: (0.25, 1)
on_release:
exit()
<AndAnotherScreen>:
name: "And Another Screen"
BoxLayout:
orientation: "vertical"
Button:
text: "Next Page"
background_color: 1,1,4,1
size_hint: (0.5, 0.5)
on_release:
app.root.current= "menu"
Button:
text: "Nextest Page"
background_color: 1,4,1,1
size_hint: (0.5, 0.5)
on_release:
app.root.current= "Another Screen"
Firstly I recommend create a global variable for screenmanager or place screenmanager in the MainApp as class property and create a list or a dictionary for the screens:
class MyApp(App):
sm = ScreenManager() # screenmanager
screens = {} # dictionary for the screens, I prefer dictionary because string indexes are more convenient
Then in a build method you can create all screens you need and return the screenmanager as root widget:
class MyApp(App):
sm = ScreenManager() # screenmanager
screens = {} # dictionary for the screens, I prefer dictionary because string indexes are more convenient
def build(self):
self.__create_screens()
MyApp.sm.add_widget(MyApp.screens['main_screen'])
return MyApp.sm
def __create_screens(self):
MyApp.screens['main_screen'] = MainScreen(name='mainscreen')
MyApp.screens['another_screen'] = AnotherScreen(name='another_screen')
MyApp.screens['and_another_screen'] = AndAnotherScreen(name='and_another_screen')
So now you can switch your app's screens easily wherever you want using switch_to method:
MyApp.sm.switch_to(MyApp.screens['another_screen'], direction='left', duration=1)
Related
I have a problem with my Kivy Python Code. I have 2 screens: 1st is to navigate to the second screen and on the 2nd screen there is a button to add text to a scrollview...navigating is working but it does not add any text to the scrollview...I think I need some help here! AttributeError: 'super' object has no attribute 'getattr'
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock, mainthread
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.effects.scroll import ScrollEffect
from kivy.lang import Builder
Builder.load_string("""
<MenuScreen>:
name: 'mainmenu'
BoxLayout:
spacing: 1
orientation: "vertical"
Label:
text: "MAIN MENU"
Button:
text: 'Go to Screen 2'
on_release:
root.manager.current = 'screen2'
root.manager.transition.direction = "left"
Button:
text: 'Quit'
on_release: root.manager.current = app.exit_software()
<Screen2>:
name: 'screen2'
BoxLayout:
spacing: 1
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
text: "You can add some Text here by pressing the button"
size_hint: None, None
size: self.texture_size
Button:
text: 'Add text!'
size_hint_y: 0.1
on_release: app.add_text()
Button:
text: 'Back to main menu'
size_hint_y: 0.1
on_release:
root.manager.current = 'mainmenu'
root.manager.transition.direction = "right"
""")
# Declare both screens
class MenuScreen(Screen):
pass
class Screen2(Screen):
pass
class AddTextApp(App):
def __init__(self,**kwargs):
super().__init__(**kwargs)
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='mainmenu'))
sm.add_widget(Screen2(name='screen2'))
return sm
def add_text(self):
self.root.ids.label.text += f"Some new Text\n"
self.root.ids.scroll_view.scroll_y = 0
def exit_software(self):
App.get_running_app().stop()
if __name__ == '__main__':
AddTextApp().run()
Thank you very much in advance!
The error occurred because self.root.ids gets access to widgets located in the root widget of the main class. To access the secondary screen elements, you need to add it to the main class (in your case, in ScreenManager) and set its id. Also, you have a lot of imported excess, so that it is clearly visible, I advise you to use Pycharm or something like that.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
kv = """
<MenuScreen>:
name: 'mainmenu'
BoxLayout:
spacing: 1
orientation: "vertical"
Label:
text: "MAIN MENU"
Button:
text: 'Go to Screen 2'
on_release:
root.manager.current = 'screen2'
root.manager.transition.direction = "left"
Button:
text: 'Quit'
on_release: root.manager.current = app.exit_software()
<Screen2>:
name: 'screen2'
BoxLayout:
spacing: 1
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
text: "You can add some Text here by pressing the button"
size_hint: None, None
size: self.texture_size
Button:
text: 'Add text!'
size_hint_y: 0.1
on_release: app.add_text()
Button:
text: 'Back to main menu'
size_hint_y: 0.1
on_release:
root.manager.current = 'mainmenu'
root.manager.transition.direction = "right"
ScreenManager:
MenuScreen:
id: menu_scr
Screen2:
id: scr_2
"""
class MenuScreen(Screen):
pass
class Screen2(Screen):
pass
class AddTextApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def build(self):
return Builder.load_string(kv)
def add_text(self):
self.root.ids.scr_2.ids.label.text += f"Some new Text\n"
self.root.ids.scr_2.ids.scroll_view.scroll_y = 0
#staticmethod
def exit_software():
App.get_running_app().stop()
if __name__ == '__main__':
AddTextApp().run()
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()
After much headbanging, I've created an app that opens the FileChooser and picks an image. A function will then transform the image and change it on the screen.
< FirstScreen > is just something to start with, relatively unimportant.
< SecondScreen > is the file chooser. The path may need editing. < ThirdScreen > shoudl show the image along with buttons that will eventually lead elsewhere.
I suspect the problem is that the line
sm.current = "_third_screen_"
is creating a new instance separate to everything else I've passed items too. How do I show the image I selected?
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
Builder.load_string("""
<MyScreenManager>:
FirstScreen:
SecondScreen:
ThirdScreen:
<FirstScreen>:
name: '_first_screen_'
BoxLayout:
orientation: "horizontal"
Label:
id: first_screen_label
text: "Hi, I'm the home page"
BoxLayout:
orientation: "vertical"
Button:
text: "Okay!"
on_press: root.manager.current = '_second_screen_'
Button:
text: "Cancel!"
on_press: app.stop()
<SecondScreen>:
name: '_second_screen_'
id: file_chooser
BoxLayout:
id: file_chooser_box_layout
orientation: "horizontal"
Button
text: "Open"
on_press:
root.callback_image_and_other_stuff(file_chooser_list_view.selection)
FileChooserListView:
id: file_chooser_list_view
<ThirdScreen>:
name: '_third_screen_'
BoxLayout:
orientation: "vertical"
id: third_screen
Label:
id: main_title
text: "Upload"
size_hint: (1, 0.1)
Image:
id: main_image
source: root.img
size_hint: (1, 0.75)
BoxLayout:
orientation: "horizontal"
padding: 10
size_hint: (1, 0.15)
Button:
text: "Okay"
size_hint: (0.5, 1)
on_press: image_viewer.image_accepted_by_user(filechooser.selection)
Button:
text: "Cancel"
size_hint: (0.5, 1)
on_press: root.manager.current = '_first_screen_'
""")
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
def callback_image_and_other_stuff(self, new_image_address):
# do other stuff here also, then pass new_image_address along
new_image_address = new_image_address[0].replace("\\", "/")
third_screen = ThirdScreen()
third_screen.callback_image(new_image_address)
class ThirdScreen(Screen):
img = ObjectProperty(None)
def __init__(self, **kwargs):
super(Screen, self).__init__(**kwargs)
def callback_image(self, new_image_address):
sm.current = "_third_screen_"
self.img = new_image_address
self.ids.main_image.source = self.img
print(self.img)
# Create the screen manager
sm = ScreenManager() # Problem?
sm.add_widget(FirstScreen(name='_first_screen_'))
sm.add_widget(SecondScreen(name='_second_screen_'))
sm.add_widget(ThirdScreen(name='_third_screen_'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
Every time you use some_obj = SomClass() you are creating a new object, in your case that is what you are doing, you are creating a new ThirdScreen different from the one shown by that you do not observe the image, the solution is that you have to access to the initial object using the ScreenManager and name screen.
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
Builder.load_string("""
<FirstScreen>:
BoxLayout:
orientation: "horizontal"
Label:
id: first_screen_label
text: "Hi, I'm the home page"
BoxLayout:
orientation: "vertical"
Button:
text: "Okay!"
on_press: root.manager.current = '_second_screen_'
Button:
text: "Cancel!"
on_press: app.stop()
<SecondScreen>:
id: file_chooser
BoxLayout:
id: file_chooser_box_layout
orientation: "horizontal"
Button
text: "Open"
on_press:
root.callback_image_and_other_stuff(file_chooser_list_view.selection)
FileChooserListView:
id: file_chooser_list_view
<ThirdScreen>:
BoxLayout:
orientation: "vertical"
id: third_screen
Label:
id: main_title
text: "Upload"
size_hint: (1, 0.1)
Image:
id: main_image
source: root.img
size_hint: (1, 0.75)
BoxLayout:
orientation: "horizontal"
padding: 10
size_hint: (1, 0.15)
Button:
text: "Okay"
size_hint: (0.5, 1)
on_press: image_viewer.image_accepted_by_user(filechooser.selection)
Button:
text: "Cancel"
size_hint: (0.5, 1)
on_press: root.manager.current = '_first_screen_'
""")
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
def callback_image_and_other_stuff(self, new_image_address):
if new_image_address:
third_screen = self.manager.get_screen("_third_screen_")
# do other stuff here also, then pass new_image_address along
new_image_address = new_image_address[0].replace("\\", "/")
third_screen.callback_image(new_image_address)
class ThirdScreen(Screen):
img = ObjectProperty(None)
def __init__(self, **kwargs):
super(Screen, self).__init__(**kwargs)
def callback_image(self, new_image_address):
sm.current = "_third_screen_"
self.img = new_image_address
self.ids.main_image.source = self.img
print(self.img)
# Create the screen manager
sm = ScreenManager() # Problem?
sm.add_widget(FirstScreen(name='_first_screen_'))
sm.add_widget(SecondScreen(name='_second_screen_'))
sm.add_widget(ThirdScreen(name='_third_screen_'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
I want that on pressing enter in a TextInput widget it should do two things-
change the screen (i am using screen manager)
and search for the keyword
I do know that with on_text_validate we can perform either of the tasks by-
1.root.manager.current='namesomething'
2.root.function_which_has_search_algorithm()
is there anyway with which i can do both the things(changing_the_screen,calling_the_search_function) using on_text_validate or do i have to use some other technique?
here a sample code:
import kivy
kivy.require("1.10.0")
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.lang import Builder
Builder.load_file('screenswitch.kv')
class MainScreen(Screen):
def SelectWord(self):
''' some search
code'''
class OtherScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(OtherScreen(name='other'))
class ScreenSwitchApp(App):
def build(self):
return sm
obj = ScreenSwitchApp()
obj.run()
heres my kivy code:
<MainScreen>:
BoxLayout:
TextInput:
text: "Search your word here"
color: 1,1,1,1
id: search_input
width: 200
size_hint: None, .20
pos_hint: {"center_x": .5, "center_y": 0.5}
multiline: False
on_text_validate: root.SelectWord() # i want this to change screen also
<OtherScreen>:
BoxLayout:
Button:
text: 'back to main screen'
on_press: root.manager.current='main'
A possible solution is to create a new function that calls that 2 functions:
*.py
import kivy
kivy.require("1.10.0")
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.lang import Builder
Builder.load_file('screenswitch.kv')
class MainScreen(Screen):
def some_function(self):
self.SelectWord()
self.manager.current='other'
def SelectWord(self):
print("SelectWord")
class OtherScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(OtherScreen(name='other'))
class ScreenSwitchApp(App):
def build(self):
return sm
obj = ScreenSwitchApp()
obj.run()
*.kv
<MainScreen>:
BoxLayout:
TextInput:
text: "Search your word here"
color: 1,1,1,1
id: search_input
width: 200
size_hint: None, .20
pos_hint: {"center_x": .5, "center_y": 0.5}
multiline: False
on_text_validate: root.some_function() # i want this to change screen also
<OtherScreen>:
BoxLayout:
Button:
text: 'back to main screen'
on_press: root.manager.current='main'
TextInput:
id:qty_inp
size_hint_x:.1
multiline:False
on_text_validate:root.update_price()
on_text_validate:root.update_purchase
Like the above code you can add one more on_text_validate: root.method()
There is something in kivy I do not understand, and am hoping that someone could shed light. I have done a lot of reading in this topic but it just doesn't seem to be connecting in my head.
My issue comes from linking a function to a kivy button.
Right now I am trying to learn how to do a simple function:
def Math():
print 1+1
What I would like to do something more complex:
def Math(a,b):
print a^2 + b^2
Where a and b are input labels from kivy, and upon clicking a button the answer will be printed.
This is what I have so far:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
#######``Logics``#######
class Math(FloatLayout):
def add(self):
print 1+1
#######``Windows``#######
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("GUI_Style.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
This is my kivy language file:
import NoTransition kivy.uix.screenmanager.NoTransition
ScreenManagement:
transition: NoTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
FloatLayout:
Button:
on_release: app.root.current = "other"
text: "Next Screen"
font_size: 50
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
pos_hint: {"right":1, "top":1}
<AnotherScreen>:
name: "other"
FloatLayout:
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
text: "add"
pos_hint: {"x":0, "y":0}
on_release: root.add
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
text: "Back Home"
on_release: app.root.current = "main"
pos_hint: {"right":1, "top":1}
<AnotherScreen>:
name: "other"
FloatLayout:
Button:
...
on_release: root.add <-- here *root* evaluates to the top widget in the rule.
Which is an AnotherScreen instance, but it doesn't have an add method.
class Math(FloatLayout):
def add(self):
print 1+1
Here you have declared a Math class by inheriting from the FloatLayout, which is a uix component -a widget-. And you defined a method on this class add. Still you haven't used it. In the kv file you used FloatLayout.
Now in order for you to access a function in kv, most of the time you'll acces it as a method of a uix component, by using either root/self or app, you can also import it e.g:
#: import get_color_from_hex kivy.utils.get_color_from_hex
<ColoredWidget>:
canvas:
Color:
rgba: get_color_from_hex("DCDCDC")
Rectangle:
size: self.size
pos: self.pos
So you can't do it like this:
<AnotherScreen>:
name: "other"
Math:
id: math_layout
Button:
...
on_release: math_layout.add()
or like this:
class AnotherScreen(Screen):
def add(self):
print(1+1)
If you still have problems conserning this topic, i'll be glad to provide more help .