I'm attempting to convert a Widget into a Screen so that I can use Kivy's ScreenManager. However, changing the classes to Screens causes the objects within them to become massively resized and displaced.
user.py
"""User-end software for signup/account data."""
# Import required Kivy modules
from kivy.app import App
# from kivy.uix.widget import Widget
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import StringProperty
# Import regex
import re
# Define ScreenManager
sm = ScreenManager()
class LoginScreen(Screen):
"""Class for login screen contents."""
email = StringProperty() # variable for email from text box
password = StringProperty() # variable for password from text box
def login(self): # check credentials and login if valid
"""Actions for when Login button is pressed."""
if not re.fullmatch(r"[^@]+@[^@]+\.[^@]+", self.email):
self.ids.valid_login.valid_color = (1, 0, 0, 1) # show if invalid
else:
self.ids.valid_login.valid_color = (0, 0, 0, 0) # hide if valid
if self.password != "": # Make sure password isnt empty
None # Search DB for email & check password
def goto_signup(self):
"""Switch to Signup Screen."""
sm.current = 'signup'
class SignupScreen(Screen):
"""Class for signup screen contents."""
email = StringProperty() # variable for email from text box
password = StringProperty() # variable for password from text box
def signup(self): # check credentials and login if valid
"""Actions for when Signup button is pressed."""
if not re.fullmatch(r"[^@]+@[^@]+\.[^@]+", self.email):
self.ids.valid_login.valid_color = (1, 0, 0, 1) # show if invalid
else:
self.ids.valid_login.valid_color = (0, 0, 0, 0) # hide if valid
def goto_login(self):
"""Switch to Signup Screen."""
sm.current = 'login'
class UserApp(App):
"""Main app."""
def build(self):
"""Build app."""
sm.add_widget(LoginScreen(name='login'))
sm.add_widget(SignupScreen(name='signup'))
self.icon = 'graphics/window_icon.png'
self.title = 'Offbox Insurance'
return sm
if __name__ == '__main__':
UserApp().run()
user.kv
#:kivy 1.11.1
<SignupScreen>:
email: email_input.text
password: password_input.text
Widget:
id: valid_login
valid_color:(0, 0, 0, 0)
canvas:
Color:
rgba: self.valid_color
Rectangle: # show/hide this object
size: root.width * 5 / 7 + 6, 46
pos: root.width * 1 / 7 - 3, root.top - 259
Label:
font_size: 20
center_x: root.width / 2
top: root.top + 20
text: "Offbox Insurance"
Label:
font_size: 64
center_x: root.width / 2
top: root.top - 30
text: "Sign up"
Label:
font_size: 20
center_x: root.width / 2
top: root.top - 140
text: "Email"
TextInput:
id: email_input
font_size: 24
height: 40
width: root.width * 5 / 7
center_x: root.width / 2
top: root.top - 216
multiline: False
Label:
font_size: 20
center_x: root.width / 2
top: root.top - 240
text: "Password"
TextInput:
id: password_input
font_size: 24
height: 40
width: root.width * 5 / 7
center_x: root.width / 2
top: root.top - 316
multiline: False
password: True
Button:
font_size: 20
height: 50
center_x: root.width / 2
top: root.top - 380
text: "Sign up"
background_normal: 'graphics/button_up.png'
background_down: 'graphics/button_down.png'
on_press: root.login()
Label:
font_size: 16
center_x: root.width / 2
top: root.height / 12 + 75
text: "Already have an account?"
Button:
font_size: 16
height: 36
center_x: root.width / 2
top: root.height / 12 + 5
text: "Log in"
background_normal: 'graphics/button_up.png'
background_down: 'graphics/button_down.png'
on_press: root.goto_login()
<LoginScreen>:
email: email_input.text
password: password_input.text
Widget:
id: valid_login
valid_color:(0, 0, 0, 0)
canvas:
Color:
rgba: self.valid_color
Rectangle: # show/hide this object
size: root.width * 5 / 7 + 6, 46
pos: root.width * 1 / 7 - 3, root.top - 259
Label:
font_size: 20
center_x: root.width / 2
top: root.top + 20
text: "Offbox Insurance"
Label:
font_size: 64
center_x: root.width / 2
top: root.top - 30
text: "Log in"
Label:
font_size: 20
center_x: root.width / 2
top: root.top - 140
text: "Email"
TextInput:
id: email_input
font_size: 24
height: 40
width: root.width * 5 / 7
center_x: root.width / 2
top: root.top - 216
multiline: False
Label:
font_size: 20
center_x: root.width / 2
top: root.top - 240
text: "Password"
TextInput:
id: password_input
font_size: 24
height: 40
width: root.width * 5 / 7
center_x: root.width / 2
top: root.top - 316
multiline: False
password: True
Button:
font_size: 20
height: 50
center_x: root.width / 2
top: root.top - 380
text: "Log in"
background_normal: 'graphics/button_up.png'
background_down: 'graphics/button_down.png'
on_press: root.login()
Label:
font_size: 16
center_x: root.width / 2
top: root.height / 12 + 75
text: "Don't have an account?"
Button:
font_size: 16
height: 36
center_x: root.width / 2
top: root.height / 12 + 5
text: "Sign up"
background_normal: 'graphics/button_up.png'
background_down: 'graphics/button_down.png'
on_press: root.goto_signup()
I want objects in each screen to be sized and scaled relative to the screen they're in, and each screen should be the same size as the window. This way, the window can be resized and the objects inside will still display properly, while still allowing for a smooth transition between screens.
Here is a re-write of your <LoginScreen>
rule. It uses BoxLayout
(convenient for arranging Widgets
vertically or horizontally) and pos_hint
to position the child Widgets
. In cases where you set the size
of a Widget
inside a Layout
, you normally need to set size_hint
to None
, since it will usually over-ride any size
setting. Here is the modified version of your rule:
<LoginScreen>:
email: email_input.text
password: password_input.text
BoxLayout:
# just using canvas to show extents of the BoxLayout
canvas.before:
Color:
rgba: 1,0,0,1
Rectangle:
size: self.size
pos: self.pos
orientation: 'vertical'
size_hint: None, None
size: self.minimum_size
pos_hint: {'center_x': 0.5, 'top': 1.0}
Widget:
# not sure what is the purpose of this Widget
id: valid_login
valid_color:(0, 0, 0, 0)
canvas:
Color:
rgba: self.valid_color
Rectangle: # show/hide this object
size: root.width * 5 / 7 + 6, 46
pos: root.width * 1 / 7 - 3, root.top - 259
Label:
size_hint: None, None
size: self.texture_size
font_size: 20
pos_hint: {'center_x': 0.5}
text: "Offbox Insurance"
Label:
size_hint: None, None
size: self.texture_size
font_size: 64
pos_hint: {'center_x': 0.5}
text: "Log in"
Label:
size_hint: None, None
size: self.texture_size
font_size: 20
pos_hint: {'center_x': 0.5}
text: "Email"
TextInput:
id: email_input
font_size: 24
size_hint: None, None
height: 40
width: root.width * 5 / 7
pos_hint: {'center_x': 0.5}
multiline: False
Label:
size_hint: None, None
size: self.texture_size
font_size: 20
pos_hint: {'center_x': 0.5}
text: "Password"
TextInput:
id: password_input
font_size: 24
size_hint: None, None
height: 40
width: root.width * 5 / 7
pos_hint: {'center_x': 0.5}
multiline: False
password: True
Button:
size_hint: None, None
size: self.texture_size
font_size: 20
height: 50
pos_hint: {'center_x': 0.5}
text: "Log in"
background_normal: 'graphics/button_up.png'
background_down: 'graphics/button_down.png'
on_press: root.login()
Label:
size_hint: None, None
size: self.texture_size
font_size: 16
pos_hint: {'center_x': 0.5}
text: "Don't have an account?"
Button:
size_hint: None, None
size: self.texture_size
font_size: 16
height: 36
pos_hint: {'center_x': 0.5}
text: "Sign up"
background_normal: 'graphics/button_up.png'
background_down: 'graphics/button_down.png'
on_press: root.goto_signup()
See the size_hint documentation and the pos_hint documentation.