How to use Widget Class with Screen class - python

I made a kivy application where everything is done within this class :
class MyGame(Widget):
Consequently, my kv file look like this
<MyGame>:
GridLayout:
rows: 1
size: root.width, root.height
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
size: self.size
FloatLayout:
Button:
id: question
font_size: 20
size_hint: 0.77, 0.1
pos_hint: {"x": 0.09, "y":0.85}
on_press: root.start_round()
SmoothButton:
But now that my game is almost done I feel the need to include 2 screens:
One is for the game menu (to let the user select a game mode)
The other one is for the game itself
I have tried to include this in my main.py
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
class MenuScreen(Screen):
pass
class GameScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('my.kv')
class MyGame(Widget):
...
and my class that inherits from App returns kv in build
Here is my kv file: WindowManager: MenuScreen: GameScreen:
<MenuScreen>:
name: 'Menu'
Button:
<GameScreen>:
name: 'Game'
<MyGame>:
As you can see I have tried to nest MyGame(Widget) within the GameScreen(Nest) but when I run my code, a screen opens but the screen is black
Does anyone know how I can solve my issue ? This is pretty much my first project in kivy so I have many basics things to learn yet. Thanks

<MenuScreen>:
name: 'Menu'
Button:
<GameScreen>:
name: 'Game'
<MyGame>:
This syntax is wrong, you don't want the <> around MyGame. I don't know if this is the cause of your issue.

Related

python, kivymd, builder, loadfile

I have a seemingly pretty easy question. I am making a app with kivymd and the first .kv file is sort of long. I have three .kv files that I would like to navigate in between. Currently i'm wondering how to use Builder.load_file, or something else to read from window to window, thanks for your help.
Not sure if there is a better way to do this or not. I myself couldn't find anything but ended up doing the following.
Create your main .kv file that is a screen manager. Make sure you include your other .kv files with '#:include 'filename.kv'
#:include screen1.kv
#:include screen2.kv
ScreenManager:
Screen1:
Screen2:
Format your other .kv files however you'd like. Just make sure to include a name for referencing in your screen manager. You must also name the screens the same as you did in your main.kv file.
<Screen1>
name: 'screen1'
orientation: 'vertical'
MDLabel:
text: 'Screen1'
halign: 'center'
MDFlatButton:
text: 'Go to screen 2'
pos_hint: {'center_x': 0.5}
on_release: root.manager.current = 'screen2'
This is .kv file #2
<Screen2>
name: 'screen2'
orientation: 'vertical'
MDLabel:
text: 'Screen2'
halign: 'center'
MDFlatButton:
text: 'Go to screen 1'
pos_hint: {'center_x': 0.5}
on_release: root.manager.current = 'screen1'
Your main.py file will have to include the libraries, define the classes, add the screens to your screen manager, and then you can build your main.kv file in your MDApp.
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
class Screen1(Screen):
pass
class Screen2(Screen):
pass
sm = ScreenManager()
sm.add_widget(Screen1(name= 'screen1'))
sm.add_widget(Screen2(name= 'screen2'))
class MainApp(MDApp):
def build(self):
sm = Builder.load_file("Main.kv")
return sm
MainApp().run()

Kivy: Previous screen still visible behind current (next) screen

I am making a simple GUI with kivy. made twi screens but facing a problem.
PROBLEM: Previous is still visible behind the current screen.
check screenshots:
First Screen..
enter image description here
second screen where first screen is still visible..
enter image description here
main.py code
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file("design.kv")
class LoginScreen(Screen):
def sign_up(self):
self.manager.current = "signup_screen"
class SignUpScreen(LoginScreen):
pass
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MainApp().run()
Here, design.kv
<LoginScreen>:
GridLayout:
cols:1
GridLayout:
cols:1
Label:
text: "User Login"
TextInput:
hint_text:"Username"
TextInput:
hint_text:"Password"
Button:
text:"Login"
GridLayout:
cols:2
Button:
text:"Forgot Password?"
Button:
text:"Sign up"
on_press:root.sign_up()
<SignUpScreen>:
GridLayout:
cols:1
Label:
text:"Welcome to Another Dimension, Bitch!"
TextInput:
hint_text:"New Username"
TextInput:
hint_text:"New Password"
GridLayout:
cols:2
Button:
text:"Submit"
Button:
text:"Cancel"
<RootWidget>:
LoginScreen:
name:"login_screen"
SignUpScreen:
name:"signup_screen"
The problem here is that you inherited your SignUpScreen from your LoginScreen, which is why the widgets of the login screen is still in the signup one. The simple solution here is to instead inherit your SignUpScreen from the Screen class:
class SignUpScreen(Screen):
pass

