使用不带.kv文件的屏幕管理器的一些麻烦

时间:2019-08-14 01:32:49

标签: python oop kivy

我正在尝试使用Pthon和kivy进行应用程序。我正在其中的“登录/注册”部分。我正在尝试为每个屏幕(登录和注册)创建一个屏幕,并将它们与ScreenManager连接,但是没有.kv文件。如果不可能的话,我想在.kv文件中写的越少越好

我看过一些教程,说我必须为每个窗口类继承“ Screen”并为ScreenManager创建一个类。然后,在.kv文件中,为每个类设置“名称”变量。之后,我应该在'on_click'函数中使用'root.app.current ='。我试过只用python,然后再用一点KvLang来做,但是没有用。

我尝试使用代码的注释部分,但也没有用

.py文件

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition


class ScreenManagement(ScreenManager):
    def __init__(self, **kwargs):
        super(ScreenManagement, self).__init__(**kwargs)
        #self.transition = FadeTransition()
        #self.add_widget(RegisterWindow(name='register'))
        #self.add_widget(LoginWindow(name='login'))

    def screen_transition(self, *args):
        self.current = 'register'


class RegisterWindow(Screen, FloatLayout):
    def __init__(self, **kwargs):
        super(RegisterWindow, self).__init__(**kwargs)
        self.name = 'register'
        self.add_widget(Label(text='Username', size_hint=(.45, .1), pos_hint={'x': .05, 'y': .7}))
        self.username = TextInput(multiline=False, size_hint=(.45, .1), pos_hint={'x': .5, 'y': .7})
        self.add_widget(self.username)
        self.add_widget(Label(text='Password', size_hint=(.45, .1), pos_hint={'x': .05, 'y': .5}))
        self.password = TextInput(multiline=False, password=True, size_hint=(.45, .1), pos_hint={'x': .5, 'y': .5})
        self.add_widget(self.password)
        self.add_widget(Label(text='E-mail', size_hint=(.45, .1), pos_hint={'x': .05, 'y': .3}))
        self.email = TextInput(multiline=False, size_hint=(.45, .1), pos_hint={'x': .5, 'y': .3})
        self.add_widget(self.email)
        self.btn = Button(text='Register', size_hint=(.9, .2), pos_hint={'center_x': .5, 'y': .03})
        self.add_widget(self.btn)
        self.btn.bind(on_press=self.submit)

    def submit(self, instance):
        username = self.username.text
        password = self.password.text
        email = self.email.text

        info = {'Username': username,
                'Password': password,
                'Email': email}

        file = open('data.csv', 'a+')
        file.write(f'{info["Username"]},{info["Password"]},{info["Email"]}\n')
        file.close()

        self.username.text = ''
        self.password.text = ''
        self.email.text = ''

        print(info)


class LoginWindow(Screen, FloatLayout):
        def __init__(self, **kwargs):
            super(LoginWindow, self).__init__(**kwargs)
            self.name = 'login'
            self.btn2 = Button(text='Go')
            self.add_widget(self.btn2)
            self.btn2.bind(on_press = ScreenManagement().screen_transition())


class Application(App):
    def build(self):
        return LoginWindow()


if __name__ == "__main__":
    Application().run()

.kv文件

#:import FadeTransition kivy.uix.screenmanager.FadeTransition

ScreenManagement:
    transition: FadeTransition()
    RegisterWindow:
        name: 'register'
    LoginWindow:
        name: 'login'

它引发异常:kivy.uix.screenmanager.ScreenManagerException:没有名称为“ register”的屏幕。

2 个答案:

答案 0 :(得分:1)

您实际上根本不需要任何kv。这是不含kv的代码版本:

from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition


class ScreenManagement(ScreenManager):
    def __init__(self, **kwargs):
        super(ScreenManagement, self).__init__(**kwargs)


