Skip to content

Kivy ScreenManager Example

GitHub Repository

AI Transcript provided by KivyWhisper

Hello everybody and welcome back to Kivy School. Today will be the screen manager video.

It's going to be about how to make an app like this where you have multiple screens. So as you can see here, I'm just flipping through multiple screens of this like fake app.

Now, what is a screen manager? A screen manager is used to manage apps with multiple screens, as you can see already. And it's a pre-built solution provided by Kivy itself. Now, let's get started.

The first thing I wanna show just very quickly is most of the information is already here on the Kivy org page. If you have the time, please go read through it. It's very good. There are some notes that I got from the page. The first one is that when you are creating a screen, you absolutely need to give a name to it, right?

So how are you going to give a name to a screen? You're going to, there's two ways.

The first way is to just say name equals when you're making a screen through Python.

The second way is here using Kivy. And in Kivy, you can say just name colon user screen.

Okay, by default, the first screen added to the screen manager will be displayed. You can then change to another screen. Here's the fake app that I've made. This has five screens.

It's going to be the home page, which is this, the settings page, which is this, the user profile, which is this, right? The media page, which is this media screen, and then the trending page, which is like this. In this fake app, I already have five screens, four here, including this initial home screen.

And then now let's go over the code line by line. So what's the first thing you're going to do? You're going to say from Kivy app, import app. That's correct. From Kivy lang, import builder. And all the builder is going to do is load a string. And the string is going to be the KV file that you want to feed for your app. Now you can see in the app, what's the first thing you want for a KV string?

The first thing you want to do is look at the root widget. The root widget is going to be screen manager example, right? Why is it the root widget? Because it doesn't have these angle brackets. If their angle brackets were there, that'd mean it's just a class definition. But when you remove the angle brackets and use just a colon, that means you're actually using the widget.

It's the only one here that doesn't have angle brackets. It's the root widget that is provided by this KV string. Everything else you see here has angle brackets. Now let's go here and say, okay, so what is screen manager example? Now screen manager example here, when you say use the add syntax, that means you just inherit from a base Kivy class. Now in the base Kivy class, it's screen manager.

All this means is because I'm inheriting from a base Kivy class, I don't have to say declare it again as class, screen manager example, screen, right? You don't need to do that. In this KV string, this first line just says import OS OS. Why do I do this? Because later on in the code, I will show that I'm using some OS imports and paths like path.join, path.split. I will show that later.

Let's go here. Again, screen manager example, add screen manager. All that means is I'm using the base screen manager class and I'm defining a new class around it that's going to be custom and it's gonna be extending the original screen manager. Because of this add syntax, I don't need to redefine the class again in the Python. This ID, screen manager ID. And again, by default, the first screen added to the screen manager will be displayed. You can then change to another screen and I have the link here. So here are five screens, start screen, setting screen, user screen, media screen and trending screen.

Now who's the manager? It's always gonna be screen manager. You need to give it names. So you can just do name colon and then any kind of string. Right now I just say start screen in lower case. That way I know it's a string. I know it's the name of the start screen and not the class name. Because if you say something like start screen like this, then you're gonna be confused.

Okay, is this a string or is this a class usage? Or is this a class instance, right? You really make sure that things like multiple things are not named the same. Just very quickly. And again, all of these five pages are very similar. You have a manager, which is always gonna be screen manager, ID for the screens. When your app gets more complicated, you're gonna reference all your widgets by ID and the name of each screen because it says in the docs you should name them.

Then so start screen, setting screen, user screen, media screen and trending screen. Okay, so now what's the next step? I've defined these screens, but I also need to define their class definitions, either through Python or through KV. Let's go to start screen. Now start screen at screen, it's just a regular screen. Then here I'm going to actually use these widgets. I'm not going to define a class definition anymore. I'm actually using an instance of box layout and it's going to be vertical dash and inspector.

Like this, I use the inspector modules. First control E, you can show the inspector. So now I will show you this box layout. This box layout is orientation horizontal. So let's show the parent, right? Or orientation horizontal, the size is one because it's the X axis, 0.1 on the Y axis because it's one tenth of the screen. Now there's four buttons. So let's count one, two, three, four buttons, correct? Then as you can see here, these are just some unit codes to this file right here, which is going to be field here.

