Screen Manager possible bug(s)

30 views
Skip to first unread message

Juan Francisco López-Egea Martínez

unread,
Apr 4, 2019, 7:32:57 AM4/4/19
to Kivy users support
I'm learning this days about Kivy Screen Manager and I have some undesired/unexpected behaviours I'd like to share with you, perhaps it could be a bug,

The code is a mixture of -created in kv file- and added in main.py, so for document to myself all the possibilities:


main.py:

from kivy.modules import console
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition, WipeTransition, SlideTransition
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
from kivy.factory import Factory
from functools import partial



# ~ class FirstScreen(Screen):
   
# ~ def SwitchToOther(self):
       
# ~ self.manager.current = "SecondScreen"

# ~ class SecondScreen(Screen):
   
# ~ def SwitchToOther(self):
       
# ~ self.manager.current = "FirstScreen"

class test(ScreenManager):
   
    nDs
= None
   
#newDynamicallyCreatedScreen = Screen(name="s3rd", direction="up")
   
   
def SwitchToOther(self, who):
       
print ("Funcion llamada!")
       
print (str(who))
       
print (self.mainsm.current)#Por que no tiene current? > Porque la clase principal test NO puede heredar de "Widget", sino de ScreenManager, que es lo que en realidad es.
       
# ~ if who == "second_screen":
           
# ~ print ("Hola")
       
#if self.mainsm.current == "FirstScreen":#Si estas en la primera pantalla   <<<< POR SCREEN
       
if who == "FirstScreen":#Si la cadena es "FirstScreen"                      <<<< POR String habitual (argumento pasado a una funcion...)
           
self.mainsm.transition.direction = "left"#De esta manera decimos hacia donde va la transicion.
           
self.mainsm.current = "SecondScreen"#De esta manera decimos cual es la "screen" a la que vamos a pasar.
       
#elif self.mainsm.current == "ThirdScreen":  << Por screen
       
elif who == "toNewScreen":#Por argumento (string simple)
           
if not self.mainsm.has_screen("ThirdScreen"):#Tercera screen (la generada fuera del archivo kv). Si existe se crea, si no se pasa a ella sin crear...
               
print ("Ojo que alla vamos")
               
#self.mainsm.transition = FadeTransition()#COMMENT THIS LINE AND THE CODE OF "Vscreen8" will fail (line 52)
               
self.mainsm.switch_to(self.nDs, direction="down")#ASI se usa switch_to, Se anayde al screen manager A LA VEZ que cambias a el... claro que  no podremos usarlo dos veces!!! (...sin quitarlo antes!!?). Hay que probar...
               
#self.mainsm.transition.direction = "down"
               
#self.mainsm.current = "ThirdScreen"
               
print (self.mainsm.children)
           
else:
               
print ("La tercera pantalla ya fue creada!")
               
self.mainsm.transition = SlideTransition()
               
self.mainsm.direction = "down"
               
self.mainsm.current = "ThirdScreen"
       
elif who == "Vscreens8":
           
self.mainsm.transition = SlideTransition()
           
self.mainsm.transition.direction = "down"
           
self.mainsm.current = "FirstScreen"#This line will fail if you comment line 39
       
else:
           
self.mainsm.transition.direction = "right"
           
self.mainsm.current = "FirstScreen"
   
   
def nmbOfChildren(self, extra):#Al usar "partial" para llamar a la funcion evitando el AssertionError, hace falta un argumento extra... (ni idea)
       
print ("El padre de Screen Manager es "+str(self.mainsm.parent))
       
print ("El propio Screen Manager es "+str(self.mainsm))
       
print ("Los hijos de Screen Manager... contra todo pronostico, no se muestran con 'children'... "+str(self.mainsm.children))
       
if isinstance(self.mainsm, ScreenManager) and isinstance(self.mainsm, test):
           
print ("Es de ambos tipos!.")
       
elif isinstance(self.mainsm, ScreenManager):
           
print ("Es de tipo screenManager")
       
elif isinstance(self.mainsm, test):
           
print ("Es de tipo test")
       
else:
           
print ("Ni p idea de que tipo es")
       
#print ("El propio manger de Screen Manager es: "+str(self.mainsm.current.manager))
       
print ("El propio nombre de la screen mostrada por Screen Manager es: "+str(self.mainsm.current))
       
print ("El propio nombre de la screen mostrada por Screen Manager es: "+str(self.mainsm.current_screen))
       
if self.mainsm.has_screen("SecondScreen"):#Para saber si existe una screen registrada en el screen manager
           
print ("La segunda pantalla es "+str(self.mainsm.get_screen("SecondScreen")))#Esto DEVUELVE el objeto screen.
           
SegundaPantalla = self.mainsm.get_screen("SecondScreen")# ...como se puede ver aqui.
           
print ("Esto es la segunda pantalla: "+str(SegundaPantalla)+". Es de tipo "+str(type(SegundaPantalla)))# ... y aqui.
           
