Split Screen in Kivy? - python

I want to create a simple app in Kivy, but I want to split the main display in two sections. The top part will have some buttons and it will stay fixed. However, in the bottom part I want to switch between different screens. Is this possible?
Here is a simplified version:
<home screen>:
BoxLayout:
Button:
Screen:
(Switch between Screen 1, and 2)
<screen 1>
<screen 2>
I would really appreciate some help. Thank you!
Ok, here is my non working example.
.py File:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
class HomeScreen(Screen):
pass
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class SplitScreenApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(HomeScreen(name='home_screen'))
sm.add_widget(Screen1(name='screen_one'))
sm.add_widget(Screen2(name='screen_two'))
return sm
if __name__ == "__main__":
SplitScreenApp().run()
.kv File
<HomeScreen>:
BoxLayout:
orientation: 'vertical'
rows: 3
ScreenManager:
size_hint_y: 0.8
Button:
size_hint_y: 0.1
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'screen_one'
Button:
size_hint_y: 0.1
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'screen_two'
<Screen1>:
BoxLayout:
orientation: 'vertical'
rows: 1
Button:
text: "Screen 1"
<Screen2>:
BoxLayout:
orientation: 'vertical'
rows: 1
Button:
text: "Screen 2"
So I expect to see "Screen 1" show first on top of the two Buttons. Then, I can press one of the two in "HomeScreen" and it will switch between "Screen 1" and "Screen 2" on press.

Certainly, just replace Screen with ScreenManager in your example and add whatever Screens you like to it.
If you have a specific problem, post an example with real code demonstrating what you think should work and how it fails.

You lack a reference to the screenmanager object, and your homescreen should be just another screen under the screenmanager, with the buttons on a separate Layout.
Have you checked out the examples which come with kivy? The 'showcase' one does pretty much exactly what you want.

I ask this a while back - and based on the feedback I received here I got the following code working for me. Perhaps, this will help someone else.
Python File:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
class HomeScreen(BoxLayout):
pass
class Screen1(Screen):
pass
class SplitScreenApp(App):
def build(self):
return HomeScreen()
if __name__ == "__main__":
SplitScreenApp().run()
Kivy Code:
<HomeScreen>:
name: 'ScreenManager'
BoxLayout:
orientation: 'vertical'
rows: 3
ScreenManager:
id: sm
size_hint_y: 0.8
Screen1:
Screen:
name: "screen_two"
BoxLayout:
orientation: 'vertical'
rows: 1
Button:
text: "Screen 2"
on_release: sm.current = 'screen_one'
Button:
text: "Screen 1"
size_hint_y: 0.1
on_press:
sm.transition.direction = 'left'
sm.current = 'screen_one'
Button:
text: "Screen 2"
size_hint_y: 0.1
on_press:
sm.transition.direction = 'left'
sm.current = 'screen_two'
<Screen1>:
name: "screen_one"
BoxLayout:
orientation: 'vertical'
rows: 1
Button:
text: "Screen 1 Out"
on_release: root.parent.current = 'screen_two'
Thanks again to everybody that is willing to help here.

Related

Recup input value through screen manager kivy