It's going to be coming from this material designs icon, web font, the TTF. It's just a very specific font family. And this font family has a lot of icons that are in the material design style. And this is what Kivy MD uses. But because I don't want to have a very heavy project using Kivy MD, I take very specifically just the font that they're using and then use it for my own project, making the project more lightweight because I don't need all the other features of Kivy MD.

I just need their fonts. So here again, I found the font that says for the text, right, it's going to be a transition screen. There's also going to be user screen. There's also going to be media screen. So here, this is this button. Here, this is this button. Here, this is this button. And here it is this button. Okay, next step is this font name, right? What is this font name really? So I'll just very quickly show you with import PDB and set stack trace. So again, I said that this button's on the left, so let's run it. Okay, so what is this?

Let's just check it out, right? Let's copy and paste. Let's ask the app directly using PDB. What is this? Oh, it's just the path to my webfont.ttf, right? Where it's right here, you're going to see in C users, VBox user, desktop, Kivy examples, Kivy X, Kivy example again, C your resources, this font. Okay, so let's break it up very quickly. Okay, what's from the very beginning? What is it? They're right here, it's the os.kit current working directory.

It's this current working directory I'm in. It's going to be this 2024.72 folder, right? But because I know I have to go one up, I want to split it. I want to take off the inner file and then go up one. Why is that the case? Because this zero resources is in an upper level. I'm in here, I want to go up and go here, right? Let's go like this, split the current working directory like so, and I have the head and the tail. I don't need the tail, so I just get one. And then why is this, why can I split it like this, right? Check the type, go like this.

It's going to be a tuple, right? And then the tuples can be indexable. So what is the zeroth element of this tuple? It's going to be the head, right? So I have the very beginning, I don't have the end. At the beginning, and then let's see what else. Now I have the beginning right here. I just want to join it with this file because I know the file location is going to be in zero underscore resources. And then again, I also want to add the web font.

It's three parts. The first part is this head. The second part is going to be zero resources. So let's do it like this, this is the first half. Then this is the second half. Sorry, not second half, but second part. And then this is the third part right here. Right, and I've already kind of pre-constructed my address in my repo, right?

But how do I make this into a complete file location? You simply use ospath.join. And ospath.join will connect all of these and create a cross-platform way of knowing this file location in my repo. Then so let's see it. It will be again, ospath.join. The first half, which is the head of my current working directory, because I'm going up one, and zero resources because I know the folder name of the folder below. And then I add the material design icons web font ttf because I also know the name of the font. So if you go like this, sorry, if you go like this, you will get the font location.

And that is the correct location on my system in my repo. And then we can just compare, see users, there's two slashes here because the first one is an escape character. So it's just escaping itself. So it will, the two slashes will just reduce to one slash when it gets parsed. Users, the box user, desktop, give the examples, give the example, give the example, zero resources and the name of the font. That's all this huge section on font name is. I'm just specifying a font name. And then again, font size DP40 on release. I'm just PDB, you don't need it. What else? You don't need this because it's commented. Similarly, this is text as an image. You don't need this because it's commented out. Again, it's a font name, font size on release, go to the new screen.

And from here, I say root.parent.current, setting screen. So again, let's say, okay, why is there root and parent? So from this PDB, let's check root. Oh, the root is just my screen, which is start screen. If you go right here, the root. But I don't wanna tell the screen to change screens. In order to change screens, you need to tell the screen manager itself to go to a different screen.

So how do you do that? Because I know that start screen right here, is also a child of screen manager. Root, or your root of this button is start screen. Go to the parent of start screen, you will go to screen manager. Then at screen manager, you tell the current screen to be the name of the screen. So, go root, just start screen, root.parent, going to be our screen manager example.

Notice it's not saying screen manager, it's saying screen manager example, because it is an instance of our class that we have defined here in the KV. Here, then we go, okay, let's check the current, right? Root.parent.current. What is it right now? Start screen, right? But we wanna change it to setting screen. And then if PDB were not on, it would just go to the setting screen. That's why these screens need to be named, because the screen manager needs a name, so it knows what screen you're going to. If this screen was not named, you would not be able to do this technique. Next, keep going, keep going, keep going. Then again, you have a button that just says start screen. Right, and then the orientation is vertical, back to start. So, if we go like this, exit. So, the rest of the code and turn off PDB.

So, it's setting screen, at screen. Go here, the setting screen. All it does is have two buttons, back to start, which that's the current screen, to start screen. That's the button that says setting screen, right? Then, I have said, okay, what are we going to do when we press this button? Self.text, the text of this button, is going to be app.getCurrentApp.rootCurrent. Now, why is this important? Because one way of getting to your screen manager is from your widget, going all the way up to your screen manager example, right? From this widget here, this button, I was able to get root, which is start screen, and the start screen's parent, which is screen manager.

