Kivy Creating screens as variables - python

I have a question about kivy. Is it possible to create screens as variables? Lets say I want to create a new screen with a button inside the kivy application. Is it possible to do that? If so how could you do it??

You just have to create a Screen object that you want to create and add it to the ScreenManager:
screen = Your_Screen(name="some_name")
your_screen_manager.add_widget(screen)
Example:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class TestScreen(Screen):
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
layout = BoxLayout(orientation="vertical")
self.add_widget(layout)
layout.add_widget(Label(text=self.name))
button = Button(text="{}: Add Screen".format(self.name))
layout.add_widget(button)
button.bind(on_press=self.add_screen)
def add_screen(self, *args):
n = len(self.manager.screen_names)
screen = TestScreen(name="screen {}".format(n))
self.manager.add_widget(screen)
self.manager.current = screen.name
# Create the screen manager
sm = ScreenManager()
sm.add_widget(TestScreen(name='screen 0'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()

Related

Substituting text inside buttons with widgets

My app (using kivy) needs to substitute text with widgets inside an unspecified number of buttons using iteration. I don't use kv language. Only the last button displays any content.
My app should display an unspecified number of buttons. Simplified example:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
class Layout(Widget):
def __init__(self, app):
super().__init__()
self.layout = BoxLayout(orientation='vertical', size=Window.size)
contents = ['text1', 'text2', 'text3']
for text in contents:
button = Button(height=300, size_hint=(1, None))
button.text = text
self.layout.add_widget(button)
self.add_widget(self.layout)
class MyApp(App):
def build(self):
self.form = Layout(self)
return self.form
def on_pause(self):
return True
if __name__ in ('__main__', '__android__'):
MyApp().run()
Only instead of text buttons display images with descriptions. I change the code:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
class Layout(Widget):
def __init__(self, app):
super().__init__()
self.layout = BoxLayout(orientation='vertical', size=Window.size)
contents = [('img1', 'text1'), ('img2', 'text2'), ('img3', 'text3')]
for img, text in contents:
button = Button(height=300, size_hint=(1, None))
button_layout = BoxLayout(orientation='vertical', size_hint=(1, 1))
label = Label(text=text)
image = Image(source=f'{img}.jpg', size_hint=(1, 1), allow_stretch=True)
button_layout.add_widget(image)
button_layout.add_widget(label)
button.add_widget(button_layout)
self.layout.add_widget(button)
self.add_widget(self.layout)
class MyApp(App):
def build(self):
self.form = Layout(self)
return self.form
def on_pause(self):
return True
if __name__ in ('__main__', '__android__'):
MyApp().run()
And only the last button displays content.
As far as I can understand, at some point Python automatically gets read of the content of the previous button. How can I prevent it? Also what is the best way to center it?
I'm not a native speaker, so sorry for bad grammar. Thank you in advance.

Doing a ModalView subclass in Kivy messes up position of view and children

I have a very simplistic case of a window with a single button. With a button release I want to pop up a modal view with some text on it. In every button release I create and open an instance of ModalView and it works:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.modalview import ModalView
from kivy.uix.label import Label
class AButton(Button):
def on_release(self, *largs):
view = ModalView(size_hint=(None, None), size=[200, 200])
view.add_widget(Label(text='I am a modal view'))
view.open()
class MyApp(App):
def build(self):
return AButton()
if __name__ == '__main__':
MyApp().run()
Now let's say I want to create a subclass of ModalView so I don't have to specify size_hint and size every time I pop up a modal view. This is the code after that change:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.modalview import ModalView
from kivy.uix.label import Label
from kivy.properties import ListProperty
class AButton(Button):
def on_release(self, *largs):
view = ModalView2()
view.add_widget(Label(text='I am a modal view'))
view.open()
class ModalView2(ModalView):
size_hint = ListProperty([None, None])
size = ListProperty([200, 200])
def __init__(self, **kwargs):
super(ModalView2, self).__init__(**kwargs)
class MyApp(App):
def build(self):
return AButton()
if __name__ == '__main__':
MyApp().run()
ModalView and Label position get totally messed up. I tried with anchor_x and anchor_y in ModalView2 in an attempt to fix the label position with no luck. What am I doing wrong?
The ModalView already has size_hint and size attributes, so you don't need to create new ones, just set the existing attributes to the values you want:
class ModalView2(ModalView):
def __init__(self, **kwargs):
super(ModalView2, self).__init__(**kwargs)
self.size_hint = (None, None)
self.size = (200, 200)

Screen manager issue in kivy

I am experimenting with Kivy. When I tried using a screen manager, when the application runs, there is a black screen, nothing appears
That is my code. I have no idea what is the problem. It seems that the GridLayout doesn't get displayed on the screen.
import kivy
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import *
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class load_file_screen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.my_layout = GridLayout(cols=1)
self.my_layout.cols = 1
self.label = Label(text="Loading files from here")
self.button = Button(text="Click to change")
self.button.bind(on_press=self.changer)
self.my_layout.add_widget(self.label)
self.my_layout.add_widget(self.button)
def changer(self, *args):
self.manager.current = "ViewFile"
class view_file_screen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.my_layout = GridLayout(cols=1)
self.label = Label(text="View File here")
self.button = Button(text="Click to change")
self.button.bind(on_press=self.changer)
self.my_layout.add_widget(self.label)
self.my_layout.add_widget(self.button)
def changer(self, *args):
self.manager.current = "LoadFile"
class my_app(App):
def build(self):
self.my_screen_manger = ScreenManager(transition=SlideTransition())
self.my_screen_manger.add_widget(load_file_screen(name="LoadFile"))
self.my_screen_manger.add_widget(view_file_screen(name="ViewFile"))
# self.my_screen_manger.current = "LoadFile"
return self.my_screen_manger
application = my_app()
application.run()
In both your view_file_screen and your load_file_screen, you need to add the line:
self.add_widget(self.my_layout)
in the __init__() method.

How to display slider value as it changes in python kivy

how do i change the text of a label to the value of the slider immediately.
this is my current code
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label``
class app(App):
def build(self):
layout = BoxLayout(orientation='vertical')
slide = Slider(min=-100, max=100,value=0)
label = Label(text=str(slide.value))
layout.add_widget(slide)
layout.add_widget(label)
return layout
app().run()
i want the answer in python
You need to create a Kivy Property and bind the slider value to an on_ event where you can then update the label's text. Here's one way to do that:
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.properties import NumericProperty
import kivy
kivy.require('1.10.0')
class Container(BoxLayout):
slider_val = NumericProperty(0)
def __init__(self, *args, **kwargs):
super(Container, self).__init__(*args, **kwargs)
self.orientation = 'vertical'
slide = Slider(min=-100, max=100, value=0)
slide.fbind('value', self.on_slider_val)
self.label = Label(text=str(self.slider_val))
self.add_widget(slide)
self.add_widget(self.label)
def on_slider_val(self, instance, val):
self.label.text = str(val)
class app(App):
def build(self):
return Container()
app().run()

widget won't display until screen size changed

I want to make a game and I have chosen Kivy for my GUI, as I have written my backend in Python. I am currently using runTouchApp(appwindow) to run the application, where appwindow is a FloatLayout() object. The way I update my screen is that I run appwindow.clear_widgets() and then appwindow.add_widget(new_screen) where new_screen is the layout object which contains all other widgets.
It worked fine till now, but for some reason I can't understand the widget I add gets loaded properly (according to the cmd running in the background) but won't display till I change the screen size.
Here is a sample code:
import kivy
kivy.require('1.1.1')
from kivy.base import runTouchApp
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
appwindow = FloatLayout()
class MenuScreen():
def build(self):
bg = Image(source = 'Images/bg/bg.jpg',allow_stretch= True,keep_ratio= False)
box = BoxLayout(orientation = 'vertical')
menu_items = []
for i in range (0,4):
button = Button(text = 'Menu item no:'+str(i))
button.bind(state = checkMenuPress)
menu_items.append(button)
for button in menu_items:
box.add_widget(button)
floater = FloatLayout(size = bg.size)
floater.add_widget(bg)
floater.add_widget(box)
floater.size_hint = 1,1
return floater
class SecondScreen():
def build(self):
bg = Image(source = 'Images/bg/bg.jpg',allow_stretch= True,keep_ratio= False)
box = BoxLayout(orientation = 'vertical')
box.add_widget(bg)
return box
def checkMenuPress(button,*args):
if button.state == 'normal':
sc = SecondScreen().build()
appwindow.clear_widgets()
appwindow.add_widget(sc)
if __name__ == '__main__':
menuscreen = MenuScreen().build()
appwindow.add_widget(menuscreen)
runTouchApp(appwindow)
Okay, there are a few things wrong here. To create an app, you should subclass kivy.app.App and have it's build method return the "root" widget. Only this class needs build method: any others are redundant.
Once you have a root widget, it's just a matter of inserting and removing widgets. This is how I would approach it.
import kivy
kivy.require('1.1.1')
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.app import App
class MenuScreen(App):
floater = None
def build(self):
bg = Image(source='Images/bg/bg.jpg',
allow_stretch= True,
keep_ratio= False)
box = BoxLayout(orientation='vertical')
menu_items = []
for i in range(0, 4):
button = Button(text='Menu item no:'+str(i))
button.bind(state=self.checkMenuPress)
menu_items.append(button)
for button in menu_items:
box.add_widget(button)
self.floater = FloatLayout(size=bg.size)
self.floater.add_widget(bg)
self.floater.add_widget(box)
self.floater.size_hint = 1, 1
return self.floater
def checkMenuPress(self, button,*args):
if button.state == 'normal':
self.floater.clear_widgets()
self.floater.add_widget(SecondScreen())
class SecondScreen(FloatLayout):
def __init__(self, **kwargs):
super(SecondScreen, self).__init__(**kwargs)
self.add_widget(Image(source='Images/bg/bg.jpg',
allow_stretch=True,
keep_ratio=False))
if __name__ == '__main__':
MenuScreen().run()
Okay, so here's a quick rework of the example using Screens. It's difficult without knowing what you are trying to do, so if this does not help, try writing summary of the behavior you are looking for.
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
"""
The Screen containing the menu
"""
def __init__(self, sm, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
self.sm = sm # Store a reference to the screen manager
bg = Image(source='Images/bg/bg.jpg',
allow_stretch= True,
keep_ratio= False)
box = BoxLayout(orientation='vertical')
menu_items = []
for i in range(0, 4):
button = Button(text='Menu item no:'+str(i))
button.bind(state=self.check_menu_press)
menu_items.append(button)
for button in menu_items:
box.add_widget(button)
floater = FloatLayout(size=bg.size)
floater.add_widget(bg)
floater.add_widget(box)
floater.size_hint = 1, 1
self.add_widget(floater)
def check_menu_press(self, button, *args):
if button.state == 'normal':
self.sm.current = "second"
class SecondScreen(Screen):
def __init__(self, sm, **kwargs):
super(SecondScreen, self).__init__(**kwargs)
self.add_widget(Image(source='Images/bg/bg.jpg',
allow_stretch=True,
keep_ratio=False))
self.sm = sm # Store a reference to the screen manager
def on_touch_down(self, touch):
self.sm.current = "menu"
class MainApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(sm, name="menu"))
sm.add_widget(SecondScreen(sm, name="second"))
return sm
if __name__ == '__main__':
MainApp().run()
looks like i have found a source of the crashing problem. I had used multi-threading for a server client interaction. i had been using two extra threads, one for the server and another for the client. If i try to integrate the client thread with the GUI it raises another problem. even if the socket.recv() is after the ScreenManager.current = "newscreen" line, the app's screen does not change. it freezes in the way i left it. it resumes only after it gets a message from the server.

Categories

Resources