print ("La 'siguiente' pantalla seria... "+str(self.mainsm.next())+", y la 'anterior' seria... "+str(self.mainsm.previous()))
           
print ("Los NOMBRES de la lista completa (excepto la screen actual) es "+str(self.mainsm.screen_names)+". La lista de OBJETOS y no solo de nombres es asi:\n "+str(self.mainsm.screens))
       
self.mainsm.transition=WipeTransition()
       
self.mainsm.direction="down"
       
self.mainsm.current = "Vscreens8"
   
   
def __init__(self, **kwargs):
       
super(test, self).__init__(**kwargs)
        mainsm
= ObjectProperty(None)
        s1st
= ObjectProperty(None)
        s2nd
= ObjectProperty(None)
       
#        self.mainsm.add_widget(Factory.Scr(name = "ThirdScreen"))#Pero asi no podemos acceder per se a third screen <<< ESTE ES EL BUENO, PERO NO TENEMOS ACCESO A EL
       
#De la siguiente manera SI TENEMOS ACCESO:
       
#Usamos self.nDs en lugar de directametne nDs para poder acceder a el desde varios puntos. La declaracion formal esta arriba, al principio. Necesario para usar el "switch_to" en SwitchToOther.
       
self.nDs = Factory.Scr(name = "ThirdScreen")#Creamos una screen nueva almacenada en la variable nDs con el nombre -obligatorio en la creacion del screen- "ThirdScreen"
        b3tn
= Button(text="Probandoooo....")#Le creamos un boton
       
#b3tn.bind(on_press=self.nmbOfChildren())#Esto da un "assertion Error" porque la funcion "nmbOfChildren()" devuelve "None", y on_press=None es una cagada. La forma correcta es o una funcion Lambda o... (siguiente linea):
        b3tn
.bind(on_press=partial(self.nmbOfChildren))
       
self.nDs.add_widget(b3tn)#Se lo anyadimos...
       
#self.mainsm.add_widget(nDs)#Y anyadimos la propia screen al manager.#NO LO VAMOS A ANYADIR DESDE AQUI, para poder usar la funcion "switch_to" en SwitchToOther.
       
        variasScreens
= []
        variosButtons
= []
       
for i in range (10):
            variasScreens
.append(Factory.Scr(name = "Vscreens"+str(i)))
            variosButtons
.append(Button(text="Vbutton"+str(i)))#Le creamos un boton
            variasScreens
[-1].add_widget(variosButtons[-1])#Se lo anyadimos...
           
if i == 8:
                variosButtons
[-1].bind(on_press=partial(self.SwitchToOther))
           
self.mainsm.add_widget(variasScreens[-1])#Y anyadimos la propia screen al manager.
       
print ("Terminado el proceso de anyadir screens almacenadas en una lista")
   
       
class testApp(App):
   
def build(self):
        prog
= test()
       
return prog

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


And kv file:

#: kivy 1.10.1

   
<Scr@Screen>:#Scr SIEMPRE CON LA PRIMERA LETRA MAYUSCULA
    pos
: 0,0
           
<Test@ScreenManager>:
    mainsm
:screen_manager
    s1st
:first_screen
    s2nd
:second_screen
    boton1
: Btn1
    boton2
: Btn2

    id
:screen_manager

   
Scr:
        id
: first_screen
        name
: 'FirstScreen'
       
Button:
            size_hint
: 0.5, 1.0
            pos
: 0,0
            id
: Btn1
            text
: "First"
            on_press
: root.SwitchToOther("FirstScreen")
           
#on_press:
               
#if self.text == 'a': print 'It is A!'; print 'Sure it is!'#Condition in event in kv file.
               
#else: print 'No.'
       
Button:
            size_hint
: 0.5, 1.0
            pos
: first_screen.width*0.5, 0
            id
: Btn3
            text
: "Third"
            on_press
: root.SwitchToOther("toNewScreen")
       
Label:
            text
: "hola"
   
Scr:
        id
: second_screen
        name
: 'SecondScreen'
       
Button:
            id
:Btn2
            text
: "Second"
            on_press
: root.SwitchToOther("SecondScreen")
           


There is two questions:

A) If you comment line 39 (tell screen manager about use a specific transition... Line 52 will fail (switching to "FirstScreen", that of course, exists). If you uncomment line 39, it works.
Once executed, is click just in "Third", "Probandoo...", "Vbutton8" (that should return you to main/first screen). But... this makes nonsense, a transition mode isn't related with a screen existence.

B) If you test this in an android device with a buildozer generated apk, when you change orientation of the screen, it falls apart the screen, and if you touch one of the button witch corner is still visible, it adapts then perfectly well.
There is any way to force a "redraw" or a touch that does nothing except refresh the screen to get widgets adapted to device screen?.

I hope this example helps if there is a bug finally.
Reply all
Reply to author
Forward
0 new messages