There's a second way to get the screen manager. And that second way is using app.getRunningApp. Because usually, you have an app that uses a screen manager, your screen manager should be the root app. So, in order to do that, we just go to app.getRunningApp, go to root, which is our screen manager, and then set the current screen using that way. So, there's two parts to this. The first part is that app.getRunningApp.root is the screen manager example widget, right? And the second part is that this current attribute is actually a string. And this string is a proxy for the actual screen. This is the second way to get to your screen manager. Go app.getRunningApp, right? Gets you your app object.

Now, let's check what the root is. What's root? Going to be your screen manager example. Why is that? Because in my example, and usually, even in your apps, you should be returning a screen manager as your root widget. That way, your screens are handled automatically by the screen manager. So, okay, we're at that point. What next? Why am I doing .current? Why am I able to use .current as a text? App.getRunningApp.root.current. And then, let's just check the type. Let's check the type. What is it? It's a string.

Now, why is this a string? Because actually, up here, we have already defined it as a string, where it's named as start screen. And when you set a new string, the string actually corresponds to a screen that you have created. And this link is created when you define a screen and the name. So the name and the screen are correlated through the screen manager. But as you can see, the .current attribute itself is actually just a string. So I can use the current attribute as the text for self-text. I do not have to type change it into a string, basically. So that's just something to keep in mind. And this string to screen relation is created by you using the screen manager when you say the name is a start screen under the actual screen itself in your KV. Now, there's that.

I've covered this. User screen at screen. This is another box layout. Okay. Setting screen. It's just a vertical box layout. There's two buttons. Back to start. Then setting screen. Or rather, user screen, I'm here. And then here, it's going to be a media screen. Back to start. And it says it's a media screen. And back to start. I have a trending screen. It says trending screen. So that's the KV done.

Now let's check for the Python. It's very quick and very simple. It just says, okay, we need an app class. So this is going to be my screen manager app. I've set the title screen manager example. If you can see here, the title is set to screen manager example. You can also set the icon as well. And then in the build method, as long as you return any root widget, which is returned by builder.load underscore string, which is this KV string up here. And as you can see, the root widget is screen manager. If you want to use a screen manager, you have to return it. In any way, you can also just load a KV. But here I'm loading the KV using builder.load string. This is actually KV, because if you make any kind of random indents, it will complain.

It will say, hey, you had an invalid indentation. Must be multiple of four spaces. So this is actually should be compliant KV code. If you are not compliant, it will complain. And then if name equals main, all this means is that you have, it's just a guard to make sure that this module is called directly. Or otherwise, if it is called as a module, it will not run this code. And then this again, it's just to make the window on top. And then, okay, finally, you are main.py, you're not a module. You make the window on top. Now let's run the app. And then that's the code line by line. Okay, now I've gone through code line by line.

It did say about, I returned screen manager as a root widget. Now the first thing is, okay, how do you switch screens? So again, I've covered it. You're going to check for how to access this screen manager. Again, I'll show you two ways. The first way is from the widget itself. You can go up the tree and then go through some parents and then get to screen manager. If you use the screen manager as your root widget, that's why it's very important to use the screen manager as your root widget. There's the first way, right? Go root.parent, get to the screen manager. The second way is going to be using app.get, running app, right?

Check the root, which should be your screen manager. Then just set the current attribute to be the name of the screen that you have set already in the KV. So I've covered this, root parent. Tell the screen manager itself, there's two ways. Top down and then bottom up. Show this. Now how do you get the current screen? Again, you can get the current screen using this code, which is just ask for the current attribute, right? To go here, just ask for the current attribute.

It will tell you, okay, the attribute is just setting screen, right? Why? Because this is the string you have set as the name of your screen. That will be linked to each other and referenced under your screen manager. I'll just very quickly touch up on proper way to manipulate widgets. For example, if you look at a webpage, right? At the webpage, they have some sort of backend or data type that your widgets will read from or inherit from.

And then one example is look at Facebook, right? Facebook has a webpage and that page itself, all the widgets query the Facebook backend and they display the information accordingly. But because we do not have a backend, I will show you how to manually manipulate widgets instead. Okay, so very quickly, I'm going to touch upon how to manipulate widgets from app.getrunningapp.

