How to add navigation in kivy using .py file? - python

I am trying to add navigation in my kivy app using .py file but because the things I tried are not working and I am a complete beginner. I don't know what problem is occurring and I am not able to find any solutions on my own pls help me. I am trying to change the main screen from class Dre to class SecondWindow when the play button is clicked. BTW the things I already tried are tagged now. Pls give the solution in .py file because I am trying to do everything on it. Here is the code. 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')
# self.callback()
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()

Here's the correct code for that (at least for me):
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 SM(ScreenManager):
pass
class MainWindow(Screen, RelativeLayout):
def __init__(self, **kwargs):
super(MainWindow, 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')
# self.callback()
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 bruh(self):
App.get_running_app().root.current = 'SecondWindow'
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='', on_press= lambda x: self.bruh())
# 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):
sm = SM()
sm.add_widget(MainWindow(name='MainWindow'))
sm.add_widget(SecondWindow(name='SecondWindow'))
return sm
if __name__ == '__main__':
LabApp().run()
The main changes here are the fact that the build method for LabApp is required, since the .kv file isn't used; to also inherit the Screen class into the MainWindow class, which is renamed from Dre for less confusing code, since it is essential forScreenManager; and the bruh method in the MainWindow (im not good at naming ok dont roast me) that changes to the SecondWindow screen when the B1 button's on_press event is called. Sorry for the confusing English but at least it's understandable(?) ig

Related

Image not showing up in kivy python

I want to make a launcher app which matches the windows 11 theme. i made the background and i want to make a button which would close the launcher, but the button does not work for some reason when i put it in a different class. i can put it in the same class but i want to learn this method as i would use it while making the app icons. the code it provided below.
from kivy.config import Config
from kivy.core.window import Window
from kivy.graphics import Rectangle
from kivy.graphics.context_instructions import Color
from kivy.properties import Clock
from kivy.uix.image import Image
import cv2
from kivy.uix.widget import Widget
Config.set('graphics', 'fullscreen', 'auto')
Config.set('graphics', 'borderless', 'true')
Config.set('graphics', 'window_state', 'maximized')
from kivy.app import App
import pyautogui
from kivy.uix.floatlayout import FloatLayout
theme = 'dark'
screen = 'main'
x_button_size = (100,100)
x_button_pos = (50,50)
class XButton(Image):
def __init__(self):
super().__init__(source='assets/images/bg_image.png')
class MainScreenWidget(FloatLayout):
bg = None
rectangle = None
def __init__(self, **kwargs):
super(MainScreenWidget, self).__init__(**kwargs)
Clock.schedule_interval(self.update, 1.0/60.0)
self.init_bg()
# x_button_size = (self.width , self.height )
self.x_button = XButton()
def init_bg(self):
with self.canvas.before:
self.bg = Image(source='assets/images/bg_image.png', size_hint=[1, 1])
if theme == 'light':
Color(0.9, .9, .9, 0.7)
elif theme == 'dark':
Color(0, 0, 0, 0.6)
self.rectangle = Rectangle(size=self.size)
pass
def update(self, dt):
self.update_bg()
self.update_x_button()
def update_bg(self):
self.bg.size = self.width, self.height
self.bg.pos_hint = {'center_x': self.width / 2, 'center_y': self.height / 2}
self.rectangle.size = self.size
pass
def update_x_button(self):
self.x_button.size = (Window.size[0], Window.size[1])
self.x_button.pos = (5, 5)
pass
class LauncherApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
bg_image = pyautogui.screenshot()
bg_image.save(r'assets/images/bg_image.png')
image = cv2.imread('assets/images/bg_image.png')
blurred_image = cv2.GaussianBlur(image, (75, 75), 0)
cv2.imwrite('assets/images/bg_image.png', blurred_image)
LauncherApp().run()
any recommendations for how to make the icons are also helpful

How to move a circular progressbar alongside its progressive numbers within a FloatLayout?

