i made a gui with python kivy with a starting screen that has a button in it which generates new screens when pressed, and it also generates new buttons so its easier to pick the screen i need to get in focus but i can't get it working properly cause i can't generate buttons on the newly made screens
when they aren't in focus, the script only generates buttons for the screen in focus it seems
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager):
def __init__(self, **kwargs):
super(ScreenManagement, self).__init__(**kwargs)
sm = ScreenManagement(transition=FadeTransition())
class newtab(Screen):
def __init__(self, **kwargs):
super(newtab, self).__init__(**kwargs)
self.bt1=(Button(text="New tab", size_hint =(.1, .1) ,pos_hint ={'center_x':.1, 'center_y':.94}))
self.add_widget(self.bt1)
self.bt1.bind(on_release=self.new_tab)
self.txt1 = TextInput(text='',size_hint =(.1, .1), pos_hint ={'center_x':.2, 'center_y':.75}, multiline=True)
self.add_widget(self.txt1)
def transition(self, instance):
self.manager.current = (instance.text)
for item in sm.screen_names:
self.bt2=(Button(text=item, size_hint =(.1, .1) ,pos_hint ={'center_x':(.1*sm.screen_names.index(item)+.1), 'center_y':.84}))
self.add_widget(self.bt2)
self.bt2.bind(on_release=self.transition)
def new_tab(self, *args):
n = len(self.manager.screen_names) ##number of screens+1
screen = newtab(name="screen {}".format(n)) #make new screen and give it number
self.manager.add_widget(screen)
self.manager.current = "screen 0"
for item in sm.screen_names:
self.bt2=(Button(text=item, size_hint =(.1, .1) ,pos_hint ={'center_x':(.1*sm.screen_names.index(item)+.1), 'center_y':.84}))
self.add_widget(self.bt2)
self.bt2.bind(on_release=self.transition)
sm.add_widget(newtab(name='screen 0'))
class Application(App):
def build(self):
return sm
if __name__ == "__main__":
Application().run()
I suppose that below is what you expected to get. But I agree with #ApuCoder that you may look for TabbedPanel functionality.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager):
def __init__(self, **kwargs):
super(ScreenManagement, self).__init__(**kwargs)
sm = ScreenManagement(transition=FadeTransition())
class newtab(Screen):
def __init__(self, **kwargs):
super(newtab, self).__init__(**kwargs)
self.bt1 = (Button(text="New tab", size_hint=(.1, .1), pos_hint={'center_x': .1, 'center_y': .94}))
self.add_widget(self.bt1)
self.bt1.bind(on_release=self.new_tab)
self.txt1 = TextInput(text='', size_hint=(.1, .1), pos_hint={'center_x': .2, 'center_y': .75}, multiline=True)
self.add_widget(self.txt1)
# add all present screen buttons to newly created screen
for i, screen in enumerate(sm.screens):
self.bt2 = (Button(text=screen.name, size_hint=(.1, .1), pos_hint={'center_x': (.1 * i + .1), 'center_y': .84}))
self.add_widget(self.bt2)
self.bt2.bind(on_release=self.transition)
# add this newly created screen button to all screens
for screen in sm.screens + [self]:
screen.bt2 = (Button(text=self.name, size_hint=(.1, .1), pos_hint={'center_x': (.1 * len(sm.screens) + .1), 'center_y': .84}))
screen.add_widget(screen.bt2)
screen.bt2.bind(on_release=screen.transition)
def transition(self, instance):
self.manager.current = instance.text
def new_tab(self, *args):
n = len(self.manager.screen_names) ##number of screens+1
screen = newtab(name="screen {}".format(n)) # make new screen and give it number
self.manager.add_widget(screen)
self.manager.current = "screen 0"
sm.add_widget(newtab(name='screen 0'))
class Application(App):
def build(self):
return sm
if __name__ == "__main__":
Application().run()
Related
I want to create a list of coloured labels. The thing is that I could do it with the kv file, but I need to do it through the build() method. So I tried replicate what I have done, but it does not work. And I can't understand why.
This is what I've coded
from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import *
class RL(RelativeLayout): # Creates the background colour for each label
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Color(.7, 0, .5, 1)
Rectangle(size_hint=self.size)
class MainMenu(BoxLayout):
N_LBLS = 8
labels_text = []
RL_list = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
button = Button(text='do something')
button.bind(on_release=self.change_text)
box = BoxLayout(orientation='vertical', padding= 10, spacing = 15)
for i in range(0, self.N_LBLS):
self.RL_list.append(RL())
self.labels_text.append(Label(text=f'{i}º label', size_hint=self.size))
self.RL_list[i].add_widget(self.labels_text[i])
box.add_widget(self.RL_list[i])
self.add_widget(button)
self.add_widget(box)
def change_text(self, instance):
for lbl in self.labels_text:
if lbl.text[0] == '5':
lbl.text = 'Text changed'
class MainApp(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
MainApp().run()
It's supposed to make a button to the left, and a list of 8 coloured labels to the right.
The problem is that you are setting size_hint=self.size in each Label. The self.size is the size of the MainMenu, which is [100,100] when that code is executed. Note that size_hint is a multiplier that is applied to the parents size to calculate the widgets size. So a size_hint of [100,100] makes each Label 100 times bigger than the MainMenu. So your code is working, but the Labels are so large that the text is off the screen. Start by just removing size_hint=self.size.
And, to set a background color on a Label, you can just use the canvas of that Label, rather than some container. Here is a version of your code that does that:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
class ColorLabel(Label):
pass
Builder.load_string('''
<ColorLabel>:
bg_color: [.7, 0, .5, 1]
canvas.before:
Color:
rgba: self.bg_color
Rectangle:
pos: self.pos
size: self.size
''')
class MainMenu(BoxLayout):
N_LBLS = 8
labels_text = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
button = Button(text='do something')
button.bind(on_release=self.change_text)
box = BoxLayout(orientation='vertical', padding=10, spacing=15)
for i in range(0, self.N_LBLS):
self.labels_text.append(ColorLabel(text=f'{i}º label'))
box.add_widget(self.labels_text[i])
self.add_widget(button)
self.add_widget(box)
def change_text(self, instance):
for lbl in self.labels_text:
if lbl.text[0] == '5':
lbl.text = 'Text changed'
lbl.bg_color = [0, 1, 0, 1]
class MainApp(App):
def build(self):
return MainMenu()
if __name__ == '__main__':
MainApp().run()
I have a screen manager ThirdWindow which is supposed to change the screen when B1 is clicked basically a navigation thing. Please note ThirdWindow is a a different class. callback is called when B1 is clicked. it changes the screen with the help of ThirdWindow I think. I used self.manager.current it didn't worked, I also tried using it by making ThirdWindow a def in class Dre but the results were same. The print statement is not getting printed that is inside def callback(self, instance) so I think the def is not getting called on_click at all. How can I fix that? Thanks
import kivy
from kivy.app import App
from kivy.core.audio import SoundLoader
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.stacklayout import StackLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.graphics import Rectangle
from kivy import platform
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MainWindow(Screen):
pass
class ThirdWindow(ScreenManager):
def load(self):
sm = ScreenManager
sm.add_widget(Dre(name='Dre'))
sm.add_widget(SecondWindow(name='SecondWindow'))
self.sm.current = 'Dre'
class Dre(RelativeLayout):
def __init__(self, **kwargs):
super(Dre, self).__init__(**kwargs)
self.color = [254/255, 102/255, 37/255, 1]
self.H_color = [254/255, 102/255, 37/255]
self.sound_theme = None
self.init_audio()
self.kv = Builder.load_file('Levels.py')
if platform in ('linux', 'win', 'macosx'):
with self.canvas.before:
self.bg = Rectangle(size=self.size, source='Neo.png')
self.bind(pos=self.update_bg)
self.bind(size=self.update_bg)
else:
with self.canvas.before:
self.bg = Rectangle(size=self.size, source='Neon.png')
self.bind(pos=self.update_bg)
self.bind(size=self.update_bg)
def update_bg(self, *args):
if platform in ('linux', 'win', 'macosx'):
self.bg.pos = self.pos
self.bg.size = self.size
self.add_widget(Label(text='D R E A M S',
pos_hint={'center_x': .5, 'center_y': .8},
font_size='60dp', font_name='Roboto-Bold.ttf', color=self.H_color))
B1 = Button(text='P L A Y', font_name='Roboto-Bold.ttf', size_hint=(.2, .15),
pos_hint={'center_x': .5, "center_y": .3}, background_color = self.color, background_normal='')
# B1.bind(on_press=return self.kv)
self.add_widget(B1)
else:
self.bg.pos = self.pos
self.bg.size = self.size
self.add_widget(Label(text='D R E A M S',
pos_hint={'center_x': .5, 'center_y': .8},
font_size='30dp', font_name='Roboto-Bold.ttf', color=self.H_color))
B1 = Button(text='P L A Y', font_name='Roboto-Bold.ttf', size_hint=(.2, .15),
pos_hint={'center_x': .5, "center_y": .3}, background_color=self.color, background_normal='',
on_press=self.callback)
self.add_widget(B1)
def callback(self, instance):
print('working')
self.manager.current = 'SecondWindow'
def init_audio(self):
self.sound_theme = SoundLoader.load('Bg_theme.mp3')
self.sound_theme.volume = 1
self.sound_theme.loop = True
if self.sound_theme:
self.sound_theme.play()
print('okay')
else:
print('not okay')
class SecondWindow(Screen):
def __init__(self, **kwargs):
super(SecondWindow, self).__init__(**kwargs)
self.color = [254 / 255, 102 / 255, 37 / 255, 1]
if platform in ('linux', 'win', 'macosx'):
with self.canvas.before:
self.bg = Rectangle(size=self.size, color=self.color)
class LabApp(App):
def build(self):
return Dre()
if __name__ == '__main__':
LabApp().run()```
if you provide any solution please provide it in .py file.
Many issues with your code.
First, you have defined a ScreenManager class (ThirdWindow), but you have not created an instance of it or included it in your GUI. In order to use a ScreenManager to manage Screens, you must add it to your GUI. I would suggest modifying your LabApp class to use ThirdWindow:
class LabApp(App):
def build(self):
return ThirdWindow()
and modify ThirdWindow to replace the load() method with an __init__() method:
class ThirdWindow(ScreenManager):
def __init__(self, **kwargs):
super(ThirdWindow, self).__init__(**kwargs)
self.add_widget(Dre(name='Dre'))
self.add_widget(SecondWindow(name='SecondWindow'))
Since the Dre class is being used as a Screen, it must be redefined as a Screen:
class Dre(Screen):
and you can add the callback to the creation of the B1 Button:
B1 = Button(text='P L A Y', font_name='Roboto-Bold.ttf', size_hint=(.2, .15), on_release=self.callback,
pos_hint={'center_x': .5, "center_y": .3}, background_color = self.color, background_normal='')
How do I access a widget from screen1 and make changes to it in screen2 and also return screen1 back to it initial state(like I just run the code).
I have commented out some code that is not working.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class ScreenManagement(ScreenManager):
def __init__(self, **kwargs):
super(ScreenManagement, self).__init__(**kwargs)
class Screen2(Screen):
def __init__(self, **kwargs):
super(Screen2, self).__init__(**kwargs)
self.retry = Button(text='retry', font_size=15, size_hint=(.26, .26),
pos_hint={'center_x': .5, 'center_y': .32}, on_press=self.retrying,
background_color=(0, 0, 1, 1))
self.add_widget(self.retry)
def retrying(self, *args):
self.manager.current = 'screen1'
# it should change the text in screen1 to "i am back to screen1, thanks you"
#self.welc.text=" i am back to screen1, thank you"
# it should change the button color back to it normal state
#self.goto.background_color='normal state'
class Screen1(Screen):
def __init__(self, **kwargs):
super(Screen1, self).__init__(**kwargs)
self.welc = Label(text='hi there welcome to my first screen', font_size=15, size_hint=(.26, .26),
pos_hint={'center_x': .5, 'center_y': .7})
self.add_widget(self.welc)
self.goto = Button(text='next screen', font_size=15, size_hint=(.2, .2),
pos_hint={'center_x': .5, 'center_y': .32}, on_press=self.going, background_color=(0, 0, 1, 1))
self.add_widget(self.goto)
def going(self, *args):
self.goto.background_color=(1,0,0,1)
self.manager.current = 'screen2'
class Application(App):
def build(self):
sm = ScreenManagement(transition=FadeTransition())
sm.add_widget(Screen1(name='screen1'))
sm.add_widget(Screen2(name='screen2'))
return sm
if __name__ == "__main__":
Application().run()
My question is this:
how do i change the text in screen1 when the retry button is pressed.
How do i return screen1 back to it initial state after the retry button is pressed so that the "next screen" button color changes back to blue
Once you have changed the current screen to screen1, then you can access that Screen as self.manager.current_screen, so your retrying() method can be:
def retrying(self, *args):
self.manager.current = 'screen1'
self.manager.current_screen.welc.text = "i am back to screen1, thanks you"
self.manager.current_screen.goto.background_color = background_color=(0, 0, 1, 1)
To set the screen1 back to its original state, you could write another method that just sets all the values back to the original value one by one. Or you could recreate screen1 by doing something like this in a method of your Application.:
def reset_screen1(self):
sm = self.root
scr1 = sm.get_screen('screen1`)
sm.remove_widget(scr1)
sm.add_widget(Screen1(name='screen1'))
I want to change some button labels of a class in a popup and retain the new label after reopening the popup. If you run my app, you can see that after pressing "Press me" button, a popup appears with a button with a label "Default", after pressing on it, it changes the label to "New". I want to be able to close the popup, press the "Press me" button and see the button in a popup with a label "New".
My .py file
from kivy.uix.floatlayout import FloatLayout
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.app import App
from kivy.uix.widget import Widget
import time
Window.clearcolor = (1, 1, 1, 1)
Window.size = (800, 480)
class MyGrid(Widget):
def btn(self):
show_popup(T, "Window")
class T(FloatLayout):
pass
def show_popup(tab, name):
show = tab()
popupWindow = Popup(title = name, content = show, size_hint = (None,None), size = (800,384), auto_dismiss = True)
popupWindow.open()
return popupWindow
class TimeApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
TimeApp().run()
my .kv file
<MyGrid>
Button:
text: "Press me"
on_press: root.btn()
<T>:
Button:
pos_hint: {"center_x": 0.5, "center_y": 0.5}
text: "Default"
on_press: self.text = "New"
One way that you can do it, is by keeping a reference to the popup.
The py side:
Window.clearcolor = (1, 1, 1, 1)
Window.size = (800, 480)
class MyGrid(Widget):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.popupWindow = Popup(content=T(), size_hint=(None, None),
size=(800, 384), auto_dismiss=True)
def btn(self):
self.show_popup("Window")
def show_popup(self, name):
self.popupWindow.title = name
self.popupWindow.open()
class T(FloatLayout):
pass
class TimeApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
TimeApp().run()
I wanted to make a small program with an widget containing an image, which changes the image when you click on it, but when I ran the program it did not displayed the widget.
Instead it displayed an empty, screen, but with the correct backgroundcolor.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
kv_string = Builder.load_string('''
<Root>:
Feld:
pos_hint: {"right": 1, 'top': 1}
id: a1
<Feld>:
Image:
pos: root.pos
id: my_image
source: root.weg
''')
class Root(FloatLayout):
kr = StringProperty('kreuz.png')
ks = StringProperty('kreis.png')
def __init__(self, *args, **kwargs):
super(Root, self).__init__(*args, **kwargs)
Clock.schedule_interval(self.Update, 1/60.)
def Update(self, *args):
pass
class Feld(Widget):
weg = StringProperty('hinterg.png')
def __init__(self, *args, **kwargs):
super(Feld, self).__init__(*args, **kwargs)
Clock.schedule_interval(self.Update, 1/60.)
def Update(self, *args):
pass
def on_touch_down(self, touch):
if self.ids.my_image.collide_point(*touch.pos):
self.weg = self.parent.kr
class TTT(App):
def build(self):
Window.clearcolor = (0, 1, 1, 1)
return kv_string
if __name__ == "__main__":
TTT().run()
Your root widget is kv_string, which is None since the variable is the result of Builder.load_string on a string that doesn't contain a root widget.