Kivy - 从小部件切换到屏幕时对象会改变大小和位置
Kivy - Objects change size and position when switching from Widget to Screen
我正在尝试将 Widget 转换为 Screen,以便我可以使用 Kivy 的 ScreenManager。但是,将 类 更改为 Screens 会导致其中的对象大幅调整大小并移位。
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()
我希望每个屏幕中的对象都根据它们所在的屏幕调整大小和缩放,并且每个屏幕的大小应与 window 相同。这样,window 可以调整大小,里面的对象仍然可以正确显示,同时仍然允许屏幕之间的平滑过渡。
这是您的 <LoginScreen>
规则的 re-write。它使用BoxLayout
(方便Widgets
竖排或横排)和pos_hint
定位childWidgets
。如果在 Layout
中设置 Widget
的 size
,通常需要将 size_hint
设置为 None
,因为它通常会 over-ride 任何 size
设置。这是您的规则的修改版本:
<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()
参见size_hint documentation and the pos_hint documentation。
我正在尝试将 Widget 转换为 Screen,以便我可以使用 Kivy 的 ScreenManager。但是,将 类 更改为 Screens 会导致其中的对象大幅调整大小并移位。
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()
我希望每个屏幕中的对象都根据它们所在的屏幕调整大小和缩放,并且每个屏幕的大小应与 window 相同。这样,window 可以调整大小,里面的对象仍然可以正确显示,同时仍然允许屏幕之间的平滑过渡。
这是您的 <LoginScreen>
规则的 re-write。它使用BoxLayout
(方便Widgets
竖排或横排)和pos_hint
定位childWidgets
。如果在 Layout
中设置 Widget
的 size
,通常需要将 size_hint
设置为 None
,因为它通常会 over-ride 任何 size
设置。这是您的规则的修改版本:
<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()
参见size_hint documentation and the pos_hint documentation。