I'm trying to make an app where I can display a circular progressbar, I've been told to use a FloatLayout so the arrangements stay organized no matter the size of the mobile screen. I've used this example for the circular progressbar How to make circular progress bar in kivy? , however, I can't seem to put the progressbar within the FloatLayout so that it organizes itself as I change the size of the screen. Anyone has a suggestion?
EDIT: I want the progressbar to stay at the center of the window, relatively based on the current window size and height. With the current code, when I change the size of the window, the progressbar doesn't relocate itself to the middle.
Here's the code I'm using:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.progressbar import ProgressBar
from kivy.core.text import Label as CoreLabel
from kivy.lang.builder import Builder
from kivy.graphics import Color, Ellipse, Rectangle
from kivy.clock import Clock
class CircularProgressBar(ProgressBar, FloatLayout):
def __init__(self,**kwargs):
super(CircularProgressBar,self).__init__(**kwargs)
self.thickness = 40
self.label = CoreLabel(text="0", font_size=self.thickness, )
self.texture_size = None
self.refresh_text()
self.draw()
def draw(self):
with self.canvas:
self.canvas.clear()
Color(0.26,0.26,0.26)
Ellipse(pos=self.pos, size=self.size)
Color(1,0,0)
Ellipse(pos=self.pos,size=self.size,angle_end=(self.value/100.0)*360)
Color(0,0,0)
Ellipse(pos=(self.pos[0] + self.thickness / 2, self.pos[1] + self.thickness / 2),size=(self.size[0] - self.thickness, self.size[1] - self.thickness))
Color(1, 1, 1, 1)
Rectangle(texture=self.label.texture,size=self.texture_size,pos=(self.size[0]/2-self.texture_size[0]/2,self.size[1]/2 - self.texture_size[1]/2))
self.label.text = str(int(self.value))
def refresh_text(self):
self.label.refresh()
self.texture_size=list(self.label.texture.size)
def set_value(self, value):
self.value = value
self.label.text = str(int(self.value))
self.refresh_text()
self.draw()
class MainWindow(Screen, Widget):
current = ""
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("main.kv")
sm = WindowManager()
screens = [MainWindow(name="main")]
for screen in screens:
sm.add_widget(screen)
sm.current = "main"
class Main(App):
def animate(self,dt):
circProgressBar = self.root.get_screen('main').ids.cp
if circProgressBar.value < 99:
circProgressBar.set_value(circProgressBar.value+1)
else:
circProgressBar.set_value(0)
def build(self):
Clock.schedule_interval(self.animate, 0.1)
return sm
if __name__ == "__main__":
Main().run()
Here is the .kv file:
WindowManager:
MainWindow:
<MainWindow>:
name: "main"
FloatLayout:
CircularProgressBar:
id: cp
pos: 250, 250
size_hint:(None,None)
height:200
width:200
max:100
You can accomplish that by using pos_hint to set the position of the CircularProgressBar, and then making sure that everything in your draw() method is based on that position. For example, here is pos_hint in your kv:
WindowManager:
MainWindow:
<MainWindow>:
name: "main"
FloatLayout:
CircularProgressBar:
id: cp
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
size_hint:(None,None)
height:200
width:200
max:100
Then your draw() method can be:
def draw(self):
with self.canvas:
self.canvas.clear()
Color(0.26,0.26,0.26)
Ellipse(pos=self.pos, size=self.size)
Color(1,0,0)
Ellipse(pos=self.pos,size=self.size,angle_end=(self.value/100.0)*360)
Color(0,0,0)
Ellipse(pos=(self.pos[0] + self.thickness / 2, self.pos[1] + self.thickness / 2),size=(self.size[0] - self.thickness, self.size[1] - self.thickness))
Color(1, 1, 1, 1)
Rectangle(texture=self.label.texture,size=self.texture_size,pos=(self.pos[0]-self.texture_size[0],self.center[1] - self.texture_size[1]/2))
self.label.text = str(int(self.value))
The only modification to your draw() method is in the pos of the Rectangle.

Cannot change ByteFitImage data after it is defined