I want to catch a value from my first screen into my thirdscreen.
In the first, I write my name in an input field.
I go to the next window.
And I try to show my name in this last window.
So I share the code with you and I hope I will find an issue.
Python code :
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
#define ou different screens
class FirstWindow(Screen):
def envoyer(self):
name = self.ids.nom_input.text
self.ids.my_name.text = name
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
#PROBLEM HERE
def on_press(self):
self.ids.recup_infos.text = self.root.get_screen('FirstWindow').ids.my_name.text
class WindowManager(ScreenManager):
pass
class MonWidget(Widget):
pass
kv = Builder.load_file('new_window.kv')
class AwesomeApp(App):
def build(self):
Window.clearcolor = (0,0,0,0)
return kv
if __name__ == '__main__':
AwesomeApp().run()
My KV CODE :
WindowManager:
FirstWindow:
SecondWindow:
ThirdWindow:
<FirstWindow>:
name: "romain"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
id: my_name
text: "Entrez votre nom"
font_size: 32
TextInput:
id: nom_input
multiline: False
size_hint: (1, .5)
Button:
text: "Next screen"
font_size: 32
on_press: root.envoyer()
on_release:
app.root.current = "Mickael"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "Mickael"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Entre votre ville"
font_size: 32
TextInput:
id: ville_input
multiline: False
size_hint: (1, .5)
Button:
text: "VĂ©rifier les infos"
font_size: 32
on_release:
app.root.current = "foncier"
root.manager.transition.direction = "left"
Button:
text: "go back first screen"
font_size: 32
on_release:
app.root.current = "romain"
root.manager.transition.direction = "right"
<ThirdWindow>:
name: "foncier"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Verifier : "
font_size: 32
Label:
id: recup_infos
text: ""
font_size: 32
color: 'white'
Button:
text: "On press"
font_size: 32
#Problem HERE
on_press: root.on_press()
Button:
text: "Précedent"
font_size: 32
on_release:
app.root.current = "Mickael"
root.manager.transition.direction = "right"
Could you help me ?
Thank you
Romain
In your on_press method:
def on_press(self):
self.ids.recup_infos.text = self.root.get_screen('FirstWindow').ids.my_name.text
self.root.get_screen('FirstWindow').ids.my_name.text isn't the correct way to get access to widgets outside of the class that you are in right now, or in this situation, screen. The correct way is to use the App.get_running_app() method:
self.ids.recup_infos.text = App.get_running_app().root.ids.First.ids.my_name.text
But before doing that, you have to give ids to the screens of your app, so that the First argument of the method demonstrated above actually makes sense:
WindowManager:
FirstWindow:
id: First
# "First" is the id of the FirstWindow class
# which can also explain why there was a "First" arg
# inside "App.get_running_app().root.ids.First.ids.my_name.text"
SecondWindow:
id: Second
ThirdWindow:
id: Third
Still confused to why this works? Let's divide the attributes of App.get_running_app().root.ids.First.ids.my_name.text into 3 parts:
App.get_running_app(): this method returns the location of your running App class, in this case AwesomeApp. This also acts as self if you were to get the variable inside the App object itself
.root.ids.First: if you read the Kivy documentation, or just simply watched Kivy course videos online, carefully, you should know that self.root.ids inside the App object returns a list of ids of the widgets inside your root widget. In this case, App.get_running_app().root.ids is doing the same thing here, and your screens are passed in the ScreenManager root widget, hence make First an available attribute in App.get_running_app().root.ids
.ids.my_name.text: same as above, App.get_running_app().root.ids.First acts the same as self if you were to run it in your FirstWindow class, which gives you the opportunity to get access to variables outside of your working classes/screens

Multiple classes in one screen stops FloatLayout from working correctly

