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 中设置 Widgetsize,通常需要将 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