In this code, there is a Button and I have made a Toggle Button inside the Main button. ON pressing the main button, I want the state of the Toggle Button to be "down". How can I do so?
Main Code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import Screen,ScreenManager
class Main(Screen):
def onbtn(self,widget):
for child in self.ids.Fl.children:
if isinstance(child, ToggleButton): # This part is wrong... How to access Widgets inside child Widgets?
child.state='down'
class Manager(ScreenManager):
pass
kv=Builder.load_file("test2.kv")
screen=Manager()
screen.add_widget(Main(name="main"))
class Test(App):
def build(self):
return screen
Test().run()
Kv Code:
<Main>:
name: "main"
FloatLayout:
id: Fl
Button:
id: btn1
text: "BTN 1"
size_hint: (.5,.3)
pos_hint: {"center_x":.5,"center_y":.6}
on_press:
root.onbtn(self)
ToggleButton:
id: tglbtn1 # How to Access this button to change its state to down
size: 80,80
text: "TGL BTN 1"
pos: 500,400
Just change:
class Main(Screen):
def onbtn(self,widget):
for child in self.ids.Fl.children:
if isinstance(child, ToggleButton): # This part is wrong... How to access Widgets inside child Widgets?
child.state='down'
to:
class Main(Screen):
def onbtn(self,widget):
for child in widget.children:
if isinstance(child, ToggleButton):
child.state='down'
The widget that is passed into the onbtn() method is the Button.
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 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
>> 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 am new to Kivy language. I am trying build a simple program to switch between two screens. First screen with contain a button which on_release it will switch to second screen. On clicking the button on second screen will get to first screen.
Issues i face:
1. Button is placed on the corner and i am expecting its size to be full window but it small
On click and release the button doesnt' show any effect.
Chat.kv
<ChatGUI>:
MainManager:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
Button:
text:"to second window"
on_release:app.root.current="second"
<SecondWindow>:
name: "second"
Button:
text:"back to main"
on_release:app.root.current="main"
python code:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.graphics import Rectangle, Color, Canvas
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
class ChatGUI(Widget):
present=Builder.load_file("Chat.kv")
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class MainManager(ScreenManager):
pass
class ChatApp(App):
def build(self):
return ChatGUI()
if __name__=="__main__":
ChatApp().run()
My output# i am not able to add image so posted link of output
I am practicing from youtube tutorial.
I have checked many codes from stack overflow and i don't see issues in my code.
output should display button of size occupying whole window and on_release it should switch to next screen.
Can you let me know what could be issue.
You do not need to add a ScreenManager inside a Widget.
So
class ChatGUI (ScreenManager):
in python file and
<ChatGUI>:
MainWindow:
SecondWindow:
in kv file
that's all I changed to make your example work.
Chat.kv
<ChatGUI>:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
Button:
text:"to second window"
on_release:app.root.current="second"
<SecondWindow>:
name: "second"
Button:
text:"back to main"
on_release:app.root.current="main"
main.py
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.graphics import Rectangle, Color, Canvas
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
class ChatGUI(ScreenManager):
present=Builder.load_file("Chat.kv")
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class ChatApp(App):
def build(self):
return ChatGUI()
if __name__=="__main__":
ChatApp().run()
Problem 1 - widget # bottom left hand corner & not full window?
Button is placed on the corner and i am expecting its size to be full
window but it small
Root Cause
The Button widget appeared on the bottom left hand corner because the root is a Widget and no position (pos, or pos_hint) was provided. Therefore, the default position of (0, 0) was used.
The size is not a full window because by default the size of a Widget is (100 x 100) or the default size_hint is (1, 1).
Kivy Widget » Default values
A Widget is not a Layout: it will not change the position or the size of its children. If you want control over positioning or
sizing, use a Layout.
The default size of a widget is (100, 100). This is only changed if the parent is a Layout. For example, if you add a Label inside a
Button, the label will not inherit the button’s size or position
because the button is not a Layout: it’s just another Widget.
The default size_hint is (1, 1). If the parent is a Layout, then the widget size will be the parent layout’s size.
Problem 2 - on release button screen not switched?
On click and release the button doesnt' show any effect.
Root Cause
The screen was not switched when button press was released, because the root of the App is not a ScreenManager.
Solution
There are two options to the problems.
Option 1 - use Layout as root
This option use BoxLayout as the root and requires the following enhancements. A Layout can be a GridLayout, BoxLayout, FloatLayout, etc.
Py file
Replace Widget with BoxLayout
Replace present = Builder.load_file(...) with Builder.load_file(...)
Move Builder.load_file(...) out of class ChatGUI() and add pass
kv file
Add id: sm under instantiated object, MainManager:
Replace app.root.current with app.root.ids.sm.current
Snippets - Option 1
main1.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
Builder.load_file("main1.kv")
class ChatGUI(BoxLayout):
pass
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class MainManager(ScreenManager):
pass
class ChatApp(App):
def build(self):
return ChatGUI()
if __name__ == "__main__":
ChatApp().run()
main1.kv
<ChatGUI>:
MainManager:
id: sm
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
Button:
text: "to second window"
on_release: app.root.ids.sm.current="second"
<SecondWindow>:
name: "second"
Button:
text: "back to main"
on_release: app.root.ids.sm.current="main"
Option 2 - use ScreenManager as root
This option requires the following enhancements:
Py file
Remove import statement, from kivy.uix.widget import Widget
Remove class ChatGUI()
Replace return ChatGUI() with return MainManager()
Replace present = Builder.load_file(...) with Builder.load_file(...)
kv file
Remove class rule, : in the kv file
Replace MainManager: with class rule, :
Snippets - Option 2
main2.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
Builder.load_file("main2.kv")
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class MainManager(ScreenManager):
pass
class ChatApp(App):
def build(self):
return MainManager()
if __name__ == "__main__":
ChatApp().run()
main2.kv
<MainManager>:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
Button:
text: "to second window"
on_release: app.root.current="second"
<SecondWindow>:
name: "second"
Button:
text: "back to main"
on_release: app.root.current="main"
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()