[Kivy] ScreenManager: Problem beim Aufruf einer Methode

Hier werden alle anderen GUI-Toolkits sowie Spezial-Toolkits wie Spiele-Engines behandelt.
Antworten
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Hallöchen zusammen,
ich hätte da mal ein Problem.

Ich habe mit Kivy einen Login gestaltet und möchte nun, dass nach einer erfolgreichen Authentifizierung der "innere Bereich" angezeigt wird. Das möchte ich mit dem Screenmanager realisieren.

Code: Alles auswählen

WindowManager:
    LoginWindow:
    GameWindow:
Im Bereich "LoginWindow" gibt es einen Login-Button.

Code: Alles auswählen

RoundedButton:
            text: "Login"
            pos_hint: {'center_x': .5}
            size_hint: (1, None)
            height: 50
            on_press: app.root.press()
In meiner Pythondatei gibt es die entsprechende Methode dazu.

Code: Alles auswählen

class MyLayout(Widget):

    name = ObjectProperty(None)
    password = ObjectProperty(None)

    def press(self):
        user_hash = hashlib.sha256(self.name.text.encode('utf-8')).hexdigest().upper()
        pass_hash = hashlib.sha256(self.password.text.encode('utf-8')).hexdigest().upper()
        if (user_hash == super_user) and (pass_hash == super_pass):
            print("Das hat geklappt!")
            WindowManager.current = 'GameWindow'
        else:
            print("Du kummst hier net rein!")
Anmerkung: Die Print-Ausgaben dien(t)en nur als visuelle Bestätigung in der Konsole.

Ich bekomme folgende Fehlermeldung:
AttributeError: 'WindowManager' object has no attribute 'press'
Ich meine, klar ... die Methode ist in der Klasse MyLayout und nicht etwa in ...

Code: Alles auswählen

# Define screens
class LoginWindow(Screen):
    pass


class GameWindow(Screen):
    pass


class WindowManager(ScreenManager):
    pass
Aber ich dachte, wenn ich die Methode mit ...

Code: Alles auswählen

 on_press: app.root.press()
... aufrufe, dass das funktionieren sollte.

Offenbar habe ich mal wieder ein grundsätzliches Verständnisproblem, wie das alles mit einander interagiert und vor allem, wie es das nicht tut.

Könnte jemand bitte ein Stichwort in den Raum werfen?

Liebe Grüße
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

wieso steht die Funktion nicht in der Klasse, die auf den Screen der gerade "aktiv" ist bezogen ist?
'pass' ist hier kein muss.

Grüße
Dennis

Edit: Vielleicht kannst du auch mal den vollständigen Code zeigen, das ist dann etwas übersichtlicher und man weis zum Beispiel wo das 'app' hingehört
"When I got the music, I got a place to go" [Rancid, 1993]
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Edit, da inzwischen eine Antwort gekommen ist:
Ja, den Fehler habe ich auch bemerkt.

Ich versuche mich durchzu boxen, aber es will nicht so recht.

Die Klasse MyLayout wird gar nicht benutzt, also habe ich diese entfernt. Totaler Blödsinn. Da hatte ich wohl eine Denkblockade.

Ich denke, dass die Methode on_press in LoginWindow gehört. Das ist ja (eigentlich, aber ... siehe unten) der erste Screen, der natürlich aufgerufen wird.

Code: Alles auswählen

class LoginWindow(Screen):

    name = ObjectProperty(None)
    passw = ObjectProperty(None)

    def press(self):
        user_hash = hashlib.sha256(self.name.text.encode('utf-8')).hexdigest().upper()
        pass_hash = hashlib.sha256(self.passw.text.encode('utf-8')).hexdigest().upper()
        if (user_hash == super_user) and (pass_hash == super_pass):
            print("Das hat geklappt!")
            WindowManager.current = 'GameWindow'
        else:
            print("Du kummst hier net rein!")
Leider ergibt sich daraus ein anderes Problem. Es wird statt dem Screen LoginWindow der Screen GameWindow aufgerufen. Das sollte eigentlich erst nach einem erfolgreichen Login geschehen.
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Ja, ich denke die kompletten Files sind hier der Übersichtlichkeit zuliebe hilfreich:

Code: Alles auswählen

from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
import hashlib

Window.size = (512, 512)

