KivyMD BottomNavigation with different .kv files - python

Im working on an mobile calculator app. Please be aware that this is my first own project.
The app should be able to offer a simple calc advanceded and should display different functions.
I achive this with the BottomNavigation but the file gets huge. Any troubleshooting is not possible at least not for me.
with the screenmanager I could separate the different screens into different files but I cannot do this BottomNavigator.
Could Anybody give me a hint please.
working with the screenmanager

found it just in case anybody doesnt know either:
#main.py
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.bottomnavigation.bottomnavigation import MDBottomNavigationItem
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
return Builder.load_file("my.kv")
MainApp().run()
#my.kv
#:include advanced_calc_screen.kv
BoxLayout:
orientation: "vertical"
MDBottomNavigationItem:
name: "advanced_calc"
text: "advanced"
icon: "calculator"
Advanced:
#advanced_calc_screen.kv
<Advanced>:
Button:
text: "You are at Homescreen"

Related

How to repair an error "Pyperclip could not find a copy/paste mechanism in your device" in Python Kivy?

I am using Pyperclip library in Python in Kivy UI, and I want to be able to copy a text by pressing a button, but it gives me this error message:
pyperclip.PyperclipException:
Pyperclip could not find a copy/paste mechanism for your system.
For more information, please visit https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error
My .py file is:
import kivy
import pyperclip
kivy.require("1.10.1")
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.app import App
class Screen1(Screen):
def copy_on_press(self):
pyperclip.copy("text_which_should_be_copied")
class Copy(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Screen1(name = "scr1"))
return sm
app = Copy()
app.run()
My .kv file is:
<Screen1>:
id: scr1
orientation: "vertical"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "Background.png"
Button:
text: "Copy"
on_press: scr1.copy_on_press()
Thanks for any answer.
I haven't found any informations which could solve my error.
I found similar errors, but their solutions didn't work for me.
Thanks to the comments, I've found it. The .py:
import kivy
from kivy.core.clipboard import Clipboard
kivy.require("1.10.1")
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.app import App
class Screen1(Screen):
def copy_on_press(self):
Clipboard.copy("text_which_should_be_copied")
class Copy(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Screen1(name = "scr1"))
return sm
app = Copy()
app.run()
The .kv remains the same.

How to make kivy app from different py files

I am trying to make an app out of different .py files. But I don't know how to add them together, I have one main file, and one login file with plans to add a lot more, but with these I'm experimenting right now. They are pretty basic for now until I figure out this "bonding" between them and then I will start adding some more complex stuff. I tried couple of things and they didn't work, but I left them in code for you to see (I tried to make the app to start with MainWindow, and on press of the first button it goes to login page*). Here's the code and please help me.
*Right now when I press the button it gives me this error: OSError: exception: access violation writing 0x0000000080006010
this is main.py:
from kivy.lang import Builder
from kivy.app import App
import login
from kivy.uix.screenmanager import Screen
kv = Builder.load_string('''
<MainWindow>:
GridLayout:
cols:1
GridLayout:
rows:5
Button:
text:"NOVA ROBA"
on_release:
root.call_login()
Button:
text:"KUPCI"
Button:
text:"PRODATO"
Button:
text: "AGRONOMI"
Button:
text: "STANJE U MAGACINU"
''')
class MainWindow(Screen):
def call_login(self):
login.app().run()
pass
class main_app(App):
def build(self):
return MainWindow()
if __name__ == '__main__':
main_app().run()
this is login.py:
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.app import App
class Login(Screen, App):
def build(self):
return
pass
kv = Builder.load_string('''
<Login>:
name:"login"
GridLayout:
rows:2
GridLayout:
cols:2
Label:
text:"Password: "
TextInput:
id:passwd
multiline: False
Button:
text: "Submit"
on_release:
passwd.text = ""
''')
class app(App):
def build(self):
return Login()
if __name__ == "__main__":
app().run()
You are creating 2 apps, which is not needed. Instead of inheriting from both Screen and App in the Loginscreen, inherit only from Screen. Then create a ScreenManager in your main.py's build method and then add the imported loginscreen as a widget, to switch to the new screen, use self.manager.current = "login" in the call_login method of MainWindow
class app(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainWindow())
sm.add_widget(Login())
return sm

ScreenManager accepts only Screen widget. is raised while run a basic code

I am just learning some styles and designs of kivymd, but for some reason when the code runs
kv = Builder.load_file(MainLayout.kv), it raises the Exception(
kivy.uix.screenmanager.ScreenManagerException: ScreenManager accepts only Screen widget.
).
I just can't get it to run and any further. It has been raising this Exception no matter what changes I make.
And Just for Reference, this is the Code for the Main.py
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.list import MDList
from kivymd.theming import ThemableBehavior
from kivy.core.window import Window
class Login(Screen):
pass
class Settings(Screen):
pass
sm = ScreenManager()
sm.add_widget(Login(name='login'))
sm.add_widget(Settings(name='settings'))
sm.current = "login"
class DemoApp(MDApp):
class ContentNavigationDrawer(BoxLayout):
pass
class DrawerList(ThemableBehavior, MDList):
pass
def build(self):
self.theme_cls.primary_palette = "Teal"
Window.size = (412, 732)
#The Error Occurs when the KV file is loaded
kv = Builder.load_file("MainLayout.kv")
return kv
if __name__ == '__main__':
DemoApp().run()
This the Kivy File and in Login File I just have ( )
#: include Login.kv
#: include Settings.kv.
NavigationLayout:
id:nav_layout
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "Kivy Demo App"
Widget:
ScreenManager:
id: screen_manager
Login:
id: login1
name: "login"
Settings:
id: settings1
name:"settings"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: 'vertical'
padding: "8dp"
spacing: "8dp"
MDLabel:
text: 'Username'
MDLabel:
text: 'Captions'
Okay, it was not too hard to fix this. I just Changed the name of the class/page from settings to just setting and it fixed the problem. Not really sure how it affected the code but would love to know about the bug if anyone might know.
I ran into the same problem. The class name "Settings" causes the error "ScreenManager accepts only Screen widget". I changed the class name to "Setting" and the screen widget's id and name both to "setting" and everything works fine. Frustrating.