Not set focus when come back screen manager with kivy and python

I want set the focus in textinput. at the begining the focus set correctly but when i go to the next screen and come back to initial screen the focus dont set correctly.
This is a app with a rfid lector, I want to read a code and select enter or exit
main.py
import kivy
kivy.require('1.10.0') # replace with your current kivy version !
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
class MyScreenManager(ScreenManager):
def __init__(self,**kwargs):
super(MyScreenManager,self).__init__()
class Menu1(Screen):
def __init__(self, **kwargs):
super(Menu1, self).__init__()
class Menu2(Screen):
def __init__(self, **kwargs):
super(Menu2, self).__init__()
Builder.load_file("main.kv")
class Fichaje(App):
def build(self):
return MyScreenManager()
if __name__ == '__main__':
Fichaje().run()
main.kv
#:kivy 1.10.0
#:import WipeTransition kivy.uix.screenmanager.WipeTransition
<MyScreenManager>:
#transition: WipeTransition()
Menu1:
id: menu1
Menu2:
id: menu2
<Menu1>:
name: "screen1"
BoxLayout:
orientation: 'vertical'
TextInput:
id: input1
size_hint_y: .1
multiline: False
focus: True
on_text_validate:
root.manager.current = "screen2"
BoxLayout:
<Menu2>:
name: "screen2"
BoxLayout:
Button:
text:"Entrada"
on_press:
root.manager.current = "screen1"
Button:
text:"Salida"
on_press:
root.manager.current = "screen1"
No error messages but the focus is not in the right site,
Thanks
I change the code to simplify the error
In the example, there is not an attempt to change the focus. But I assume this was tried but it lost focus again.
The reason the text input looses focus again, is because it gets focused before the mouse or tap is released. The on_press method, is followed by on_release where the text input looses focus again.
To fix this you can just set the focus in the on_release method instead.
The quickest is to only add one line of code to the kv file and change on_press to on_release.
root.manager.get_screen("screen1").ids["input1"].focus
This line can be different by using object property in screen1, for example. Or if you cannot use the on_release method, maybe use clock to schedule a focus in some amount of time, and if the touch is still down, reschedule it.
But here is the quick fix.
<Menu2>:
name: "screen2"
BoxLayout:
Button:
text:"Entrada"
on_release:
root.manager.current = "screen1"
root.manager.get_screen("screen1").ids["input1"].focus = True

Python & Kivy: Camera and Changing Screen

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

.kv file doesn't seem to work

So I'm just working with some example Kivy file code, and I came across this code which allows the user to switch between screens:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<MenuScreen>:
BoxLayout:
Button:
text: 'Build Scenario'
on_press: root.manager.current = 'settings'
Button:
text: 'Run Existing Scenerio'
<SettingsScreen>:
BoxLayout:
Button:
text: 'Run Existing Scenerio'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
""")
# Declare both screens
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
I wondered to myself if it would be possible to put the code given in the Builder.load_string() method into a separate .kv file. So I did just that. I commented the Builder part out (I admit I don't know what its role is) and copied the string into a .kv file which looks like this:
# the file name is test.kv
#:kivy 1.0.9
<MenuScreen>:
BoxLayout:
Button:
text: 'Build Scenario'
on_press: root.manager.current = 'settings'
Button:
text: 'Run Existing Scenerio'
<SettingsScreen>:
BoxLayout:
Button:
text: 'Run Existing Scenerio'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
Unfortunately when I run the code now I just get a black screen. Can anyone tell me what's wrong? Thanks!
The code creates the screenmanager (sm) in the main body of the python file. When the kv is loaded from a file this only happens later, so none of the kv rules are applied to sm. It was okay before because the load_string happens before it is instantiated.
For this reason, instantiating widgets this way is bad practice, and the sm = ScreenManager(... etc should be moved to the build method. This is run after the kv file is loaded, so everything should work.

Categories

Resources