So I'm working on my first app and when learning about kivy and watching youtube videos I was seeing different ways people would load in their KV file and one was putting in in a variable and returning it from the build method. Anytime I do this, no errors are necessarily thrown but it doesn't load the window properly and it makes no sense why the KV file isnt loading. If anyone can point me in the right direction I'd appreciate it, the code is below.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
class LoginLayout(Widget):
def login(self, **kwargs):
print("Login function working")
username = self.ids.username.text
password = self.ids.password.text
print(username)
print(password)
kv = Builder.load_file('loginScreen.kv')
class LoginScreen(App):
def build(self):
return kv
app = LoginScreen()
app.run()
kv file
<LoginLayout>:
BoxLayout:
orientation: 'vertical'
size: root.width, root.height
Label:
text: 'Username'
TextInput:
id: username
multiline: False
size_hint: (.5, .3)
pos_hint: {'center_x' : .5}
Label:
text: 'Password'
TextInput:
id: password
multiline: False
size_hint: (.5, .3)
pos_hint: {'center_x' : .5}
Button:
text: 'Login'
size_hint: (.2, .8)
pos_hint: {'center_x' : 0.5}
on_release: root.login()
Button:
text: 'Create Account'
size_hint: (.2, .8)
pos_hint: {'center_x' : 0.5}
Button:
text: 'Forgot login Info'
size_hint: (.2, .8)
pos_hint: {'center_x' : 0.5}
The problem is that your kv does not define a root widget, it only defines rules for how to build the LoginLayout. An easy fix is to remove the <> from around LoginLayout.
Related
I want to know the method of loading the second screen when authentication is passed.
I can call the second screen from the .kv file vi on_press or other methods. But I need to call from python code to check the authentication.
Can anyone help with my code?
Here is my code:
app.py
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import ObjectProperty
class my_layout(FloatLayout):
screen_mngr = ObjectProperty(None)
class myapp(MDApp):
def build(self):
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "BlueGray"
return Builder.load_file("app.kv")
def logger(self):
if self.root.ids.user.text == 'admin' and self.root.ids.password.text=='admin':
self.root.ids.welcome_label.text = f'Sup {self.root.ids.user.text}!'
screen = Screen(name='screen2')
else:
self.root.ids.welcome_label.text = 'Wrong credentials'
if __name__ == "__main__":
myapp().run()
And here is my design kv file.
app.kv file:
my_layout:
screen_mngr: screen_mngr
ScreenManager:
id: screen_mngr
home: home
Screen:
id: home
name: 'home'
MDCard:
size_hint: None, None
size: 450, 600
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: 25
spacing: 25
orientation: 'vertical'
MDLabel:
id: welcome_label
text: "WELCOME"
font_size: 40
halign: 'center'
size_hint_y: None
height: self.texture_size[1]
padding_y: 15
MDTextField:
id: user
hint_text: "username"
icon_right: "account"
size_hint_x: None
width: 200
font_size: 18
pos_hint: {"center_x": 0.5}
MDTextField:
id: password
hint_text: "password"
icon_right: "eye-off"
size_hint_x: None
width: 200
font_size: 18
pos_hint: {"center_x": 0.5}
MDRoundFlatButton:
text: "LOG IN"
font_size: 12
pos_hint: {"center_x": 0.5}
on_press: screen2
Screen:
id: screen2
name: 'screen2'
MDRoundFlatButton:
text: "This is Second Screen\nGo to Screen1"
size_hint: 0.2,0.1
pos_hint: {"center_x":0.5,"y":0.5}
on_press: screen_mngr.current = "home"
A couple small problems:
First, in your kv you need to have your LOG IN Button call the code to handle the log in, like this:
MDRoundFlatButton:
text: "LOG IN"
font_size: 12
pos_hint: {"center_x": 0.5}
on_press: app.logger() # call the method that handles login
Then, in that method, you can change to the screen2 by using the current property of the ScreenManager, like this:
def logger(self):
if self.root.ids.user.text == 'admin' and self.root.ids.password.text=='admin':
self.root.ids.welcome_label.text = f'Sup {self.root.ids.user.text}!'
self.root.ids.screen_mngr.current = 'screen2' # go to screen2
# screen = Screen(name='screen2')
else:
self.root.ids.welcome_label.text = 'Wrong credentials'
I'm working on a project using Kivy with ScreenManager (and KivyMD).
The reason for using this is my need of making an application with multiple screens. My goal is to get User Input from an existing MDTextField by (a string) ID and then Print it out.
However, I keep getting this Error: File "<string>", line 37, in <module> File "c:/Users/admin/Desktop/myApp/Main.py", line 75, in loginFunction username = mainScreenInstance.ids["input_username"].text KeyError: 'input_username'.
I have searched for answers all over the internet and StackOverflow, but no solution seems to work for me. Maybe there's someone who can help me with my problem and make my code work.
Anyway, here's my short & simple Code:
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
import sys
screen_helper = """
ScreenManager:
MenuScreen:
name: 'menu'
SecondScreen:
name: 'second'
<MenuScreen>:
MDToolbar:
title: "Menu Screen"
pos_hint: {"top": 1}
anchor_title: "center"
md_bg_color: (0/255, 0/255, 0/255, 1)
Image:
source: "Logo_h_black.png"
pos_hint: {"center_x": 0.5, "center_y": 0.75}
size_hint_x: (0.25)
size_hint_y: (0.25)
MDTextField:
id: input_username
hint_text: "Username"
size_hint: (0.5, 0.1)
pos_hint: {"center_x": 0.5, "center_y": 0.55}
font_size: 20
mode: "rectangle"
MDTextField:
id: input_password
hint_text: "Password"
size_hint: (0.5, 0.1)
pos_hint: {"center_x": 0.5, "center_y": 0.45}
font_size: 20
mode: "rectangle"
MDFillRoundFlatButton:
text: "LOG IN"
font_size: 17
pos_hint: {"center_x": 0.5, "center_y": 0.25}
on_press: app.loginFunction()
<SecondScreen>:
MDLabel:
text: 'Profile'
halign: 'center'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class SecondScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SecondScreen(name='second'))
class myApp(MDApp):
def loginFunction(self, args=None):
if args is None:
args = sys.argv
mainScreenInstance = sm.get_screen('menu')
username = mainScreenInstance.ids["input_username"].text
password = mainScreenInstance.ids["input_password"].text
print (username)
print (password)
def build(self):
screen = Builder.load_string(screen_helper)
return screen
myApp().run()
The problem is that your loginFunction is trying to get the mainScreenInstance from sm, but sm is created before the screen_helper is loaded, so it doesn't know about the ids you have defined in your screen_helper. Also, that sm is not actually used as part of you GUI, it is just ignored (except for your reference to it in the loginFunction).
So, I recommend that you eliminate the following lines completely:
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SecondScreen(name='second'))
And change loginFunction to not use sm by replacing:
mainScreenInstance = sm.get_screen('menu')
with:
mainScreenInstance = self.root.get_screen('menu')
You're duplicating the widget definitions and then not using them in code. Finally, you're overwriting the Screen manager from the screen_helper string with a new instance. Tbh I did some of that when I started learning Kivy. The kv language is confusing at first but once you get it is beautiful. This version should work (I haven't tested it since I haven't found an easy way to install kivymd on my phone's dev env):
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
import sys
screen_helper = """
ScreenManager:
MenuScreen:
name: 'menu'
SecondScreen:
name: 'second'
<MenuScreen>:
MDToolbar:
title: "Menu Screen"
pos_hint: {"top": 1}
anchor_title: "center"
md_bg_color: (0, 0, 0, 1)
Image:
source: "Logo_h_black.png"
pos_hint: {"center_x": 0.5, "center_y": 0.75}
size_hint_x: (0.25)
size_hint_y: (0.25)
MDTextField:
id: input_username
hint_text: "Username"
size_hint: (0.5, 0.1)
pos_hint: {"center_x": 0.5, "center_y": 0.55}
font_size: 20
mode: "rectangle"
MDTextField:
id: input_password
hint_text: "Password"
size_hint: (0.5, 0.1)
pos_hint: {"center_x": 0.5, "center_y": 0.45}
font_size: 20
mode: "rectangle"
MDFillRoundFlatButton:
text: "LOG IN"
font_size: 17
pos_hint: {"center_x": 0.5, "center_y": 0.25}
on_press: app.loginFunction()
<SecondScreen>:
MDLabel:
text: 'Profile'
halign: 'center'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class SecondScreen(Screen):
pass
class myApp(MDApp):
sm = None
def on_start():
self.sm = self.root
def loginFunction(self, args=None):
if args is None:
args = sys.argv
mainScreenInstance = self.sm.get_screen('menu')
username = mainScreenInstance.ids["input_username"].text
password = mainScreenInstance.ids["input_password"].text
print (username)
print (password)
# if self.is_login_correct(username, password):
# self.sm.current('second')
def build(self):
return Builder.load_string(screen_helper)
myApp().run()
Personally, I would move all login-related functions to the MenuScreen class, for consistency.
When I try to grab the Text value from my TextField, I always get empty. At the same time, if I set the default text value, for example "123", then regardless of whether I enter anything into my TextField into the console, I still get "123". I had a guess that it might be due to some kind of screen duplication, but when I call self.root.get_screen ('registration'). Ids, I get three different ids, i.e. there is no duplication. I will be glad for your help <3
my.kv
<RegistrationScreen>:
name: "registration"
MDCard:
size_hint: None, None
size: 400, 600
orientation: "vertical"
pos_hint: {"center_x": 0.5, "center_y": 0.5}
padding: 15
spacing: 50
MDLabel:
text: "Регистрация"
font_name: 'fonts/montserrat-bold.ttf'
font_size: 20
color: .43, 0, .48, 1
halign: "center"
BoxLayout:
size_hint: None, None
size: 200, 160
pos_hint: {"center_x": 0.5}
orientation: "vertical"
MDTextField:
id: pomogite
hint_text: "Rectangle mode"
mode: "rectangle"
helper_text_mode: "on_focus"
hint_text: "Введите логин"
helper_text: "Минимум 6 символов (a-z, A-Z, 0-9)"
icon_right: "account"
color_mode: 'custom'
line_color_focus: .43, 0, .48, 1
size_hint_x: None
width: 250
pos_hint: {"center_x": .5, "center_y": .3}
text: "Начинайте ввод"
MDTextField:
id: textfield_password
hint_text: "Rectangle mode"
mode: "rectangle"
helper_text_mode: "on_focus"
hint_text: "Введите пароль"
helper_text: "Минимум 6 символов (a-z, A-Z, 0-9)"
icon_right: "form-textbox-password"
color_mode: 'custom'
line_color_focus: .43, 0, .48, 1
size_hint_x: None
width: 250
pos_hint: {"center_x": .5, "center_y": .3}
MDRectangleFlatButton:
id: reg
text: "Регистрация"
theme_text_color: "Custom"
text_color: .43, 0, .48, 1
line_color: .43, 0, .48, 1
pos_hint: {"center_x": .5}
on_press: app.registration()
main.py
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from client import Client
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.textfield import MDTextField
sm = ScreenManager()
class LoadingScreen(Screen):
pass
class AuthorizationScreen(Screen):
pass
class RegistrationScreen(Screen):
pass
class MyApp(MDApp):
def build(self):
sm.add_widget(LoadingScreen(name='loading'))
sm.add_widget(AuthorizationScreen(name='authorization'))
sm.add_widget(RegistrationScreen(name='registration'))
sm.switch_to(AuthorizationScreen())
return sm
def fff(self):
self.screen.ids.text_field_error.error = True
sm.switch_to(LoadingScreen())
def registration(self):
addwindow_instance = self.root.get_screen('registration')
print(addwindow_instance.ids)
print(addwindow_instance.ids["pomogite"].text)
MyApp().run()
A couple errors in your code, Whenever you use a classname followed by (), you are creating a new instance of that class. So the line:
sm.switch_to(AuthorizationScreen())
creates a new instance of AuthorizationScreen, in addition to the one already created by the line:
sm.add_widget(AuthorizationScreen(name='authorization'))
A better approach is to use sm.current = rather than sm.switch_to, like this:
def build(self):
sm.add_widget(LoadingScreen(name='loading'))
sm.add_widget(AuthorizationScreen(name='authorization'))
sm.add_widget(RegistrationScreen(name='registration'))
sm.current = 'authorization'
return sm
This switched the current screen to the already existing AuthorizationScreen instance. Or, even simpler, just place the AuthorizationScreen as the first added Screen and it will become the current Screen:
def build(self):
sm.add_widget(AuthorizationScreen(name='authorization'))
sm.add_widget(LoadingScreen(name='loading'))
sm.add_widget(RegistrationScreen(name='registration'))
return sm
The same error appears in your fff() method in the line:
sm.switch_to(LoadingScreen())
which is creating a new instance of LoadingScreen rather than using the already existing one. That line should probably be:
sm.current = 'loading'
I am having trouble with MDTextField. It carries on displaying the hint inside the textfield while typing. I have tried setting the background color to hide it but that didn't work. I have looked at a few tutorials and everyone seems to be doing it the same way as me and it just works for other people so i feel i have done something really wrong.
Image of what happens this is my first post so i am not aloud to post images :)
Any help will be greatly appreciated. Thanks in advance.
main.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.core.window import Windowfrom kivy.config import Config
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.theming import ThemeManager
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.graphics import Rectangle, Color
import pymysql
class WelcomeScreen(Screen):
pass
class LoginScreen(Screen):
pass
class RegisterScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class MainApp(MDApp):
def build(self):
# theme_cls = ThemeManager()
return Builder.load_file("main.kv")
def change_screen(self, screen, direction):
self.root.transition.direction = direction
self.root.current = screen
if __name__ == "__main__":
MainApp().run()
main.kv
#: import Window kivy.core.window.Window
#: import MDLabel kivymd.uix.label.MDLabel
#: import Rectangle kivy.graphics.Rectangle
#: import Color kivy.graphics.Rectangle
WindowManager:
WelcomeScreen:
LoginScreen:
RegisterScreen:
<WelcomeScreen>:
name: "welcome_screen"
FloatLayout:
orientation: "vertical"
MDToolbar:
id: toolbar
title: "SecureIT 24/7"
pos_hint: {'top': 1}
Button:
text: 'Login'
color: 1, 1, 1, 1
size_hint: 0.25, 0.25
pos_hint: {"right":0.625, "top":0.80}
on_release:
app.root.current = "login_screen"
Button:
text: 'Register'
color: 1,1,1,1
size_hint: 0.25, 0.25
pos_hint: {"right":0.625, "top":0.55 }
on_release:
app.root.current = "register_screen"
<LoginScreen>:
name: "login_screen"
FloatLayout:
MDBanner:
id: banner
text: "Login"
# The widget that is under the banner.
# It will be shifted down to the height of the banner.
MDToolbar:
id: toolbar
title: "Login"
elevation: 10
pos_hint: {'top': 1}
left_action_items: [['arrow-left', lambda screen: app.change_screen('welcome_screen', 'right')]]
FloatLayout:
padding: [50,50,50,50]
spacing: 50
FloatLayout:
orientation: 'vertical'
Label:
text: 'Login'
font_size: 18
halign: 'center'
text_size: root.width-20, 20
color: 0,0,0,1
pos_hint: {"right":1, "top":1.25}
TextInput:
id: login
multiline:False
font_size: 28
size_hint: 0.50, 0.10
pos_hint: {"right":0.75, "top":0.70}
FloatLayout:
orientation: 'vertical'
Label:
text: 'Password'
halign: 'center'
font_size: 18
text_size: root.width-20, 20
color: 0,0,0,1
TextInput:
id: password
multiline:False
password:True
font_size: 28
size_hint: 0.50, 0.10
pos_hint: {"right":0.75, "top":0.45}
Button:
text: 'Login'
size_hint: 0.25, 0.25
font_size: 24
pos_hint: {"right":0.625, "top":0.30}
<WhiteLabel#MDLabel>
height: self.texture_size[1]
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
<CustomInput#MDTextField>
multiline:False
# required: True
mode: "line"
pos_hint: {"right": 0.456}
current_hint_text_color: [0,0,0,0.5]
<RegisterScreen>:
name: "register_screen"
FloatLayout:
MDBanner:
id: banner
text: "ioshrdioaoisdhf"
MDToolbar:
id: toolbar
title: "Register"
elevation: 10
pos_hint: {'top': 1}
left_action_items: [['arrow-left', lambda screen: app.change_screen('welcome_screen', 'right')]]
BoxLayout:
orientation: "vertical"
height: self.minimum_height * 2
size_hint_y: None
pos_hint: {"top": 2}
CustomInput:
id: firstname
hint_text: "color_mode = 'custom'"
CustomInput:
id: surname
hint_text: 'Surname'
CustomInput:
id: email
hint_text: 'Email'
By naming your kv file as main.kv, you are taking advantage of the automatic loading of correctly named kv files as described in the documentation. However, you are also loading the same file using Builder.load_file("main.kv"). Loading the same kv file more than once can cause the sort of problems you are seeing. You can fix your problem by simply eliminating the call to Builder.load_file("main.kv"), or removing the entire build() method, or by changing the name of either the kv file or the MainApp class.
I'm trying to use the id function to reference text_input from MDTextField, however I can't understand how does the id function works. Does anyone know what is wrong in my code?
The first code is the Main App and the second one is where all the widgets are. I've already searched for a solution in internet, but I can't understand why my code does not work.
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from Screen_helper import Home
class MenuScreen(Screen):
pass
class ProfileScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MenuScreen(name='Menu'))
sm.add_widget(MenuScreen(name='Profile'))
class Mainapp(MDApp):
def build(self):
screen = Screen()
helper = Builder.load_string(Home)
screen.add_widget(helper)
key = self.root.ids.username_input
return screen
Mainapp().run()
Home = '''
ScreenManager:
MenuScreen:
ProfileScreen:
<MenuScreen>:
name: 'Menu'
MDRectangleFlatButton:
id: my_button
text: 'Profile'
pos_hint: {'center_x': 0.5, 'center_y': 0.1}
on_press: root.manager.current = 'Profile'
MDTextField:
id: username_input
input_filter: "int"
hint_text: 'CHIAVE NUMERICA'
helper_text: 'compresa tra 0 e 95'
helper_text_mode: 'on_focus'
icon_right: 'key-variant'
icon_right_color: app.theme_cls.primary_color
pos_hint: {'center_x':0.5,'center_y':0.55}
size_hint_x:None
width:230
input_filter: 'int'
<ProfileScreen>:
name: 'Profile'
MDLabel:
text: 'Welcome'
halign: 'center'
MDRectangleFlatButton:
text: 'back'
pos_hint: {'center_x': 0.5, 'center_y': 0.3}
on_press: root.manager.current = 'Menu' '''
Give an id to the MenuScreen class and then access to the widget.
Add this to the kv file.
<MenuScreen>:
id: menu
To access the widget you can now do this in python:
key = self.root.menu.ids.username_input