I'm trying to build an interface in python with Kivy. To do this, i want to follow this structure:
[ScreenManager#1] -> [Login Screen]
[ScreenManager#2] -> [All others screens]
My ScreenManager#1 is declared in my App function in python file. My ScreenManager#2 is initialised in a kv file. To simply the help that you can bring to me, i've joined the two in the code below.
my AllScreensScreenManager#2, need to have a template shared with all the other screens. I've gave an id to it and call this one with my button in my LoginScreen, like this was suggested here. But the switch is not working. What i'm doing wrong with it.
import kivy
kivy.require('2.1.0') # replace with your current kivy version !
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager,Screen
Builder.load_string('''
<AllScreens>:
id: second_manager
manager: scr_manager
orientation: "vertical"
BoxLayout:
ScreenManager:
id: scr_manager
transition: "left"
Welcome:
GenerateScreen:
ModifyScreen:
ConsultScreen:
LogoutScreen:
BoxLayout:
size_hint: 1, None
height: "40dp"
pos_hint: {"bottom": 0}
spacing: "5dp"
Button:
id: consult
text: "Consult"
on_press: root.manager.current("consult")
Button:
id: modify
text: "Modify"
on_press: root.manager.current("modify")
Button:
id: generate
text: "Generate"
on_press: root.manager.current("generate")
Button:
id: logout
text: "Logout"
on_press: root.manager.current("logout")
<LoginScreen>:
name: "login"
BoxLayout:
Label:
text: "Login"
Button:
text: "Connect"
on_release: second_manager.current("welcome")
<WelcomeScreen>:
name: "welcome"
BoxLayout:
Label:
text: "welcome"
<ConsultScreen>:
name: "consult"
BoxLayout:
Label:
text: "consult"
<GenerateScreen>:
name: "generate"
BoxLayout:
Label:
text: "password"
''')
class ScreenManagement(ScreenManager):
pass
class LoginScreen(Screen):
print("login screen")
pass
class WelcomeScreen(Screen):
pass
class AllScreens(ScreenManager):
pass
class ConsultScreen(Screen):
pass
class GenerateScreen(Screen):
pass
class MyApp(App):
def build(self):
sm = ScreenManagement()
sm.add_widget(LoginScreen(name="login"))
return sm
if __name__ == '__main__':
MyApp().run()
Related
I need help. I'm making an app, And when i want to use an Spinner. I assigned several values ("Catalogue","Buy","Payment Methods", "Contact"). I want that when choosing the value "Buy", My screen change to the "SecondWindow(Screen)". I was trying to do it from my py.file but I'm not sure how to do it correctly. I was trying to do it from my "def spinner_clicked(self,value):"
If you I can do it from my kv.file straightly. I would like to learn how to do it too.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.core.spelling import Spelling
from kivy.uix.screenmanager import ScreenManager, Screen
kv= Builder.load_file('test2.kv')
class MyLayout(Widget):
def spinner_clicked(self,value):
sm= ScreenManager()
screen= Screen(name='second')
self.ids.Label1.text= f'You selected: {value}'
#IN THIS PART WHEN PRESSING IN MY SPINNER the choice "buy" I need to change to the SecondWindow(Screen)
if self.ids.spinner_id.values == "Buy":
#self.sm.current= 'second'
#sm.root.manager.current= "second"
#sm.switch_to(screen)
pass
#Definine our different screens
class FirstWindow(Screen):
pass
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class AwesomeApp(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
AwesomeApp().run()
kv.file
<MyLayout>
BoxLayout:
orientation:"vertical"
size: root.width, root.height
GridLayout:
cols:3
rows:3
Spinner:
id: spinner_id
text: "Menu"
values: ["Catalogue","Buy","Payment Methods", "Contact"]
on_text: root.spinner_clicked(spinner_id.text)
#on_text: root.manager.current= "second" - it doesnt' work
#I want to change the screens from here choosing the value "Buy" to the 2ndScreen
Label:
id: Label1
text: "My Panel"
Button:
text:"Buy"
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "First Screen"
font_size: 32
Button:
text: "Next Screen"
font_size: 32
on_release:
root.manager.current= "second"
root.manager.transition.direction= "left" #up
<SecondWindow>:
name: "second"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Second Screen"
font_size: 32
Button:
text: "Go Back"
font_size: 32
on_release:
#app.root.current= "first"
root.manager.current= "first"
root.manager.transition.direction= "right"
If you set the Screen names to the values in your Spinner, then you can modify your kv slightly. In the Spinner section:
Spinner:
id: spinner_id
text: "Menu"
values: ["Catalogue","Buy","Payment Methods", "Contact"]
on_text: root.spinner_clicked(spinner_id.text)
on_text: window_manager.current = self.text # uses an id defined in the WindowManager section
And the window_manager id is defined later in the kv:
WindowManager:
id: window_manager
FirstWindow:
SecondWindow:
The window_manager.current refers to the id defined for the WindowManager, and accesses its current property.
Note that the root.manager in the kv file only works inside a rule for a Screen, like inside <FirstWindow>: or <SecondWindow>:. In that context, the root refers to the root widget of the rule (one of those Screens), and manager then refers to the ScreenManager that contains that Screen.
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 was trying to use a new feature in KivyMD, the MDNavigationRail and wanted to give the icons in it a function. The goal is that the user could change to the desired screen by pressing the icon that represents it. I gave the icon an on_press. But something goes wrong, I get an error; ValueError: MDNavigationRail.state is set to an invalid option 'down'. Must be one of: ['close', 'open']. The rail should be open or closed I guess, isn't it possible to give it a function? Furthermore, I would want to know if it is possible to not break the text. If anyone could help me out, it would be very nice!
My .py file
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
class Screen1(MDScreen):
def screen2(self):
self.manager.current = 'screen2'
class Screen2(MDScreen):
def screen1(self):
self.manager.current = 'screen1'
def rail_open(self):
if self.ids.rail.state == "open":
self.ids.rail.state = "close"
else:
self.ids.rail.state = "open"
class MyScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
class Test(MDApp):
def build(self):
return MyScreenManager()
Test().run()
My kv file
<MyScreenManager>:
Screen1:
id: screen1
name: 'screen1'
Screen2:
id: screen2
name: 'screen2'
<Screen1>:
id: screen1
MDFloatLayout:
MDRectangleFlatButton:
text: "Change to screen 2"
on_press: root.screen2()
pos_hint: {'center_x':0.5, 'center_y':0.5}
<Screen2>:
id: screen2
MDBoxLayout:
orientation: "vertical"
MDToolbar:
left_action_items: [["menu", lambda x: root.rail_open()]]
MDBoxLayout:
MDNavigationRail:
id: rail
elevation: 1
use_resizeable: True
MDNavigationRailItem:
icon: "home"
text: "homepage"
on_press: root.screen1()
MDNavigationRailItem:
icon: ""
text: ""
MDFloatLayout:
MDTextField:
id: field1
hint_text: "Enter something:"
size_hint_x: 0.4
pos_hint: {'center_x':0.25,'top':0.8}
It was a bug. Already fixed - https://github.com/kivymd/KivyMD/commit/8a31b0f3ccad9c2d9ad35d80953f7396f2dc78f2
main.py file
from kivymd.app import MDApp
from kivy.lang import Builder
class Hero(MDApp):
def build(self):
return Builder.load_file("stackoverflow.kv")
Hero().run()
the above is the main.py file
please guys help me with this
stackoverflow.kv file
ScreenManager:
id: screenmanager
Screen:
id: accountscreen
name: "screen1"
BoxLayout:
oreintation: "vertical"
MDGridLayout:
cols:1## Heading ##
MDLabel:
text: "[color=00FF00]Sign In[/color]"
bold:True
markup:True
halign: "center"
valign: "middle"
MDTextField:
id: username
padding: "30dp"
spacing: "30dp"
hint_text:"User Name or Email"
pos_hint: {"center_x":.5,"center_y":.5}
MDTextField:
id:password
padding: "20dp"
spacing: "20dp"
hint_text:"Password"
MDRectangleFlatButton:
text:"Sign In"
padding: "16dp"
spacing: "16dp"
halign: "center"
pos_hint: {"center_x":.9,"center_y":.5}
on_press: app.root.current="screen2"
BoxLayout:
oreintation: "vertical"
Screen:
id: welcome_screen
name: "screen2"
MDLabel:
text: "welcome"
valign: "middle"
halign: "center"
any time i open the app i get the sign in screen how can i save the user information and clear the screen using config ini file please help me????
Here is a version of you code that uses Config to do what you want:
import os
from kivymd.app import MDApp
from kivy.lang import Builder
class Hero(MDApp):
def build(self):
sm = Builder.load_file("stackoverflow.kv")
self.load_my_config()
sm.current = self.initial_screen
return sm
def build_config(self, config):
# Make sure that the config has at least default entries that we need
config.setdefaults('app', {
'startup_screen': 'screen1',
})
def get_application_config(self):
# This defines the path and name where the ini file is located
return str(os.path.join(os.path.expanduser('~'), 'Hero.ini'))
def on_stop(self):
# save the config when the app exits
self.save_config()
def save_config(self):
# this writes the data we want to save to the config
# set the data in the config
self.config.set('app', 'startup_screen', 'screen2')
# write the config file
self.config.write()
def load_my_config(self):
# extract our saved data from the config (it has already been read)
self.initial_screen = self.config.get('app', 'startup_screen', fallback='screen1')
Hero().run()
And in the kv file, I would add a call to save the configuration when the Sign In button is pressed:
MDRectangleFlatButton:
text:"Sign In"
padding: "16dp"
spacing: "16dp"
halign: "center"
pos_hint: {"center_x":.9,"center_y":.5}
on_press:
app.root.current="screen2"
app.save_config()
I have been learning Kivy with a YouTube channel. I made two screens and one screenmanager but they are classes in python code. I saw examples like WinManager = ScreenManager(transition=CardTransition()) but I didn't structure my code like that. How can i change transition with my code? I tried to do it on init function of class, didn't work; and tried to add transition properity in kv file. Didn't work either.
Python:
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, CardTransition
class MainWindow(Screen):
pass
class AdminPanel(Screen):
pass
class WinManager(ScreenManager):
pass
kvTemplate = Builder.load_file("template.kv")
class MyMainApp(App):
def build(self):
return kvTemplate
if __name__ == "__main__":
MyMainApp().run()
Kivy (.kv):
WinManager:
MainWindow:
AdminPanel:
<MainWindow>:
name: "loginPanel"
nickname: nicknameID
password: passwordID
key: keyID
GridLayout:
rows: 2
GridLayout:
cols: 2
Label:
text: "Nickname: "
TextInput:
id: nicknameID
multiline: False
Label:
text: "Password: "
TextInput:
id: passwordID
multiline: False
Label:
text: "Key: "
TextInput:
id: keyID
multiline: False
Button:
text: "Log in"
on_release:
app.root.current = "adminPanel"
root.manager.transition.direction = "up"
<adminPanel>:
name: "adminPanel"
Button:
text: "Back"
on_release:
app.root.current = "loginPanel"
root.manager.transition.direction = "down"
In your kv file you can do:
#:import CardTransition kivy.uix.screenmanager.CardTransition
WinManager:
transition: CardTransition()
MainWindow:
AdminPanel: