I'm writing a python script with a kv script outside it for formatting.
I have 2 basic screens thus far. I can load 1 screen into a preview but things fall apart when I try 2 screens.
I get this error:
kivy.uix.screenmanager.ScreenManagerException: ScreenManager accepts only Screen widget.
Here's my python code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
Builder.load_file("design.kv")
class Intro(Screen):
def go_settings(self):
self.manager.current = "settings"
pass
class Settings(Screen):
print("In settings")
pass
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == "__main__":
MainApp().run()
My kv code, titled "design.kv":
<Intro>:
GridLayout:
cols: 1
Label:
text: "Intro"
Button:
text: "Settings"
on_press: root.go_settings()
<Settings>:
GridLayout:
cols: 1
Label:
text: "Settings"
<RootWidget>:
Intro:
name: "intro"
Settings: #will work if I comment this line and below
name: "settings"
Not sure what's going on. Thanks for the help!
Alright, I think I got it.
I need to change the names of
Intro
and
Settings
to
IntroScreen
and
SettingsScreen
It seemed to work for me. Never thought the name I'd give would matter.
Related
I'm trying to make a Kivy interface that updates constantly when values imported from other files are constantly changing.
Questions:
How do I make it so, when I change the value of the "fk" variable in
test.py, that the Kivy app updates, without me having to restart the
program?
What is the use of "AnchorLayout" in class Interface(AnchorLayout): ?
I've tried to Google this, and still not 100% sure. Why put self in def build():?
What is the use of self.update in the code?
Questions 2 and 3 are unrelated to my main questions, but if anyone can help, that would be great.
What I have tried and failed:
main.py:
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder
import test123
Builder.load_file('main.kv')
Builder.load_file('robotinformation.kv')
class Interface(AnchorLayout):
val = NumericProperty(0)
class InterfaceApp(App):
def build(self):
Clock.schedule_interval(self.update, 1)
return Interface()
def update():
val = test123.numval()
if __name__ == '__main__':
InterfaceApp().run()
main.kv:
<Interface>:
BoxLayout:
orientation: 'vertical'
StackLayout:
orientation: 'tb-rl'
RobotInformation:
id: _robot_information
...
robotinformation.kv:
<RobotInformation#BoxLayout>:
BoxLayout:
orientation:'vertical'
Label:
text: app.val
...
test123.py:
def numval():
fk = 101
return fk
When i run the file, the buttons show up. Everything looks fine, until i click button 1 for the method Main.c() to get called. the interpreter spits out an exception claiming i haven't defined it yet, when i have. I cannot find a solution anywhere.
the .py file:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.lang.builder import Builder
kivy.require("1.11.1")
class Main:
#staticmethod
def c():
print("c")
class Start(App):
def setup(self):
Builder.load_file('start.kv')
Start().run()
the .kv file:
BoxLayout:
Button:
id: btn1
text: "Button 1"
on_press: Main.c()
Button:
text: "Button 2"
on_press: print(8 * 8)
There are many problems with your code, but, one way to do what you ask for is to
Create an instance of your Main class in your App class: self.main = Main()
Call this instance from your kv code: on_press: app.main.c()
I want to build an app with Kivy in Python but I got some errors that I tried to solve many times but I can't.
I want to open a camera screen firstly. In screen, we will see our webcam screen and there will 2 buttons at the bottom (Play and Capture). While I pressing Play, webcam will be on and if I press Capture button, I want to take snapshot. I built the working code until here.
After pressing Capture button and taking snapshot, I want to change the screen in order to go 2nd screen and it will just show a basic Hello World sentence in black background.
Here it is my code, where is my fault? Can you fix it?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
import time
class CheckScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
Builder.load_string("""
ScreenManagement:
CheckScreen:
<CameraClick#ScreenManager>:
orientation: 'vertical'
Camera:
id: camera
resolution: (640, 480)
play: False
ToggleButton:
text: 'Play'
on_press: camera.play = not camera.play
size_hint_y: None
height: '48dp'
Button:
text: 'Capture'
size_hint_y: None
height: '48dp'
on_press:
root.capture()
root.manager.transition.direction = 'left'
root.manager.current = 'check'
<CheckScreen>:
name: "check"
Button:
text: "Next Screen"
font_size: 50
""")
class CameraClick(BoxLayout):
def capture(self):
camera = self.ids['camera']
timestr = time.strftime("%Y%m%d_%H%M%S")
camera.export_to_png("IMG_{}.png".format(timestr))
print("Captured")
return CheckScreen
class TestCamera(App):
def build(self):
return CameraClick()
TestCamera().run()
When I'm running this code, it shows;
AttributeError: 'CameraClick' object has no attribute 'manager'
There were a couple problems with your code. As John Anderson mentioned in the comments, you had one class inheriting from different classes in your py/kv files. You also had 2 screen managers - you should only need 1. I believe your CameraClick class should really only inherit Screen from kivy, not ScreenManager or BoxLayout. You can define a layout inside of the CameraClick class itself.
Your error was coming from the fact that you were trying to get the 'manager' attribute of your CameraClick class which you hadn't defined anywhere. To reference a screen manager (which it looks like is what you were trying to do) you must give the screen manager an 'id' and reference it that way (as you have with your Camera).
Another good practice you should use when working with a ScreenManager is to give your screens and id and name when you're adding the screens to the ScreenManager widget. e.g. instead of
ScreenManagement:
CheckScreen:
Do
ScreenManagement:
CheckScreen:
name: "check_screen"
id: check_screen
Another good practice is to load your kv code into a variable, and return that in your main app's build method.
And so forth. I've changed your code a bit and I think it should do what you expect now. Take the time to review it and compare to yours so you can see the differences, and let me know if it's not what you're looking for.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
import time
class CheckScreen(Screen):
pass
class CameraClickScreen(Screen):
def capture(self):
camera = self.ids['camera']
timestr = time.strftime("%Y%m%d_%H%M%S")
camera.export_to_png("IMG_{}.png".format(timestr))
GUI = Builder.load_string("""
GridLayout:
cols: 1
ScreenManager:
id: screen_manager
CameraClickScreen:
name: "camera_click_screen"
id: camera_click_screen
CheckScreen:
name: "check_screen"
id: check_screen
<CameraClickScreen>:
orientation: 'vertical'
GridLayout:
cols: 1
Camera:
id: camera
resolution: (640, 480)
play: False
ToggleButton:
text: 'Play'
on_press: camera.play = not camera.play
size_hint_y: None
height: '48dp'
Button:
text: 'Capture'
size_hint_y: None
height: '48dp'
on_press:
root.capture()
# root refers to <CameraClickScreen>
# app refers to TestCamera, app.root refers to the GridLayout: at the top
app.root.ids['screen_manager'].transition.direction = 'left'
app.root.ids['screen_manager'].current = 'check_screen'
<CheckScreen>:
Button:
text: "Next Screen"
font_size: 50
""")
class TestCamera(App):
def build(self):
return GUI
TestCamera().run()
Their is no problem with the code. To run the code on Android, you have to give it permission. Here is the code; you can add it on the top of your code:
from android.permissions import request_permissions, Permission
request_permissions([Permission.CAMERA,Permission.WRITE_EXTERNAL_STORAGE,Permission.READ_EXTERNAL_STORAGE])
NOTE: After importing the Android module, the code may give an “import error” while compiling on a desktop, but it will build and run successfully on Android.
Also, don't forget to change the code in the buildozer.spec file:
android.permissions = CAMERA, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE
Simple problem I'm having:
When I click a button in my Kivy/Python app, I want to gain access to the ID of that button.
# Kivy code
Button:
id: position_1
on_press: app.access_button_id()
I have had various trial and error attempts but I cannot figure it out. The button is nested as follows (as part of a bigger app), if this is a factor in my problem:
FloatLayout:
AnchorLayout:
ScreenManager:
Screen:
BoxLayout:
FloatLayout:
Button:
id: position_1
on_press: app.access_button_id()
Here is my Python code, which returns all of the id's. That's as close as I have got:
# Python code
def access_button_id(name):
print(self.root.ids)
The problem I've got is that I don't even know what I should be looking at in the documentation as I do not fully understand the terminology yet, so I can't find the right information to learn from.
EDIT:
The (name) passed into the function is for some other functionality, not related to this problem.
You already know the id - you set it yourself. These are mostly used as a hard-coded values in your code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string('''
<MyWidget>:
Button:
id: id_value_1
text: 'Print my id'
on_press: print({'id_value_1': self.proxy_ref})
Button:
id: id_value_2
text: 'Print all ids'
on_press: print(root.ids)
''')
class MyWidget(BoxLayout):
pass
class MyApp(App):
def build(self):
widget = MyWidget()
print({'id_value_1': widget.ids['id_value_1']})
return widget
if __name__ == '__main__':
MyApp().run()
Why do you need id of a Button if you already have an access to it? What are you trying to accomplish?
EDIT
An example solution to problem mentioned in the comment:
import random
import functools
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.lang import Builder
Builder.load_string('''
<MyWidget>:
Button:
text: 'B1'
on_press: root.open_popup(self)
Button:
text: 'B2'
on_press: root.open_popup(self)
''')
class MyWidget(BoxLayout):
def open_popup(self, caller):
fun = functools.partial(self.rename, caller)
popup = Popup(
title='Test popup',
content=Button(
text='rename',
on_press=fun
),
size_hint=(None, None), size=(400, 400)
)
popup.open()
def rename(self, caller, *args):
caller.text = ''.join(chr(random.randint(48, 90)) for i in range(5))
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
All the tutorials in the internet show how to use the ScreenManager and change different screens from the .kv files.
I am still learning and I can not manage to control it from the .py file.
I want my app first to perform some validation before starting. There fore i want Kivy app to start with a simple "Please wait" screen, and after that to go to the Main screen.
Please help!
Here is a short example of how one can change a screen from the python code
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
Builder.load_string("""
<Screen1>:
name: 'screen1'
Button:
on_press: root.on_click()
<Screen2>:
name: 'screen2'
Label:
text: "Cool!"
<MyScreenManager>:
Screen1:
Screen2:
""")
class Screen1(Screen):
def on_click(self):
sm.current = 'screen2'
class Screen2(Screen):
pass
class MyScreenManager(ScreenManager):
pass
class SimpleApp(App):
def build(self):
global sm
sm = MyScreenManager()
return sm
SimpleApp().run()
I have used the button on_press event to call the python code but you can run your validations in another thread and when your are done you can call back to the kivy code using the Clock api