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:
Related
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()
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 been working on an app with Kivy that receives 0, 1 or 2 as text input by the user and a label on the final screen shows a text which should differ based on the received input. It does not present with any errors any longer, but the final screen will only show the "else" text ("Bad Luck") even when the requirements of the "if statement" are met.
By searching similar questions, I tried using an "input_filter" for integers in case it resolved the issue, but it didn't.
I am a beginner with no programming background, so please feel free to be as elaborate as you like in your answers. Thank you in advance for your time and any ideas/recommendations you may share. Following are the codes of the .py and .kv files:
.py file:
import kivy
from kivy.app import App
from kivy.lang import Builder
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.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import NumericProperty, StringProperty, NumericProperty
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
pass
class FourthWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class MyApp(App):
def build(self):
kv = Builder.load_file("my.kv")
return kv
if __name__=="__main__":
MyApp().run()
.kv file:
WindowManager:
MainWindow:
SecondWindow:
ThirdWindow:
FourthWindow:
<MainWindow>:
name: "main"
GridLayout:
cols:1
rows:2
Label:
text: "stuff"
Button:
text: "stuff"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "second"
GridLayout:
cols:1
rows:2
GridLayout:
cols:2
Label:
text: "stuff"
TextInput:
id: ti_a
multiline:False
Label:
text: "stuff"
TextInput:
id: ti_b
multiline:False
Label:
text: "stuff"
TextInput:
id: ti_c
multiline:False
Label:
text: "stuff"
TextInput:
id: ti_d
multiline:False
Label:
text: "stuff"
TextInput:
id: ti_e
multiline:False
GridLayout:
cols:2
Button:
text: "stuff"
on_release:
app.root.current = "third"
root.manager.transition.direction = "left"
Button:
text: "Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
<ThirdWindow>:
name: "third"
GridLayout:
cols:1
rows:2
GridLayout:
cols:2
Label:
text: "stuff"
TextInput:
id: ti_f
multiline:False
GridLayout:
cols:2
Button:
text: "stuff"
on_release:
app.root.current = "fourth"
root.manager.transition.direction = "left"
Button:
text: "Back"
on_release:
app.root.current = "second"
root.manager.transition.direction = "right"
<FourthWindow>:
name: "fourth"
Label:
text: "Stuff" if root.manager.get_screen("second").ids.ti_a.text == "0" and root.manager.get_screen("second").ids.ti_b.text == "0" and root.manager.get_screen("second").ids.ti_c.text == "0" and root.manager.get_screen("second").ids.ti_d.text == "0" and root.manager.get_screen("second").ids.ti_e.text == "1" and root.manager.get_screen("third").ids.ti_f.text == "0" else "Bad Luck"
The problem is that kivy doesn't recognize the expression:
root.manager.get_screen("second").ids.ti_a.text
as a property that it can bind to, so the value of Label text in your FourthWindow is only evaluated once (when the FourthWindow is created). Any changes to the other Labels in your app will have no effect on FourthWindow. See the documentation.
The fix is to write your own code to update that Label by adding an id to that Label:
<FourthWindow>:
name: "fourth"
Label:
id: lab
text: ""
And adding a on_pre_enter() method to FourthWindow:
class FourthWindow(Screen):
def on_pre_enter(self, *args):
if self.manager.get_screen("second").ids.ti_a.text == "0" and \
self.manager.get_screen("second").ids.ti_b.text == "0" and \
self.manager.get_screen("second").ids.ti_c.text == "0" and \
self.manager.get_screen("second").ids.ti_d.text == "0" and \
self.manager.get_screen("second").ids.ti_e.text == "1" and \
self.manager.get_screen("third").ids.ti_f.text == "0":
self.ids.lab.text = 'Stuff'
else:
self.ids.lab.text = 'Bad Luck'
This will evaluate your expression and set the text each time just before the FourthWindow is displayed.
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
I'm beginner in kivy module. I want to put 8 textboxes in screen to get input from user and then, save this inputs in a list in order to use them later!
I searched in the internet but a didn't find any thing useful.
I think I should do sth like this code:
Save text input to a variable in a kivy app
But don't want to show the inputs in shell, I wanna save them in a list!
Py file
Use a for loop to traverse through a container of all widgets e.g. TextInput.
Snippets
for child in reversed(self.container.children):
if isinstance(child, TextInput):
self.data_list.append(child.text)
kv file
Use a container e.g. GridLayout
Add an id for the container
Add all those Label and TextInput widgets as child of GridLayout
Snippets
GridLayout:
id: container
cols: 2
Label:
text: "Last Name:"
TextInput:
id: last_name
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty, ListProperty
from kivy.lang import Builder
Builder.load_file('main.kv')
class MyScreen(Screen):
container = ObjectProperty(None)
data_list = ListProperty([])
def save_data(self):
for child in reversed(self.container.children):
if isinstance(child, TextInput):
self.data_list.append(child.text)
print(self.data_list)
class TestApp(App):
def build(self):
return MyScreen()
if __name__ == "__main__":
TestApp().run()
main.kv
#:kivy 1.11.0
<MyScreen>:
container: container
BoxLayout:
orientation: 'vertical'
GridLayout:
id: container
cols: 2
row_force_default: True
row_default_height: 30
col_force_default: True
col_default_width: dp(100)
Label:
text: "Last Name:"
TextInput:
id: last_name
Label:
text: "First Name:"
TextInput:
id: first_name
Label:
text: "Age:"
TextInput:
id: age
Label:
text: "City:"
TextInput:
id: city
Label:
text: "Country:"
TextInput:
id: country
Button:
text: "Save Data"
size_hint_y: None
height: '48dp'
on_release: root.save_data()
Output
You need to give your text inputs ids, then reference the id of them and get their text using .text. self.root in the TestApp class refers to the root widget of your kv file, which is the one that doesn't have brackets (< >) around it, in this case the GridLayout.
main.py
from kivy.app import App
class MainApp(App):
def get_text_inputs(self):
my_list = [self.root.ids.first_input_id.text, self.root.ids.second_input_id.text]
print(my_list)
pass
MainApp().run()
main.kv
GridLayout:
cols: 1
TextInput:
id: first_input_id
TextInput:
id: second_input_id
Button:
text: "Get the inputs"
on_release:
app.get_text_inputs()