How can I bind a button on the .kv file to make it play a sound?

Hello StackOverflow community,
I would like to ask for some help as before asking I did a long research but found nothing to help me out.
I have a school project that I decided to code with Python using Kivy for cross-platform. My project is about a SoundBox, to simplify I need to first create buttons and bind them to play various sounds. On pure python code (without a .kv file), I learned how to bind a button to make it play a sound, so I decided to reach the next level that is the Screen Management part. I kind of learned that to using now a .kv file to make it simple but I'm stuck on how to bind a button using .kv file.
I tried out some stuff but always ended up with errors on the console, also (but it's not really important for now), my Fade Transition doesn't work.
Your help is highly appreciated, thanks in advance.
.py:
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.audio import SoundLoader
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
sound = SoundLoader.load('Sunset_Lover.ogg')
sm = ScreenManager()
class ScreenManager(ScreenManager):
pass
class Menu(Screen):
pass
class Genre(Screen):
pass
class TestApp(App):
def build(self):
sm.add_widget(Menu(name='menu'))
sm.add_widget(Genre(name='genre'))
return sm
def son(self, instance):
if sound:
sound.play()
if __name__ == "__main__":
TestApp().run()
.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
<ScreenManager>:
FadeTransition:
Menu:
Genre:
<Menu>:
BoxLayout:
Button:
text: "Commencer"
size_hint: 1, 1
pos_hint: {'x': 0.3, 'y':0.3}
on_press: root.manager.current = 'genre'
<Genre>:
BoxLayout:
Button:
text: "Exemple1"
size_hint: 0.2, 0.2
pos_hint: {'x': 0.2, 'y':0.2}
on_press: root.son()
The problem is that you have sound out of any scope you could use in kv file. First, move it somewhere, where you can access it:
class TestApp(App):
def build(self):
self.sound = SoundLoader.load('file')
sm = ScreenManager()
sm.add_widget(Menu(name='menu'))
sm.add_widget(Genre(name='genre'))
return sm
Then collect the arguments in more efficient way - this way you can use it both in kv and python and the additional args will be collected (won't throw an error)
def son(self, *args):
if self.sound:
self.sound.play()
Then in kv you have to make sure the ScreenManager recieves only the appropriate widgets i.e. Screens only. To get the transition working, you have to add it to a variable it's used from:
<ScreenManager>:
transition: FadeTransition()
Menu:
Genre:
And to actually play the sound (run the method) you can call it from the place you define it in i.e. from App instance:
<Genre>:
BoxLayout:
Button:
text: "Exemple1"
size_hint: 0.2, 0.2
pos_hint: {'x': 0.2, 'y':0.2}
on_press: app.son() # here
You can import it to the kv file:
#: import sound __main__.sound
Button:
on_release: sound()

How to pass arguments to build() in kivy?

I have written a code with GridLayout which need to be added with buttons in Python file. So, the add_widget() mainpulation should be done in build(). I am getting errors and couldn't get it.Someone Please help me.
In short, instead of add_btn(), I need it in build() of MineApp class.
Thanks in advance.`
main.py
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
class MainLayout(BoxLayout):
def build(self):
pass
def add_btn(self,id):
for i in range(100):
id.add_widget(Button())
class MineApp(App):
def build(self):
return MainLayout()
if __name__ == '__main__':
MineApp().run()
mine.kv file:
<MainLayout>:
orientation:'vertical'
BoxLayout:
orientation:'horizontal'
height: '30px'
size_hint_y:None
TextInput:
id: tinput
text:'10'
Button:
text:'start'
on_press:root.add_btn(grid)
Label:
id:mylabel
text:'0'
GridLayout:
id: grid
cols:10
rows:10
It took some time but think I get what you're trying to say! You can get the same effect by passing the id parameter of Grid in the .py file like so...
class MainLayout(BoxLayout):
def build(self):
for i in range(100):
self.ids.grid.add_widget(Button())
Then, you can just take your start button and...
Button:
text:'start'
on_press:root.build()
This works because "self" in .py refers to the class while in the .kv a similar wording would be 'root' (while 'self' in .kv refers to the widget!) Is this what you kind of had in mind? Let me know! I tried it out myself and had no problem running it through :)
Also, it wasn't put explicitly here that to test the code you'd need to import Builder via:
from kivy.lang import Builder
and do...
Builder.load_file("mine.kv")
as your .py and .kv don't share the same name (which you'd still need to add a "#File name: main.py" to the .kv if they did match names! Other than that, it looks good!

Categories