super_user = "9279F4A7C1C145D5AE930FDA23EF386168F6720B4E0F0D3DEE383C5AD8535737"
super_pass = "EE22032527082315A747781829EF1F9195F6AEAC09C0D52DE06EBF9D8C463918"


# Define screens
class LoginWindow(Screen):

    name = ObjectProperty(None)
    passw = ObjectProperty(None)

    def press(self):
        user_hash = hashlib.sha256(self.name.text.encode('utf-8')).hexdigest().upper()
        pass_hash = hashlib.sha256(self.passw.text.encode('utf-8')).hexdigest().upper()
        if (user_hash == super_user) and (pass_hash == super_pass):
            print("Das hat geklappt!")
            WindowManager.current = 'GameWindow'
        else:
            print("Du kummst hier net rein!")


class GameWindow(Screen):
    pass


class WindowManager(ScreenManager):
    pass


kv = Builder.load_file('box_multiscreen.kv')


class Affenquiz(App):

    def build(self):
        Window.clearcolor = (0.8, 0.8, 0.8, 1)
        return kv


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

Code: Alles auswählen

WindowManager:
    LoginWindow:
        name: "login"
    GameWindow:
        name: "game"

<LoginWindow>:

    name:name
    passw:passw

    BoxLayout:
        orientation: "vertical"
        size: root.width, root.height

        spacing: 20
        padding: 20

        canvas.before:
            Rectangle:
                pos: self.pos
                size: self.size
                source: 'monkey.png'

        AnchorLayout:
            anchor_y: 'top'
            BoxLayout:
                orientation: "horizontal"
                size_hint: (1, None)
                height: 50

                Label:
                    text: "Der Quizfelsen"
                    font_size: 50

        BoxLayout:
            orientation: "horizontal"
            size_hint: (1, None)
            height: 50

            Label:
                text: "Benutzer:"
            TextInput:
                id: name
                multiline:False
                background_color: (241/255.0,241/255.0,241/255.0,0.9)

        BoxLayout:
            orientation: "horizontal"
            size_hint: (1, None)
            height: 50

            Label:
                text: "Passwort:"
            TextInput:
                id: passw
                multiline:False
                background_color: (241/255.0,241/255.0,241/255.0,0.9)

        RoundedButton:
            text: "Login"
            pos_hint: {'center_x': .5}
            size_hint: (1, None)
            height: 50
            on_press: root.press()

<GameWindow>:
    Label:
        text: "Der Quizfelsen"
        font_size: 50

<Label>
    font_size: 32
    background_normal: ''
    background_color: (0.9,0.9,0.9,0)
    canvas.before:
        Color:
            rgba: self.background_color
        Rectangle:
            size: self.size
            pos: self.pos
    color: (184/255.0,70/255.0,35/255.0,1)
    bold: True
    outline_color: (1,1,1,1)
    outline_width: 2

<RoundedButton@Button>
    background_color: (0,0,0,0)
    background_normal: ''
    canvas.before:
        Color:
            rgba: (184/255.0,70/255.0,35/255.0,0.9)
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: [25]
ich gehe mal ins Bett. Vielleicht trifft mich der Hammer der Erkenntnis ja spontan im Schlaf.
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

in 'build' musst du deinen ScreenManager unterbringen. Die anderen Klassen bekommen als Argument nur 'Screen' .

Vielleicht hilft dir ein früheres Projekt von mir als Vorlage. Dort arbeite ich auch mit dem ScreenManager:
https://forum-raspberrypi.de/forum/thre ... hgeraeten/

Grüße und viel Erfolg
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Selbst wenn ich das mache ...

Code: Alles auswählen

WindowManager = ScreenManager()
WindowManager.add_widget(LoginWindow(name='login'))
WindowManager.add_widget(GameWindow(name='game'))
... wird noch immer der zweite Screen (GameWindow) beim Start geladen statt dem ersten.

Ich weiß gerade echt nicht, wo mein Denkfehler ist.
Hart mit Bart
User
Beiträge: 25
Registriert: Dienstag 30. Oktober 2018, 12:05

Hach, ein blöder Fehler.

Code: Alles auswählen

<LoginWindow>:

    name:name
    passw:passw
"name" darf ich da nicht verwenden. Das ist ein reserviertes Attribut. :oops:

Jetzt erscheint das LoginWindow, wie es sein sollte.
Benutzeravatar
Dennis89
User
Beiträge: 1123
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

super, sind dann alle Probleme beseitigt?


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Antworten