I have a music player app that reads the cover of songs and displays them on the screen. For this I created my own class ByteFitImage for the image to read bytes and for it to adapt to different sizes.
The problem I am encountering is that if I decide to change the data, I get a key error:
KeyError: 'source'
And obviously this line is causing the problem:
self.kv.ids.img.data = BytesIO(second_img.read())
Why is it asking for source? My Code:
from io import BytesIO
from kivy.clock import Clock
from kivy.core.image import Image
from kivy.graphics.context_instructions import Color
from kivy.graphics.vertex_instructions import Rectangle
from kivy.lang import Builder
from kivy.properties import BooleanProperty, ObjectProperty, VariableListProperty, Property
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.app import App
class ByteFitImage(BoxLayout):
data = Property(None)
radius = VariableListProperty([0], length=4)
mipmap = BooleanProperty(False)
_container = ObjectProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self._late_init)
def _late_init(self, *args):
self._container = Container(self.data)
self.bind(data=self._container.setter("source"))
self.add_widget(self._container)
def reload(self):
self._container.image.reload()
class Container(Widget):
# source = ObjectProperty()
image = ObjectProperty()
def __init__(self, source, **kwargs):
super().__init__(**kwargs)
# self.image = AsyncImage(mipmap=mipmap)
self.bind(size=self.adjust_size, pos=self.adjust_size)
self.image = Image(source, ext="jpg")
self.image.bind(on_load=self.adjust_size)
# self.source = source
def on_source(self, instance, value):
if isinstance(value, str):
self.image.source = value
else:
self.image.texture = value
self.adjust_size()
def adjust_size(self, *args):
if not self.parent or not self.image.texture:
return
(par_x, par_y) = self.parent.size
if par_x == 0 or par_y == 0:
with self.canvas:
self.canvas.clear()
return
par_scale = par_x / par_y
(img_x, img_y) = self.image.texture.size
img_scale = img_x / img_y
if par_scale > img_scale:
(img_x_new, img_y_new) = (img_x, img_x / par_scale)
else:
(img_x_new, img_y_new) = (img_y * par_scale, img_y)
crop_pos_x = (img_x - img_x_new) / 2
crop_pos_y = (img_y - img_y_new) / 2
subtexture = self.image.texture.get_region(
crop_pos_x, crop_pos_y, img_x_new, img_y_new
)
with self.canvas:
self.canvas.clear()
Color(1, 1, 1)
Rectangle(texture=subtexture, pos=self.pos, size=(par_x, par_y))
class Example(App):
def __init__(self, **kwargs):
with open("images/song_img.jpg", "rb") as song_img:
self.song_img_bytes = BytesIO(song_img.read())
super(Example, self).__init__(**kwargs)
self.kv = Builder.load_string('''
#:kivy 2.0.0
BoxLayout:
orientation: "vertical"
padding: 10
ByteFitImage:
id: img
data: app.song_img_bytes
Button:
text: "Change cover!"
font_size: 32
on_release: app.change_cover()''')
def build(self):
return self.kv
def change_cover(self):
with open("images/second_img.jpg", "rb") as second_img:
self.kv.ids.img.data = BytesIO(second_img.read())
if __name__ == '__main__':
Example().run()

How to chage the parameters in a LineRectangle class in python kivy?