class RegisterWindow(Screen):
    def __init__(self, **kwargs):
        super(RegisterWindow, self).__init__(**kwargs)
        self.add_widget(Label(text='Username', size_hint=(.45, .1), pos_hint={'x': .05, 'y': .7}))
        self.username = TextInput(multiline=False, size_hint=(.45, .1), pos_hint={'x': .5, 'y': .7})
        self.add_widget(self.username)
        self.add_widget(Label(text='Password', size_hint=(.45, .1), pos_hint={'x': .05, 'y': .5}))
        self.password = TextInput(multiline=False, password=True, size_hint=(.45, .1), pos_hint={'x': .5, 'y': .5})
        self.add_widget(self.password)
        self.add_widget(Label(text='E-mail', size_hint=(.45, .1), pos_hint={'x': .05, 'y': .3}))
        self.email = TextInput(multiline=False, size_hint=(.45, .1), pos_hint={'x': .5, 'y': .3})
        self.add_widget(self.email)
        self.btn = Button(text='Register', size_hint=(.9, .2), pos_hint={'center_x': .5, 'y': .03})
        self.add_widget(self.btn)
        self.btn.bind(on_press=self.submit)

    def submit(self, instance):
        username = self.username.text
        password = self.password.text
        email = self.email.text

        info = {'Username': username,
                'Password': password,
                'Email': email}

        file = open('data.csv', 'a+')
        file.write(f'{info["Username"]},{info["Password"]},{info["Email"]}\n')
        file.close()

        self.username.text = ''
        self.password.text = ''
        self.email.text = ''

        print(info)


class LoginWindow(Screen):
        def __init__(self, **kwargs):
            super(LoginWindow, self).__init__(**kwargs)
            self.btn2 = Button(text='Go')
            self.add_widget(self.btn2)
            self.btn2.bind(on_press = self.screen_transition)

        def screen_transition(self, *args):
            self.manager.current = 'register'


class Application(App):
    def build(self):
        sm = ScreenManagement(transition=FadeTransition())
        sm.add_widget(LoginWindow(name='login'))
        sm.add_widget(RegisterWindow(name='register'))
        return sm


if __name__ == "__main__":
    Application().run()

主要更改是ScreenManagement Screens方法中App实例和子build()的构建。同样,将Go Button的绑定更改为同一类中的screen_transition()方法。并且您的Screen类不需要扩展FloatLayoutScreenRelativeLayout)。

答案 1 :(得分:0)

错误-ScreenManagerException

   File ".../main.py", line 17, in screen_transition
     self.current = 'register'
   File "kivy/properties.pyx", line 497, in kivy.properties.Property.__set__
   File "kivy/properties.pyx", line 544, in kivy.properties.Property.set
   File "kivy/properties.pyx", line 599, in kivy.properties.Property.dispatch
   File "kivy/_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
   File "kivy/_event.pyx", line 1120, in kivy._event.EventObservers._dispatch
   File "/usr/local/lib/python3.7/dist-packages/kivy/uix/screenmanager.py", line 1038, in on_current
     screen = self.get_screen(value)
   File "/usr/local/lib/python3.7/dist-packages/kivy/uix/screenmanager.py", line 1064, in get_screen
     raise ScreenManagerException('No Screen with name "%s".' % name)
 kivy.uix.screenmanager.ScreenManagerException: No Screen with name "register".

根本原因

当Kivy试图切换到屏幕名称,即代码中的'register',方法self.current = 'register'中的screen_transition()时发生错误。

运行Kivy应用程序时,有两个ScreenManagement实例。其中一个是通过kv文件ScreenManagement:创建的,另一个是通过Python代码ScreenManagement().screen_transition()创建的。在kv文件中创建的实例具有屏幕名称'register''login'。而用Python代码创建的一个不包含屏幕名称'register''login'

解决方案

需要以下增强功能才能解决该问题。

kv文件

  1. 用类规则ScreenManagement:替换根规则<ScreenManagement>:

摘要-kv文件

#:import FadeTransition kivy.uix.screenmanager.FadeTransition

<ScreenManagement>:
    transition: FadeTransition()
    RegisterWindow:
        name: 'register'
    LoginWindow:
        name: 'login'

py文件

  1. 实施方法callback清除小部件并添加小部件
  2. self.btn2.bind(on_press=ScreenManagement().screen_transition())替换为self.btn2.bind(on_press=self.callback)
  3. 使用关键字pass删除ScreenManagement类中的所有方法

代码段-py文件

class ScreenManagement(ScreenManager):
    pass

...

class LoginWindow(Screen, FloatLayout):
    def __init__(self, **kwargs):
        super(LoginWindow, self).__init__(**kwargs)
        ...
        self.btn2.bind(on_press=self.callback)

    def callback(self, instance):
        self.clear_widgets()
        self.add_widget(ScreenManagement())

输出

Result