i want to access an id from class main to class fahim2_pop. want to access to word from textinput(in main class) to the popup widget which will appear when someone press the search button. when someone search "hello" and press search button the the popup widget will appear and in that popup widget the text of the label will be "hello" same as from the textinput. but the label and the id remains in different class. how to do it?
python code
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.properties import *
class fahim2_pop(Popup):
pass
class main(BoxLayout):
def word(self):
pop=fahim2_pop()
pop.open()
class go(BoxLayout):
def main(self):
self.clear_widgets()
self.add_widget(main())
class CallApp(App):
def build(self):
return go()
CallApp().run()
kv code
Builder.load_string('''
<main>:
BoxLayout:
orientation:"vertical"
TextInput:
id:word
Button:
text:"search"
on_press:root.word()
<go>:
Button:
text:"go"
on_press:root.go()
<fahim2_pop>:
id:pop
title:"result"
BoxLayout:
Label:
text:app.root.ids.word.text
''')
i know app.root.ids.word.text if that id remain in root of my app. but here go is the root of app. how to access id from class main in class fahim2_pop?
There are a couple of ways of solving this problem. One of the solution is as follow:
py file
Rename method main() in class go() to go() because in your kv file, you have binded on_press: root.go()
Instantiate main() and store it in a class attribute, main
Snippets - py file
from kivy.properties import ObjectProperty
...
class go(BoxLayout):
main = ObjectProperty(None) # declare class attribute
def go(self):
self.clear_widgets()
self.main = main()
self.add_widget(self.main)
kv file
Replace text:app.root.ids.word.text with text:app.root.main.ids.word.text
Snippets - kv file
<fahim2_pop>:
...
Label:
text:app.root.main.ids.word.text
Example - main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
Builder.load_string('''
<main>:
BoxLayout:
orientation:"vertical"
TextInput:
id:word
Button:
text:"search"
on_press:root.word()
<go>:
Button:
text:"go"
on_press:root.go()
<fahim2_pop>:
id:pop
title:"result"
BoxLayout:
Label:
text:app.root.main.ids.word.text
''')
class fahim2_pop(Popup):
pass
class main(BoxLayout):
def word(self):
pop = fahim2_pop()
pop.open()
class go(BoxLayout):
main = ObjectProperty(None)
def go(self):
self.clear_widgets()
self.main = main()
self.add_widget(self.main)
class CallApp(App):
def build(self):
return go()
CallApp().run()
Output
Related
ok, look can anyone give an example in kivy .kv file of a button that is set to a command that when you press it,it will make a label beneath the button,
I attempted this
python
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.label import Label
Builder.load_file("my.kv")
class MyLayout(Widget,App):
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
def addthelabel(self):
self.button = Label(text"you have just added me")
self.add_widget(self.button)
class UiApp(App):
def build(self):
return MyLayout()
UiApp().run()
.kv file
<MyLayout>:
BoxLayout:
orientation:"horizontal"
size: root.width, root.height
Button:
text:"hello"
on_press:
root.addthelabel()
but when I ran it and clicked the button it's not what I expected
IMAGE
https://i.stack.imgur.com/ZoOCj.png
so I need a fresh example can you guys help.
The reason you are seeing this behaviour is because in addthelabel(), the new Label is being added as a child of the root MyWidget layout, rather than to the BoxLayout that contains the existing button.
To get the behaviour you want you need to add an id to the BoxLayout in the kv file that allows you to access that widget from the Python code. You also need to change the orientation to vertical.
<MyLayout>:
BoxLayout:
id: layout
orientation:"vertical"
size: root.width, root.height
Button:
text:"hello"
on_press: root.addthelabel()
Then in the Python code, instead of adding the new Label to the root widget, we want to add it to the BoxLayout using its new id
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.label import Label
Builder.load_file("my.kv")
class MyLayout(Widget,App):
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
def addthelabel(self):
self.button = Label(text="you have just added me")
self.ids.layout.add_widget(self.button)
class UiApp(App):
def build(self):
return MyLayout()
UiApp().run()
I'd like to access my image's source by pointing to its ID.
When I try it this way without using ScreenManager it works fine but using ScreenManager and gives the following error message:
AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'source'
So do you have any idea how to access my image using ScreenManager?
Python code:
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
class MainWindow(Screen):
img1 = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
self.print_image()
def print_image(self):
print(self.img1)
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
Gui = Builder.load_file("my.kv")
class MyApp(App):
def build(self):
return Gui
if __name__ == "__main__":
MyApp().run()
kv code:
WindowManager:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
img1: img1
Button:
id: b1
text: "Submit"
Image:
id: img1
source: "IMG_8681.jpg"
<SecondWindow>:
name: "second"
Button:
text: "Go Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
Thanks a lot in advance!
You can access the Image as you described, but a print statement in a class, outside any method, is executed when the class is loaded and even before the kv file is loaded.
You can access the Image like this:
print(Gui.get_screen('main').img1)
or within a method in the MainWindow class, you can use:
print(self.img1)
But you must wait till the App is started
>> BACKGROUND :
I want to update/change the text of a Button in the SecondScreen with a press of a Button in the MainScreen. Well I did some research and did what I want, and when I checked in the terminal the text did change. BUUT, the text shown on the SecondScreen did not.
>> THIS IS WHAT I DID :
((Mind you that I'm only using snippets of code for example, I'm going to post the whole code below.))
Button:
text:"PRESS TO CHANGE TEXT"
on_press:
root.funcself()
## on press it goes to it's root and do the "funcself" function in it
which is :
class MainScreen(Screen):
def funcself(self):
app.second.funcscreen()
## it re-directs to the SecondScreen and do the "funcscreen" function
which is :
class SecondScreen(Screen):
def funcscreen(self):
self.ids["button"].text = "SUPPOSED TO CHANGE TO THIS"
and then I checked if I did it successfully by doing print(self.ids["button"].text), and yes!
It did change, but when I navigated to the next screen, the text shown still didn't change.
Anyone mind helping and explaining?
FULL CODE :
python file :
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
class MainScreen(Screen):
def funcself(self):
app.second.funcscreen()
class SecondScreen(Screen):
def funcscreen(self):
value = self.ids["button"]
self.ids["button"].text = "SUPPOSED TO CHANGE TO THIS"
kv = Builder.load_file("reproduce.kv")
class reproduce(App):
second = SecondScreen()
def build(self):
return kv
def change_screen(self, x):
scrnmngr = self.root.ids["sm"]
scrnmngr.current = x
def check(self):
print(self.second.ids["button"].text)
if __name__ == "__main__":
app = reproduce()
app.run()
kivy file :
<MainScreen>:
GridLayout:
rows:2
Label:
text: "PRESS TO GO TO THE NEXT PAGE"
GridLayout:
cols:2
Button:
text:"PRESS TO CHANGE TEXT"
on_press:
root.funcself()
Button:
text:">>>"
on_press:
app.change_screen("second")
root.manager.transition.direction = "left"
<SecondScreen>:
GridLayout:
rows:2
Label:
id:label
text: "PRESS TO CHECK AND RETURN TO PREV PAGE"
Button:
id:button
text:"TEXT BEFORE CHANGE"
on_press:
app.change_screen("first")
root.manager.transition.direction = "right"
app.check()
GridLayout:
cols: 1
ScreenManager:
id:sm
MainScreen:
id:main
name:"first"
SecondScreen:
id:second
name:"second"
Root Cause
It did not change because there are two instances of SecondScreen() i.e. one instantiated in the kv file and the other one instantiated in the App class, reproduce(). The view presented is created from the kv file and the second instance does not has a view associated to it.
Solution
There are two solutions to the problem, and remove second = SecondScreen() from the App class.
Kivy Screen ยป default property manager
Each screen has by default a property manager that gives you the
instance of the ScreenManager used.
Using get_screen()
class MainScreen(Screen):
def funcself(self):
self.manager.get_screen('second').funcscreen()
Using App.get_running_app() & ids
class MainScreen(Screen):
def funcself(self):
App.get_running_app().root.ids.second.funcscreen()
Example
In the following example, there are two solutions provided but one of it is commented off.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
class MainScreen(Screen):
def funcself(self):
self.manager.get_screen('second').funcscreen()
# App.get_running_app().root.ids.second.funcscreen()
class SecondScreen(Screen):
def funcscreen(self):
value = self.ids["button"]
self.ids["button"].text = "SUPPOSED TO CHANGE TO THIS"
kv = Builder.load_file("reproduce.kv")
class reproduce(App):
def build(self):
return kv
def change_screen(self, x):
scrnmngr = self.root.ids["sm"]
scrnmngr.current = x
def check(self):
print(self.second.ids["button"].text)
if __name__ == "__main__":
reproduce().run()
Output
The second attribute you define in your app class, is a new instantiation of the screen, and not really the instance you got in your screenmanager, which you add in kv. This is why when you check, you see its changed, but not on the right instance. And again when you call app.second.func, from mainscreen, again its the wrong instance.
But your app always has a root. In your case its the gridlayout. And every screen has a manager. There are a couple of ways to acces it. But you can do like this.
In your mainscreen class in kv:
Button:
text:"PRESS TO CHANGE TEXT"
on_press:
root.manager.get_screen("second").ids["button"].text = "Something"
Here it gets the screenmanager, and uses its get_screen() method to get the screen named second, and then the id's of that kv rule.
i want popup effect for references in kivy reStructuredText renderer, in default when we press any reference it scrolls to the reference, here i want to replace scroll with a popup, i have been searching for this for a long time but in vain, today i found goto(ref, *largs)in kivy docs, is it possible to call a reference popup using this? is it possible to redefine RstDocument fuctions in another class and use it?? i am a beginner.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string("""
<RSTGUI>:
RstDocument:
text: root.doc
goto: # Any Popup aur bubble with reference
""")
class RSTGUI(BoxLayout):
doc="""
.. _top:
Hello world
===========
This is an **emphased text**, some ``interpreted text``.
And this is a reference to top_::
$ print("Hello world")
"""
class RST(App):
def build(self):
return RSTGUI()
if __name__=='__main__':
RST().run()
After little research i have figured it out, Alhumdolillah.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.rst import RstDocument
from kivy.uix.popup import Popup
Builder.load_string("""
<RSTGUI>:
MyRST:
text: root.doc
<about_us_popup>:
size_hint: 0.8,0.6
title: "About Us"
BoxLayout:
orientation:'vertical'
RstDocument:
text: "MyText"
Button:
text:"OK"
size_hint: 1,0.1
on_press:root.dismiss()
""")
class RSTGUI(BoxLayout):
doc="""
.. _top:
Hello world
===========
This is an **emphased text**, some ``interpreted text``.
And this is a reference to top_::
$ print("Hello world")
"""
class MyRST(RstDocument):
def __init__(self, **kwargs):
super(MyRST, self).__init__(**kwargs)
self.about_us_popup = about_us_popup()
def goto(self, ref, *largs):
self.about_us_popup.open()
class RST(App):
def build(self):
return RSTGUI()
class about_us_popup(Popup):
pass
if __name__=='__main__':
RST().run()
I have the following code:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
class GUI(FloatLayout):
def remove(self):
self.remove_widget(self.ids.test)
class GUIApp(App):
def build(self):
return GUI()
if __name__ == '__main__':
GUIApp().run()
And the corresponding kv file:
#:kivy 1.9.1
<GUI>:
BoxLayout:
Button:
id: test
text: 'Test'
on_press: root.remove()
The button should be removed when clicked. However, this does not happen. If I remove the BoxLayout in the kv file, the program works as expected, and the button is removed. Why does this happen, and how can I remove a widget declared in a kv file? (I know I can replace the Button's on_press with self.parent.remove_widget(self), but I have code in root.remove() besides removing the widget.)
You're calling remove_widget of GUI object when your button's parent is actually BoxLayout inside it. remove_widget only deletes a direct children, not any descendant.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
Builder.load_string('''
<GUI>:
BoxLayout:
id: layout
Button:
id: test
text: 'Test'
on_press: root.remove()
''')
class GUI(FloatLayout):
def remove(self):
self.ids.layout.remove_widget(self.ids.test)
class GUIApp(App):
def build(self):
return GUI()
if __name__ == '__main__':
GUIApp().run()