I'm trying to get the nickname from the intro screen and then build the chat screen using this nickname in a label. However, I can't get my function to work with ids properly.
.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
Screens:
transition: FadeTransition()
Intro
Chat
<Intro>:
id: intro
TextInput:
id: intro_text
...
Button:
...
on_press: root.intro_bt_press()
<Chat>:
name: "main"
Label:
id: lb_name
.py:
from kivy import require
require("1.9.1")
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager, FadeTransition
from kivy.lang import Builder
nick = ""
class Chat(Screen):
lb_name.text = "Chat with {}".format(nick)
class Intro(Screen):
global nick
def intro_bt_press(self):
nick = intro_text.text
App.get_running_app().root.current = "main"
class Screens(ScreenManager):
pass
Screens = Builder.load_file("chat.kv")
class Chat(App):
def build(self):
return Screens
if __name__ == "__main__":
Chat().run()
So when the button is pressed, I want to get the text from TextInput, switch to the main screen and format the label on that screen with the text. I can't assign the text to the variable "nick" because it says that it's not defined. And the same goes for lb_name, but I can't even get past the first error. What am I missing before the id to tell Python, where in the kv file to look?
The ids assigned in kv are available in the ids
property. if you want to access the widgets in your Python file, use something like self.ids['intro_text'].text in intro_bt_press.
However, the desired behaviour can be achieved just using the kv language:
This is chat.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
<Screens#ScreenManager>:
Screens:
transition: FadeTransition()
Intro
Chat
<Intro#Screen>:
BoxLayout:
TextInput:
id: intro_text
Button:
on_press:
root.manager.get_screen('main').ids.lb_name.text = root.ids.intro_text.text
root.manager.current = "main"
<Chat#Screen>:
name: "main"
Label:
id: lb_name
And this is chat.py:
from kivy.app import App
class ChatApp(App):
pass
if __name__ == "__main__":
ChatApp().run()
Related
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
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.
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.uix.dropdown import DropDown
class MyPracticeApp(App):
def build(self):
return Debit()
class Debit(Widget):
def debit(self):
return Hello()
class Hello(Widget):
pass
if __name__ == "__main__":
MyPracticeApp().run()
kv file...
<Debit>
Button:
text : 'popup'
size_hint : 0.2,0.2
on_press : root.debit()
<Hello>:
Button:
text : 'popup2'
size_hint : 0.2,0.2
# on_press : root.debit()
There is a button popup, and when I press this button I am calling the debit() function. Inside the debit function I am calling Hello(), but I'm unable to get anything from this class. What am I doing wrong?
Whenever I click on a buttton I want a new screen but without screen navigation. How do I do this ?
You can use ScreenManager for this.
A little example:
from kivy.app import App
from kivy.lang import Builder
KV = """
#:import NoTransition kivy.uix.screenmanager.NoTransition
BoxLayout:
orientation: "vertical"
Label:
text: "top"
ScreenManager:
id: sm
transition: NoTransition()
Screen:
name: "screen1"
Button:
text: "screen 2"
on_release: sm.current = "screen2"
Screen:
name: "screen2"
Button:
text: "screen 1"
on_release: sm.current = "screen1"
Label:
text: "bottom"
"""
class TestApp(App):
def build(self):
return Builder.load_string(KV)
TestApp().run()
Question Kivy Factory
what is the concept of Factory in kivy
Answer
When the keyword Factory is used anywhere (e.g. kv file, or Python script) in your project, it will automatically register any class or module and instantiate them.
Example
The following example illustrates the use of Factory in the kv file to register and instantiate Popup widget, Hello. There is no class definition of Hello and no definition for method debit() in Python script.
main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
Builder.load_string("""
#:import Factory kivy.factory.Factory
<Debit>:
Button:
text : 'popup'
size_hint : 0.2,0.2
on_press : Factory.Hello().open()
<Hello#Popup>:
title: 'Popup2'
auto_dismiss: False
BoxLayout:
orientation: 'vertical'
Label:
text: 'Hello Kivy'
Button:
text : 'Close Popup'
size_hint : 1,0.2
on_press : root.dismiss()
""")
class Debit(Widget):
pass
class MyPracticeApp(App):
def build(self):
return Debit()
if __name__ == "__main__":
MyPracticeApp().run()
References: Kivy ยป Factory object
Question 1
There is a button popup, and when I press this button I am calling the
debit() function. Inside the debit function I am calling Hello(), but
I'm unable to get anything from this class. What am I doing wrong?
Explanation
The second button is not displayed because the app did not have instructions on what to do with the instantiated object, Hello which contains a child widget, Button.
Solution
One of the solution is to add the new object using add_widget() function.
Snippets - Py
def debit(self):
return self.add_widget(Hello())
Question 2
Whenever I click on a button I want a new screen but without screen
navigation. How do I do this ?
Solution
You could use Kivy Popup widget.
Example
main.py
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.lang import Builder
Builder.load_string("""
<Debit>:
Button:
text : 'popup'
size_hint : 0.2,0.2
on_press : root.debit()
<Hello>:
title: 'Hello Popup2'
auto_dismiss: False
Button:
text : 'Close Popup'
size_hint : 0.2,0.2
on_press : root.dismiss()
""")
class Debit(Widget):
def debit(self):
return Hello().open()
class Hello(Popup):
pass
class MyPracticeApp(App):
def build(self):
return Debit()
if __name__ == "__main__":
MyPracticeApp().run()
Output
i have a simple test program:
main.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen
from kivy.clock import mainthread
class TestScreen(Screen):
#mainthread
def on_pre_enter(self): #Is loaded before kv buttons etc? how make it work
pass
#mainthread
def on_enter(self): #Load after kv buttons etc?
button = Button(text="Work?")
#how now add it to display?
#how control where display it? on end or begin is just about on_pre and on?
class TestApp(App):
pass
if __name__ == '__main__':
TestApp().run()
And test.kv file
#:import NoTransition kivy.uix.screenmanager.NoTransition
<TestScreen>:
name:'try'
GridLayout:
id:'test'
cols:2
Button:
text:'Test'
on_press:app.root.current='Main'
ScreenManager:
transition: NoTransition()
Screen:
name: 'Main'
GridLayout:
cols:1
Button:
text:'1'
Button:
text:'2'
Button:
text:'Test'
on_press:root.current='try'
TestScreen:
Is simple to control kv and python widgets(but i dont know how but is more easy to writes widgets etc in kv file, but still need create some in python for automatic content) or better just create all in python withou kv file? I wanna make somehting like this: App with left menu always displayed and on the right side another screen with dynamic content based on screen(clicked from menu) is maybe another simple solution for this. Anyone can explain me step by step? :)
AttributeError
The solution to AttributeError, please replace "id: 'test'" with "id: test" in test.kv file.
Dynamic Content
It is possible to display screen with dynamic content based on clicked from menu. But remember to remove the widgets that were added when exiting the screen (TestScreen/SettingsScreen). If you do not remove the widgets, you will get duplicates/multiples of each widget added each time you enter the screen (TestScreen/SettingsScreen). I recommend using on_pre_enter and on_leave methods. Please refer to the example below for details.
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
class MyScreenManager(ScreenManager):
pass
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
def on_pre_enter(self, *args):
self.ids.test.add_widget(Button(text="Work?"))
def on_leave(self, *args):
self.ids.test.remove_widget(self.ids.test.children[0])
class TestApp(App):
title = "Add & Remove Widgets Dynamically"
def build(self):
return MyScreenManager()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
#:import NoTransition kivy.uix.screenmanager.NoTransition
<MyScreenManager>:
transition: NoTransition()
MenuScreen:
SettingsScreen:
<MenuScreen>:
name: 'menu'
GridLayout:
cols: 1
Button:
text: '1'
Button:
text: '2'
Button:
text: 'Test'
on_press: root.manager.current = 'settings'
<SettingsScreen>:
name:'settings'
GridLayout:
id: test
cols: 2
Button:
text: 'Test'
on_press: root.manager.current = 'menu'
Output
I have the same issue like described in this theme kv incorrect. When I use Builder and load the kv file I have normal working app. But when I try to use autoload kv file I have only black screen. Could someone explain me why? Thanks for any help.
My code. main.py
import kivy
kivy.require('1.9.1') # replace with your current kivy version !
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class Test(App):
def build(self):
return ScreenManagement()
if __name__ == "__main__":
Test().run()
kv file. test.kv
#:kivy 1.9.1
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
on_release: app.root.current = "other"
text: "Next Screen"
font_size: 50
<AnotherScreen>:
name: "other"
Button:
on_release: app.root.current = "main"
text: "Prev Screen"
font_size: 50
In your kv file, you define ScreenManagement to be the root element with its associated screens. But in build, you return a newly created ScreenManagement object, which will not have any children defined.
Solution:
Define build as
def build(self):
pass
or change the definition of ScreenManagement in the kv file to
<ScreenManagement>:
transition: FadeTransition()
MainScreen:
AnotherScreen:
so this will apply to all new ScreenManagement objects.
you can also add:
from kivy.properties import ObjectProperty
then change:
class ScreenManagement(ScreenManager):
pass
to this:
class ScreenManagement(screenManager):
mainscreen = ObjectProperty(None)
anotherscreen = ObjectProperty(None)
then in your .kv file you want to change this:
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
to this:
<ScreenManagement>:
transition: FadeTransition()
mainscreen: mainscreen
anotherscreen: anotherscreen
then for your MainScreen add and id like so:
<MainScreen>:
id: mainscreen
and do the same for you AnotherScreen.
Check the version of your Python and the version of Pygame you're using. I got that problem and my issue came from the version of Pygame.