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"
Related
I am trying to make an app that starts in the main menu, you press the play button and it sends you to the game on a different screen.
Problem is i keep getting an error on the:
"kv= Builder.load_file("my.kv")" saying that "WindowManager" is an unknown class.
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.vector import Vector
from kivy.uix.floatlayout import FloatLayout
kv= Builder.load_file("my.kv")
class WindowManager(ScreenManager):
pass
class MenuWindow(Screen):
pass
class Game(Screen):
pass
class MyApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyApp().run()
AND HERE IS THE KV FILE:
WindowManager:
MenuWindow:
Game:
<MenuWindow>:
name: "Menu"
FloatLayout:
Button:
text:"Play"
on_release:
app.root.current= "Game"
<Game>:
name: "Game"
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.
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
I am attempting to construct a screen with a VERTICAL splitter to separate content; however, I am unsuccessful in identifying a solution even after consulting the kivy docs and looking through the related questions here.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.splitter import Splitter
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.relativelayout import RelativeLayout
from kivy.properties import StringProperty, DictProperty
from kivy.uix.screenmanager import ScreenManager, Screen
kv = '''
ScreenManagement:
id: 'manager'
MainScreen:
name: 'main'
manager: 'manager'
<MainScreen>:
BoxLayout:
orientation: 'vertical'
Button:
text: 'New'
Splitter:
sizeable_from: 'top'
Button:
text: 'test'
'''
class ScreenManagement(ScreenManager):
pass
class MainScreen(Screen):
pass
class MyApp(App):
def build(self):
return Builder.load_string(kv)
MyApp().run()
Here is what I am current seeing with this code
As you can see, the splitter is beside the second button rather than between the buttons horizontally; and when the splitter is activated, it shrinks the button horizontally rather than vertically. How do I change the code for the effect that I desire?
Simple misspelling. sizeable_from should be sizable_from.