I am trying to incorporate ads into a Kivy app I made, and to do this, I want to have one class (with the ads) in a FloatLayout to be at the top of my screen, and the rest of the app to be below, in a separate class.
I was trying to get this to work with some test code (simple .py and .kv file that has multiple screens and classes and organizes accordingly). The code is supposed to have two float layouts: One has text, the other has a button that you press and it takes you to the next screen. However the issue I am having is that I can't position the button correctly, as it appears that the widget is shrunk in the bottom left corner. It is supposed to be next to the text box.
Here is my .kv file:
WindowManager:
Screen1:
Screen2:
<Screen1>:
name: "screen1"
FloatLayout:
Label:
pos_hint: {'top': 1, "center_x": 0.5}
size_hint: (0.2, 0.5)
font_size: 40
text: "TEXT AT TOP OF SCREEN"
FloatLayout:
TextInput:
pos_hint: {"x": 0.1, "y": 0.05}
size_hint: (0.3, 0.05)
multline:False
GoS:
FloatLayout:
Button:
text: "PRESS TO GO TO SCREEN 2"
pos_hint: {"right": 0.5, "center_y": 0.7}
on_press: widget.goscreen()
<Screen2>:
name: "screen2"
Label:
text: "YOU ARE ON SCREEN TWO"
and here is the .py file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
class Screen1(Screen):
pass
class GoS(Widget):
def goscreen(self):
self.parent.current = "screen2"
class Screen2(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("rec_view.kv")
class TestApp(App):
def build(self):
return kv
if __name__ == "__main__":
TestApp().run()
Why is this happening?
Another small point also is that my button doesn't work because I can't seem to call the correct class. If I use "root.goscreen()", it doesn't work as my root widget doesn't have this function. What should be the correct syntax here?
I recommend you to use BoxLayout to divide your GUI.
Your button don't work because you don't link it to a valid Widget.
The GoS widget must be define in KV or be imported.
Here is a proposition for your rec_view.kv file :
WindowManager:
Screen1:
Screen2:
<GoS>:
Button:
text: "PRESS TO GO TO SCREEN 2"
on_press: root.goscreen()
<Screen1>:
name: "screen1"
BoxLayout:
orientation: "vertical"
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.5 # Proportion of screen height that the widget occupe
Label:
font_size: 40
text: "TEXT AT TOP OF SCREEN"
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.3
TextInput:
multline:False
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.2
GoS:
<Screen2>:
name: "screen2"
Label:
text: "YOU ARE ON SCREEN TWO"
The definition of goscreen is not correct, GoS is not a Screen, so his parent don't have current , use instead App.get_running_app().root.current = "screen2".
I don't know what you want to do and why you define the GoS class, but you can avoid it. By moving the goscreen definition into Screen1 class, and replace the 3rd BoxLayout of Screen1 with this:
BoxLayout:
orientation: "horizontal"
size_hint_y: 0.2
Button:
text: "PRESS TO GO TO SCREEN 2"
on_press: root.goscreen()

Kivy select screen in .py-file and use in .kv-file

I'm trying to make a list of screens and randomly select one of them in this python file (other code is not included here, like builder etc):
class selectionScreen
testScreen = StringProperty('Screen1')
def screenSelector(self)
screenList = ['Screen1', 'Screen2']
testNumber = random.randint(0, 1)
testScreen = screenList[testNumber]
return testscreen
I then want to choose this screen in my .kv-file, which looks somewhat like this, but also includes screen 1 and 2
ScreenManager:
SelectionScreen:
name: 'SelectionScreen'
Screen0:
name: 'Screen0'
Screen1:
name: 'Screen1'
<SelectionScreen>:
BoxLayout:
Button:
text: "Click when ready"
size_hint: .6, .5
font_size: 10
on_press: root.screenSelector()
on_release: root.manager.current = 'Screen0'
<Screen0>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Next"
on_release: root.manager.current = str(root.testScreen)
The SelectionScreen is working fine, but now I am not able to reach screen0. When removing the line
on_press: root.screenSelector()
I can, however, do this.
Thank you in advance for any help!
Problem
You are not able to reach screen0 because it is not in your screenList.
The variable, testScreen defined in method screenSelector is a local variable, which is not the same class variable, testScreen defined in class selectionScreen.
Undefined variable, return testscreen due to typo error.
At Screen0, the code, on_release: root.manager.current = str(root.testScreen) will cause an AttributeError: 'Screen0' object has no attribute 'testScreen'
Solution
In order to reach Screen0, you have to do the following:
Python Script
Add Screen0 into the variable, screenList
Replace random.randint(0, 1) with random.randint(0, 2)
Replace testScreen with self.testScreen in method screenSelector
kv file
Define an id, e.g. id: selection_screen
Reference it, e.g. root.manager.ids.selection_screen.testScreen
Add on_press call to screenSelector in the other screens, e.g. on_press: root.manager.ids.selection_screen.screenSelector()
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import StringProperty
import random
class ScreenManager(ScreenManager):
pass
class SelectionScreen(Screen):
testScreen = StringProperty('Screen1')
def screenSelector(self):
screenList = ['Screen0', 'Screen1', 'Screen2']
testNumber = random.randint(0, 2)
self.testScreen = screenList[testNumber]
return self.testScreen
class Screen0(Screen):
pass
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class Test(App):
def build(self):
return ScreenManager()
if __name__ == "__main__":
Test().run()
test.kv
#:kivy 1.10.0
<ScreenManager>:
SelectionScreen:
id: selection_screen
name: 'SelectionScreen'
Screen0:
name: 'Screen0'
Screen1:
name: 'Screen1'
Screen2:
name: 'Screen2'
<SelectionScreen>:
BoxLayout:
Button:
text: "Click when ready"
size_hint: .6, .5
font_size: 10
on_press: root.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
<Screen0>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Screen 0"
on_press: root.manager.ids.selection_screen.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
<Screen1>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Screen 1"
on_press: root.manager.ids.selection_screen.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
<Screen2>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Screen 2"
on_press: root.manager.ids.selection_screen.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
Output

How can I put one label with time on all of my screens

I'm starting with kivy and have some question. I'm have code with couple screens and buttons. How can I put one label with time or something like that on all of my screens? In the below code I created a screens but i don't wanna put 3 separate labels on the individual screens
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import StringProperty, ObjectProperty
from kivy.clock import Clock
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<StartScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Start >'
size_hint_y: None
hight: '40dp'
on_press: root.manager.current = 'second'
<SecondScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Test2'
size_hint_y: None
hight: '40dp'
on_press: root.manager.current = 'end'
<EndScreen>:
BoxLayout:
Button:
text: 'Test3'
size_hint_y: None
hight: '40dp'
on_press: root.manager.current = 'start'
""")
#declarate both screens
class StartScreen(Screen):
pass
class SecondScreen(Screen):
pass
class EndScreen(Screen):
pass
#create the screen manager
sm = ScreenManager()
sm.add_widget(StartScreen(name='start'))
sm.add_widget(SecondScreen(name='second'))
sm.add_widget(EndScreen(name='end'))
class TutorialApp(App):
def build(self):
return sm
if __name__ == '__main__':
TutorialApp().run()
This is one possible solution based on https://stackoverflow.com/a/18926863/6646710
The code below defines a label which displays the time.
import time
class IncrediblyCrudeClock(Label):
def __init__(self, **kwargs):
super(IncrediblyCrudeClock, self).__init__(**kwargs)
Clock.schedule_interval(self.update, 1)
def update(self, *args):
self.text = time.asctime()
The update function gets the current time from the python time module. The time is used to update the text property of the label. In the init method, the clock module is used to schedule calls to this update function each second.
Next I added this Label to all your kivy screens inside the kv string.
<StartScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Start >'
size_hint_y: None
hight: '40dp'
on_press: root.manager.current = 'second'
IncrediblyCrudeClock:
<SecondScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'Test2'
size_hint_y: None
hight: '40dp'
on_press: root.manager.current = 'end'
IncrediblyCrudeClock:
<EndScreen>:
BoxLayout:
Button:
text: 'Test3'
size_hint_y: None
hight: '40dp'
on_press: root.manager.current = 'start'
IncrediblyCrudeClock:
The final result looks like that

How to change a space when a button is pressed with kivy?

I am trying create a GUI by implementing the template of the ComicCreator GUI sample as a template for my own project. The code is easy to follow, but I would like to be able to reconfigure the drawingspace.kv, each time a button is pushed, say for example something like this:
Q: How could I configure the drawingspace.kv to have a different layout with different widgets for each button that is pressed?
A neat way to do this is to use screen.
Since I allready have an example of this app from you earlier question, it was easy to implement the screens, and rewrite the classes a bit.
When a button is pressed, you set the screenmanager's current to whatever the name you named the screen you want.
Then you just edit the layouts as you want inside of each screen, in the kv file, or python file.
I choose to make most of the layout stuff in kv language here. Because I find it easier to develop a layout the way I want it this way.
Later I could rewrite it to python if I want that.
So my python file looks like this now:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen,ScreenManager,NoTransition
from kivy.lang import Builder
import time
Builder.load_file("kv.kv")
class MyLayout(BoxLayout):
def __init__(self,**kwargs):
super(MyLayout,self).__init__(**kwargs)
self.orientation = "vertical"
self.padding = 10
class MainScreen(Screen):
pass
class RemoveScreen(Screen):
pass
class GroupScreen(Screen):
pass
class MyLogo(BoxLayout):
your_time = StringProperty()
def __init__(self,**kwargs):
super(MyLogo,self).__init__(**kwargs)
Clock.schedule_interval(self.set_time, 0.1)
def set_time(self,dt):
self.your_time = time.strftime("%m/%d/%Y %H:%M")
class MyApp(App):
def __init__(self,**kwargs):
super(MyApp,self).__init__(**kwargs)
self.sm = ScreenManager(transition=NoTransition())
self.sm.add_widget(MainScreen(name = "main"))
self.sm.add_widget(RemoveScreen(name = "remove"))
self.sm.add_widget(GroupScreen(name = "group"))
self.sm.current = "main"
def build(self):
return self.sm
if __name__ == "__main__":
MyApp().run()
And kv.kv file looks like this:
#:kivy 1.9.1
<MyButtons#BoxLayout>:
padding: 10,10,10,0
spacing: 10
size_hint: 1,0.3
orientation: "horizontal"
Button:
text: "Clear"
on_press: app.sm.current = "main"
Button:
text: "Remove"
on_press: app.sm.current = "remove"
Button:
text: "Group"
on_press: app.sm.current = "group"
Button:
text: "Color"
Button:
text: "Gestures"
<MyLogo>:
spacing: 10
padding: 10,10,10,0
orientation: "horizontal"
BoxLayout:
orientation: "vertical"
size_hint: 0.3,1
canvas:
Rectangle:
pos: self.pos
size: self.size
AsyncImage
source: 'http://lmsotfy.com/so.png'
Label:
size_hint: 1,0.3
text: root.your_time
color: [0,0,0,1]
Label:
size_hint: 1,0.3
text: "NYC, New York, USA"
color: [0,0,0,1]
<MainScreen>:
MyLayout:
MyLogo:
#Button:
# text: "main"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
<RemoveScreen>:
MyLayout:
MyLogo:
BoxLayout:
orientation: "horizontal"
Label:
font_size: "40sp"
text: "Remove"
Button:
font_size: "20sp"
text: "Remove this or something"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
<GroupScreen>:
MyLayout:
MyLogo:
BoxLayout:
orientation: "vertical"
Label:
font_size: "40sp"
text: "Group"
Button:
font_size: "20sp"
text: "Something groups stuff"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
The layout frame should be a screen manager, and each layout a screen. Screen transitions would be then triggered by pressing the buttons. You can also watch a tutorial here if you don't know how to do this, but the documentation should be enough.

Categories