And one thing I want to show you is that another example is the Image Painter app. You can watch it on your own if you would like. Now, it's also similar to how to manipulate widget in another screen, which I have combined the example together and changed the text in a button. Basically, what I'm going to do is from this start screen, I'm going to change the text on this media page, right? Now, how are you going to do that? The trick is to use app.getrunningapp.

So in this code right here, you're going to see app.getrunningapp.root, which is going to be the screen manager, then .ids, media screen ID, .ids, media button ID. And then you can see there's extra pair of quotes because that's what PDB has told me. Then I'll just say .text to change the attribute of the text to be changed text from main screen. And I'll change the actual button itself to be changed text in media screen. Press it now. Say, oh, I've changed the text in media screen. And guess what? I've also changed the text from the main screen.

If we start again, I'll show you the original and then I will show you the modified. Start screen, media screen, right? And if I press like this, I have changed the text in the media screen. So you can go here. I've changed the text from the main screen, right? Now we'll go to PDB. Then we'll just go down the list and then see why I have an extra quote in here, which I think will trip up a lot of new Kivy users. But if you use PDB and you just ask the app, you know, hey, what is this really named?

What's going on? Just get the answer from the app directly itself. Don't ever guess anymore. So if you press like this, you can see PDB has started. Now let's check, okay. What's this app.getRunningAppExists, right? And again, what are the usual suspects? Got self, right? You've got arcs, right? So there's no arcs and who's self? The button, because the button's the one I've pressed already, right? So because I've pressed already, that's self. So we are not interested in the button. We're not interested in the arcs.

We're just interested in the app itself. We're going down from the top level of the app. We go app.getRunningApp, right? Now what else are we going to do? Let's check the root widget, right? Which is going to be screen manager because I've set it to be the root widget. Set it to be the root widget right here. Okay, next we're going to go like this. Okay, let's check some IDs. Why? Because I've manually set these IDs. Now the IDs are going to be start screen ID, start screen, setting screen ID settings, right? And again, I've manually set them.

The IDs are right here, right? The IDs are in the KV. So I want to change very specifically the media screen ID, right? So okay, you have app.getRunningApp.rootIDs, then media screen ID, right? So again, we proxy to media screen and why does this work? Why does this work? Because IDs, if you look at this, right? What does this remind you of? It reminds you of like index slicing or in the case of this, it should remind you of a dictionary key element pair because it is.

You check for this. What is this really, right? Let's check the type. It's going to be unobservable dictionary, for all intents and purposes, just a regular dictionary. And then, so you can see right here, you can check for the keys as well as the values. Not values, right? So we're using the ID of media screen ID just to go to media screen and keep going. So now we will be at the media screen.

And again, in the media screen, I've very quickly updated off camera. Now there's going to be IDs here, right? There's star button ID and there's media button ID. So let's look at them and see them in action, right? Now we have star button ID and media button ID. But if you notice, this has an extra quote. This has an extra quote, but these do not, right? So because of that, I noticed, oh, okay. What I need to write down for my key value pair is not gonna be star button ID with a single quotes.

It has to be, or not star button, sorry, media button ID in single quotes. I also need these double quotes. I'll show you. If you go like this and then you check media button ID, right? It's going to be key error. There's no media button ID, but I see it right here. So what's really going on? You're gonna have to do the actual key value pair, which is this guy right here, the entire thing, because why this is the key, everything in front of the colon, everything in front of the colon is the key.

So you're gonna go like this, app.getrunningapp, right click to paste, but everything in front of the colon is your key. And then it should give you the value like this. Okay, right click to paste, enter. Now it gets you the proxy to the button object. So really, you should always use PDB to ask what are things, where are things, and it will tell you some small gotchas, like this one right here, where actually there's an extra quote that you need to add in order to make sure that you go down the dictionary correctly.

Okay, let's just check the directory of this button real quick, and you'll see that there will be a text method. Oh, sorry, there will be a text attribute right here. And then what are we gonna do with this text? Okay, well, we can just change it. We can change the text to whatever you want. So again, this one, like this, right click to copy, right click to paste, dot, text, right? It's media screen.

But because you have access to this widget now, we can change all of its attributes as much as we want. And by changing their attributes, we will change their actual appearance in KV. All right, this has been Kivy School. Thank you for watching. Have a great day.

Article Error Reporting

Message @BadMetrics on the Kivy Discord.