I am not able to place an AccordionItem on a screen of the Kivy ScreenManager. For this I have to define something like root = Accordion(). But I don't know where the ScreenLayout is defined. I build it up in pure python, cause i´m complete new to Kivy, but not new to python.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.accordion import Accordion, AccordionItem
class ScreenOne(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
btn1 = Button(
text='change screen',
size_hint=(.5, .05),
pos_hint={'left':0, 'top':1}
)
btn1.bind(on_press=self.changer)
self.add_widget(btn1)
def changer(self,*args):
self.manager.current = 'screen2'
def test(self,instance):
print('This is a test')
class ScreenTwo(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
btn2 = Button(
text='change screen',
size_hint=(.5, .25),
pos_hint={'left':0, 'top':1}
)
btn2.bind(on_press=self.changer)
self.add_widget(btn2)
title = ["Title 1", "Title 2","Title 3","Title 4","Title 5"]
for x in range(5):
item = AccordionItem(title= title[x])
item.add_widget(Label(text='Very big content\n' * 10))
self.add_widget(item)
return sm
def changer(self,*args):
self.manager.current = 'screen1'
def test(self,instance):
print('This is another test')
class TestApp(App):
def build(self):
sm = ScreenManager()
sc1 = ScreenOne(name='screen1')
sc2 = ScreenTwo(name='screen2')
sm.add_widget(sc1)
sm.add_widget(sc2)
print (sm.screen_names)
return sm
if __name__ == '__main__':
TestApp().run()
ScreenTwo should show the 5 AccordionItems. But they overlap and are not working properly.
By default, a Screen displays nothing: it’s just a RelativeLayout. Therefore, in order to display a Button and an Accordion widgets in the second screen, you need to enclose those two widgets in a layout e.g. BoxLayout.
Example
The following snippets illustrates using a BoxLayout widget to enclose a Button and an Accordion widgets.
Snippets - py file
from kivy.uix.boxlayout import BoxLayout
...
class ScreenTwo(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
layout = BoxLayout(orientation='vertical') # instantiate BoxLayout
self.add_widget(layout) # add BoxLayout to screen
btn2 = Button(
text='change screen',
size_hint=(.5, .05),
)
btn2.bind(on_press=self.changer)
layout.add_widget(btn2) # add Button to BoxLayout
title = ["Title 1", "Title 2", "Title 3", "Title 4", "Title 5"]
accordion = Accordion() # instantiate Accordion
layout.add_widget(accordion) # add Accordion to BoxLayout
for x in range(5):
item = AccordionItem(title=title[x])
item.add_widget(Label(text='Very big content\n' * 10))
accordion.add_widget(item) # add AccordionItem to Accordion
Output
Related
After some days looking for an answer, I finally decided that it was time to ask some more experienced users ! Here is my problem : in the following piece of code (simplified version of the original code), when I open the Dialog by clicking on the button, the opened window doesn't have the right size, and so one part of the GridLayout is appearing outside this popup.
I anyone has an idea, thanks in advance !
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivymd.uix.dialog import MDDialog
class AppClass(MDApp):
def build_toolbar(self):
button = Button(text="Press")
button.bind(on_press=self.popup)
return button
def build(self):
self.theme_cls.theme_style = "Dark"
layout = BoxLayout(orientation='vertical')
toolbar = self.build_toolbar()
layout.add_widget(toolbar)
return layout
#==============================
def popup(self, instance):
print("called")
panel = self.build_settings_panel()
self.dialog = MDDialog(
type="custom",
title="Settings",
content_cls=panel
)
self.dialog.open()
def build_settings_panel(self):
panel = GridLayout(cols=2, row_default_height=100)
for i in range(4):
panel.add_widget(Label(text="Number"))
panel.add_widget(Label(text=str(i)))
return panel
if __name__ == '__main__':
AppClass().run()
It appears that the problem is the size of the panel. way to fix that is to just calculate that size and set it in the build_settings_panel():
def build_settings_panel(self):
row_height = 100
total_height = 0
panel = GridLayout(cols=2, row_default_height=row_height)
for i in range(4):
panel.add_widget(Label(text="Number"))
panel.add_widget(Label(text=str(i)))
total_height +=row_height
panel.height = total_height
return panel
You can try:
row_default_height=9
In your code:
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivymd.uix.dialog import MDDialog
class AppClassjbsidis(MDApp):
def build_toolbar(self):
button = Button(text="Press")
button.bind(on_press=self.popup)
return button
def build(self):
self.theme_cls.theme_style = "Dark"
layout = BoxLayout(orientation='vertical')
toolbar = self.build_toolbar()
layout.add_widget(toolbar)
return layout
#==============================
def popup(self, instance):
print("called")
panel = self.build_settings_panel()
self.dialog = MDDialog(
type="custom",
title="[color=ffffff]Settings",
content_cls=panel
)
self.dialog.open()
def build_settings_panel(self):
panel = GridLayout(cols=2, row_default_height=9)
for i in range(4):
panel.add_widget(Label(text="Number"))
panel.add_widget(Label(text=str(i)))
return panel
if __name__ == '__main__':
AppClassjbsidis().run()
Pictures:
i would like to ask for favor here for python kivy desktop application, i have small problem but it is so annoying. the problem that i have is switching between two buttons (Yes Button and No Button) in kivy Popup with keyboard "Tab key" is not working and also i want to be able pressing "Enter key" for the selected button processing the function.
here is my Popup looks like:
Popup screenshot
and the code of the popup is as follow:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
class testWindow(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def yes_btn(instance):
print("this function is called.")
contents = BoxLayout(orientation='vertical')
content_text = Label(text="Lanjutkan Transaksi?")
pop_btn = BoxLayout(spacing=10)
btn_yes = Button(text='Ya', size_hint_y=None, height=40)
btn_no = Button(text='Tidak', size_hint_y=None, height=40)
pop_btn.add_widget(btn_yes)
pop_btn.add_widget(btn_no)
contents.add_widget(content_text)
contents.add_widget(pop_btn)
pop_insert = Popup(title="Confirmation Message", content=contents, size_hint=(None, None), size=(300, 300))
btn_yes.bind(on_release=yes_btn)
btn_no.bind(on_release=pop_insert.dismiss)
pop_insert.open()
class testApp(App):
def build(self):
return testWindow()
if __name__ == '__main__':
m = testApp()
m.run()
The popup is functioned properly when i click the button using mouse. as the popup picture above, i would like to make Yes Button focused and when i press "Enter key" popup dismiss and running the function i want. meanwhile to switch between button just press "Tab key".
i have been trying to find the way to solve the problems but still got no result, so please if anyone know how to solve my problem help me.
Here is a modification of your code that I think does what you want:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.behaviors import FocusBehavior
# This is a Button that also has focus behavior
class FocusButton(FocusBehavior, Button):
first_focus = BooleanProperty(False)
def on_parent(self, widget, parent):
# if first_focus is set, this Button takes the focus first
if self.first_focus:
self.focus = True
class MyPopup(Popup):
def keydown(self, window, scancode, what, text, modifiers):
if scancode == 13:
for w in self.walk():
if isinstance(w, FocusButton) and w.focus:
w.dispatch('on_press')
def keyup(self, key, scancode, codepoint):
if scancode == 13:
for w in self.walk():
if isinstance(w, FocusButton) and w.focus:
w.dispatch('on_release')
def on_dismiss(self):
Window.unbind(on_key_down=self.keydown)
Window.unbind(on_key_up=self.keyup)
Builder.load_string('''
# provide for a small border that indicates Focus
<FocusButton>:
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.x-2, self.y-2
size: (self.size[0]+4, self.size[1]+4) if self.focus else (0,0)
''')
class testWindow(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def yes_btn(instance):
print("this function is called.")
contents = BoxLayout(orientation='vertical')
content_text = Label(text="Lanjutkan Transaksi?")
pop_btn = BoxLayout(spacing=10)
# set first_focus to True for this Button
self.btn_yes = FocusButton(text='Ya', size_hint_y=None, height=40, first_focus=True)
self.btn_no = FocusButton(text='Tidak', size_hint_y=None, height=40)
pop_btn.add_widget(self.btn_yes)
pop_btn.add_widget(self.btn_no)
contents.add_widget(content_text)
contents.add_widget(pop_btn)
pop_insert = MyPopup(title="Confirmation Message", content=contents, size_hint=(None, None), size=(300, 300))
self.btn_yes.bind(on_release=yes_btn)
self.btn_no.bind(on_release=pop_insert.dismiss)
# bind to get key down and up events
Window.bind(on_key_down=pop_insert.keydown)
Window.bind(on_key_up=pop_insert.keyup)
pop_insert.open()
class testApp(App):
def build(self):
return testWindow()
if __name__ == '__main__':
m = testApp()
m.run()
This code adds FocusBehavior to a Button to create a FocusButton, and adds key down and key up processing to the MyPopup class.
I am just trying to get code working where I have two screens in a Python Kivy app that can switch back and forth, without using the .kv file stuff.
On this page: https://kivy.org/docs/api-kivy.uix.screenmanager.html, the second block of code from the top is what I am trying to accomplish, except I want to do it without the 'Builder.load_string("""' section, and instead just instantiate buttons normally.
Here is my attempt at doing so, except I can't get it to work:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class MenuScreen(Screen):
def build(self):
def switchScreen():
root.manager.current = 'settings'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
class SettingsScreen(Screen):
def build(self):
def switchScreen():
root.manager.current = 'menu'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class MainApp(App):
def build(self):
return sm
if __name__ == '__main__':
MainApp().run()
Running this code just creates a blank page that produces no errors.
Is there a way to designate it to draw a certain screen to begin with that I am missing? I'm not really sure where my issue is.
What you did wrong:
If you want to create Widget content from Python code you should place it inside Widget __init__ method, not build
You're creating a layout and then discarding it. You need to use self.add_widget(f) to actually use it after its creation
You're binding to your switchScreen method, so it needs to accept caller widget as an argument. Or you can simply use *args and not worry about it.
You're not in kv anymore, so there's no root. Use self instead.
Putting this all together:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class MenuScreen(Screen):
def __init__(self, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
def switchScreen(*args):
self.manager.current = 'settings'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
self.add_widget(f)
class SettingsScreen(Screen):
def __init__(self, **kwargs):
super(SettingsScreen, self).__init__(**kwargs)
def switchScreen(*args):
self.manager.current = 'menu'
f = FloatLayout()
button1 = Button(text = "My settings button")
button2 = Button(text = "Back to menu", on_press = switchScreen)
f.add_widget(button1)
f.add_widget(button2)
self.add_widget(f)
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class MainApp(App):
def build(self):
return sm
if __name__ == '__main__':
MainApp().run()
i have a kivy code that makes a label, button and a text box. i want to put the textbox next to the button and not under it, how can i do that?
import socket
import sys
import os
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.bubble import Bubble
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
class TextInputApp(App):
def build(self):
layout = BoxLayout(padding=10, orientation='vertical')
btn1 = Button(text="OK", size_hint=(0.49, 0.1),pos_hint={'x': .51, 'center_y': .5})
btn1.bind(on_press=self.buttonClicked)
layout.add_widget(btn1)
self.txt1 = TextInput(multiline=False, text='',
size_hint=(0.5, 0.1))
layout.add_widget(self.txt1)
self.lbl1 = Label(text="Write your guess in the blank text box", size_hint=(1, None), height=30)
layout.add_widget(self.lbl1)
return layout
def buttonClicked(self,btn):
print "hi"
TextInputApp().run()
You could create another BoxLayout with horizontal orientation to harbor the Button and TextInput.
class TextInputApp(App):
def build(self):
layout = BoxLayout(padding=10, orientation='vertical')
# Second boxlayout
layout2 = BoxLayout()
# Add BoxLayout do main layout
layout.add_widget(layout2)
# Drop old size and pos_hints
btn1 = Button(text="OK")
btn1.bind(on_press=self.buttonClicked)
# Add Button to secondary boxlayout
layout2.add_widget(btn1)
self.txt1 = TextInput(multiline=False, text='',
size_hint=(0.5, 0.1))
layout.add_widget(self.txt1)
# Drop size_hint
self.lbl1 = Label(text="Write your guess in the blank text box")
layout2.add_widget(self.lbl1)
return layout
If you want to change the size of the Button and TextInput, you can set that in the secondary BoxLayout:
layout2 = BoxLayout(size_hint_y=None, height=30)
Trying to populate the text of three buttons with the content of myList["One", "Two", "Three"]
btn1 = myList[1] etc
myList will be populated fron csv file
from kivy.app import App
from kivy.lang import Builder
kv = """
BoxLayout:
Button:
id: btn1
Button:
id: btn2
Button:
id: btn3
"""
class TestApp(App):
def build(self):
my_box = Builder.load_string(kv)
my_ShowList = ['My Way', 'Wine Drinker', 'Boots']
'''
This is where I get lost
want to use for loop to populate Button text with my_ShowList items
'''
return my_box
if __name__ == '__main__':
TestApp().run()enter code here`
You can do it entirely in python code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class TestClass(App):
def build(self):
my_box = BoxLayout()
my_show_list = ["My Way", "Wine Drinker", "Boots"]
my_box.my_buttons = [] # if you want to keep an "easy" reference to your buttons to do something with them later
#kivy doesnt crashes because it creates the property automatically
for message in my_show_list:
button = Button(text=message)
my_box.my_buttons.append(button)
my_box.add_widget(button)
return my_box
if __name__ == "__main__":
TestClass().run()
This should solve this problem:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class MyLayout(BoxLayout):
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
self.btn_list = ['My Way', 'Wine Drinker', 'Boots']
for btn_text in self.btn_list:
self.add_widget(Button(text=btn_text))
class MyApp(App):
def build(self):
return MyLayout()
if __name__ == '__main__':
MyApp().run()