I want to draw multi-box on a image. How to chage the parameters of the box pos, size and lable in a LineRectangle class in python kivy?
class LineRectangle(Widget):
def __init__(self, **kwargs):
super(LineRectangle, self).__init__(**kwargs)
with self.canvas:
Color(1, 0, 0, 1)
self.line = Line(width=2, rectangle=(self.x, self.y, self.width, self.height))
self.label = Label(text='Rectangle', pos=(self.x, self.y), size=(10, 10))
class LineExtendedApp(App):
def build(self):
root = FloatLayout()
image = Image(source='000001.jpg', allow_stretch=False, keep_ratio=True)
root.add_widget(image)
bbox1 = LineRectangle()
bbox1.line = Line(width=1, rectangle=(100, 100, 100, 100))
bbox1.label = Label(text='bbox1', pos=(100, 100), size=(10, 10))
bbox2 = LineRectangle()
bbox2.line = Line(width=1, rectangle=(300, 300, 100, 100))
bbox2.label = Label(text='bbox1', pos=(300, 300), size=(10, 10))
root.add_widget(bbox1)
root.add_widget(bbox2)
return root
if __name__ == '__main__':
LineExtendedApp().run()
You can create Properties for the parameters that you want to be able to change. Then use a kv rule to create bindings (so that changes to a Property are automatically shown in your display). Here is an example of how to do that:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import ListProperty, NumericProperty, StringProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.widget import Widget
class LineRectangle(Widget):
line_color = ListProperty([])
line_rect = ListProperty([])
line_width = NumericProperty()
label_text = StringProperty('')
label_pos = ListProperty([])
def __init__(self, **kwargs):
self.line_color = kwargs.pop('line_color', [1,1,1,1])
self.line_rect = kwargs.pop('line_rect', [0,0,50,50])
self.line_width = kwargs.pop('line_width', 1)
self.label_text = kwargs.pop('label_text', 'text')
self.label_pos = kwargs.pop('label_pos', [0,0])
super(LineRectangle, self).__init__()
Builder.load_string('''
<LineRectangle>:
canvas:
Color:
rgba: root.line_color
Line:
width: root.line_width
rectangle: root.line_rect
Label:
text: root.label_text
pos: root.label_pos
size: 10, 10
''')
class LineExtendedApp(App):
def build(self):
root = FloatLayout()
image = Image(source='000001.jpg', allow_stretch=False, keep_ratio=True)
root.add_widget(image)
self.bbox1 = LineRectangle(line_wdth=2, line_rect=[100, 100, 100, 100], line_color=[1,0,0,1], label_text='bbox1', label_pos=[100, 100])
bbox2 = LineRectangle(line_width=1, line_rect=[300, 300, 300, 300], line_color=[0,1,0,1], label_text='bbox2', label_pos=[300, 300])
root.add_widget(self.bbox1)
root.add_widget(bbox2)
Clock.schedule_once(self.adjust, 2) # just to demonstrate change parameter
return root
def adjust(self, dt):
self.bbox1.line_width = 10
if __name__ == '__main__':
LineExtendedApp().run()

Kivy widget is bigger than it should be

I tried to make by own coockie-clicker, so I creaded an kivy widget and declared an image of an coockie as part of it.
Everytime you click on the wiget, a counter goes up and the number is displayed on an label.
Everything went fine, after I got help here on stack overflow, but now I am faced with the problem, that the widet is to big, so even if I click on the right upper corner, to counter goes up, aldoug I do not clicked on the coockie.
Here is the sourcecode:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.animation import Animation
from kivy.core.text.markup import *
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty
from kivy.properties import StringProperty
Builder.load_string('''
<Root>:
Kecks:
pos: 300, 300
size: 100, 100
<Kecks>:
Image:
pos: root.pos
id: my_image
source: root.weg
Label:
id: my_Label
font_size: 50
text: root.txt
center_x: 345
center_y: 200
''')
class Root(FloatLayout):
def __init__(self, *args, **kwargs):
super(Root, self).__init__(*args, **kwargs)
class Kecks(Widget):
count = NumericProperty(0)
amount = NumericProperty(1)
txt = StringProperty()
level = NumericProperty(1)
weg = StringProperty('piernik.png')
def __init__(self, *args, **kwargs):
super(Kecks, self).__init__(*args, **kwargs)
#self.txt = str(self.count)
Clock.schedule_interval(self.Update, 1/60.)
def Update(self, *args):
self.txt = str(self.count)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.count += self.amount
class app(App):
def build(self):
Window.clearcolor = (10, 0, 0, 1)
return Root()
if __name__ == "__main__":
app().run()
The problem is you haven't defined your collide_points on which area you want that event to be triggered.
Consider if you want your collide_points on your my_image to trigger on_touch_down event, you need to adjust like this:
def on_touch_down(self, touch):
# to check if touch.pos collides on my_image
if self.ids.my_image.collide_point(*touch.pos):
self.count += self.amount
Also perhaps consider using pos_hint and size_hint as these will help you with consistency with your app running in different devices (size of screen, for instance), rather than using absolute size and/or position.
Hope this helps.

Categories

Resources