I am trying to get a kivy app to open a dropdown. I am following the example here.
When I run the app I can click on the button, but no dropdown appears.
I am missing something simple, but I just can't see it. Can someone help please.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.lang import Builder
root = Builder.load_string('''
<MainFrame>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'Hello'
Button:
text: 'open dropdown'
on_press: root.on_menu_button_click()
''')
class MainFrame(Screen):
def __init__(self, **kwargs):
super(MainFrame, self).__init__(**kwargs)
self.dropdown = self._create_dropdown()
def _create_dropdown(self):
dropdown = DropDown()
for index in range(5):
btn = Button(text='Value %d' % index, size_hint_y=None, height=44)
btn.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(btn)
return dropdown
def on_menu_button_click(self):
self.dropdown.open
class BasicApp(App):
def build(self):
return MainFrame()
if __name__ == '__main__':
BasicApp().run()
You have to use the open() method and pass the button, you must also use on_release instead of on_press.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.lang import Builder
root = Builder.load_string('''
<MainFrame>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'Hello'
Button:
id: btn # <---
text: 'open dropdown'
on_release: root.on_menu_button_click(btn) # <---
''')
class MainFrame(Screen):
def __init__(self, **kwargs):
super(MainFrame, self).__init__(**kwargs)
self.dropdown = self._create_dropdown()
def _create_dropdown(self):
dropdown = DropDown()
for index in range(5):
btn = Button(text='Value %d' % index, size_hint_y=None, height=44)
btn.bind(on_release=lambda btn: dropdown.select(btn.text))
dropdown.add_widget(btn)
return dropdown
def on_menu_button_click(self, widget): # <---
self.dropdown.open(widget) # <---
class BasicApp(App):
def build(self):
return MainFrame()
if __name__ == '__main__':
BasicApp().run()
The above is clearly mentioned in the example as it indicates:
...
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
mainbutton.bind(on_release=dropdown.open)
...
Related
how do I create Dropdown list in the next window after clicking button in the first screen, I tried to initiate the button in the kv file just to have a button in the ModelWindow screen but the next problem is the button variable in ModelWindow class is gone. the button variable is needed for the lista method in order to activate dropdown
Python File
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
class ModelWindow(Screen):
def window(self):
box = BoxLayout(orientation='vertical')
label = Label(text='LABEL')
button = Button(text='Selecione', font_size=30, size_hint_y=0.15, on_release=self.lista)
box.add_widget(label)
box.add_widget(button)
self.dropdown = DropDown() # Create the dropdown once and keep a reference to it
self.dropdown.bind(on_select=lambda instance, x: setattr(button, 'text', x))
for index in range(10): # create the buttons once
btn = Button(text='Value %d' % index, size_hint_y=None, height=44,
on_release=lambda btn: print(btn.text)) # bind every btn to a print statement
btn.text = 'Value %d' % index
btn.bind(on_release=lambda btn: self.dropdown.select(btn.text))
self.dropdown.add_widget(btn)
return box
def lista(self, button):
# dropdown = DropDown() <---- DON'T NEED THIS
# button.bind(on_release=self.dropdown.open) <---- DON'T NEED THIS
self.dropdown.open(button) # you need this to open the dropdown
# print(button.text)
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("proj.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyMainApp().run()
Kv file
WindowManager:
MainWindow:
SecondWindow:
ModelWindow:
<ModelWindow>:
name: "model"
<MainWindow>:
name: "main"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Button:
text: "Select Model"
on_press:
app.root.current = "model"
Button:
text: "Test Model"
Button:
text: "Create New Model"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "second"
Button:
text: "Go Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
My I ask if anyone knows how to make a dropdown list in the next window? should I write it in the kv file or the python itself? Thank youu
If I get your point correctly, you want to initialize the ModelWindow class. In order to do that you can simply call the method window in __init__ with some modifications or define everything directly in __init__ as,
def __init__(self, **kwargs):
super().__init__(**kwargs)
box = BoxLayout(orientation='vertical')
label = Label(text='LABEL')
...
# Same as in your method `window`.
...
self.dropdown.add_widget(btn)
self.add_widget(box)
I am using Kivy to create a GUI.
If I go back to the Kivy operation after I activate another window, the Kivy button operation is ignored once.
This is a video of the operation.
I tried the following code
#-*- coding: utf-8 -*-
from kivy.lang import Builder
Builder.load_string("""
<TextWidget>:
BoxLayout:
orientation: 'vertical'
size: root.size
TextInput:
text: root.text
Button:
id: button1
text: "Test"
font_size: 48
on_press: root.buttonClicked()
""")
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
class TextWidget(Widget):
text = StringProperty()
def __init__(self, **kwargs):
super(TextWidget, self).__init__(**kwargs)
self.text = ''
def buttonClicked(self):
self.text += "test\n"
class TestApp(App):
def __init__(self, **kwargs):
super(TestApp, self).__init__(**kwargs)
self.title = 'greeting'
def build(self):
return TextWidget()
if __name__ == '__main__':
TestApp().run()
Is there a solution to this problem?
I've asked in past questions how to add and remove buttons dynamically.
I want to know how to dynamically delete BoxLayout with Python's Kivy.
Here is my code.
#-*- coding: utf-8 -*-
from kivy.config import Config
from kivy.uix.button import Button
Config.set('graphics', 'width', 300)
Config.set('graphics', 'height', 300)
Config.set('input', 'mouse', 'mouse,multitouch_on_demand') # eliminate annoying circle drawing on right click
from kivy.lang import Builder
Builder.load_string("""
<AddItemWidget>:
BoxLayout:
size: root.size
orientation: 'vertical'
RecycleView:
size_hint: 1.0,1.0
BoxLayout:
id: box
orientation: 'vertical'
Button:
id: addButton
text: "Add Item"
on_press: root.buttonClicked()
""")
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
class RemovableButton(Button):
def on_touch_down(self, touch):
if touch.button == 'right':
if self.collide_point(touch.x, touch.y):
self.parent.remove_widget(self)
return True
return super(RemovableButton, self).on_touch_down(touch)
class AddItemWidget(Widget):
def __init__(self, **kwargs):
super(AddItemWidget, self).__init__(**kwargs)
self.count = 0
def buttonClicked(self):
self.count += 1
boxLayout = BoxLayout()
textinput = TextInput(text='Hello world'+str(self.count),size_hint_x=0.8)
deleteButton = RemovableButton(text='×',size_hint_x=0.2)
boxLayout.add_widget(deleteButton, index=1)
boxLayout.add_widget(textinput, index=1)
self.ids.box.add_widget(boxLayout, index=1)
deleteButton.bind(on_release=boxLayout.remove_widget)
class TestApp(App):
def __init__(self, **kwargs):
super(TestApp, self).__init__(**kwargs)
def build(self):
return AddItemWidget()
if __name__ == '__main__':
TestApp().run()
When the above code is executed, GUI will be launched and a line will be added by pressing the "Add Item" button.
I want to remove the line, so with the "x" button, as in the image below.
Its a little different than your other example.
For this, you need to use a different function to do the removing.
You also have to import partial like this: from functools import partial
And here is the changed AddItemWidget class:
class AddItemWidget(Widget):
def __init__(self, **kwargs):
super(AddItemWidget, self).__init__(**kwargs)
self.count = 0
def buttonClicked(self):
self.count += 1
boxLayout = BoxLayout()
textinput = TextInput(text='Hello world'+str(self.count),size_hint_x=0.8)
deleteButton = RemovableButton(text='×',size_hint_x=0.2)
boxLayout.add_widget(deleteButton, index=1)
boxLayout.add_widget(textinput, index=1)
self.ids.box.add_widget(boxLayout, index=1)
deleteButton.bind(on_release=partial(self.remove_btn, boxLayout)) # change this
def remove_btn(self, boxLayout, *args): # and add this
self.ids.box.remove_widget(boxLayout)
I`m trying to make a simple GUI with Kivy(1.9) using a popup to change some options from a list and save it to a db, for example. When i call popup(), Python(3.4.5) crash..
main.py:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.properties import ListProperty
from kivy.lang import Builder
Builder.load_string('''
<PopView>:
title: 'Popup'
size_hint: (.8, .8)
Button:
text: 'Save'
''')
class MainApp(App):
def build(self):
b = Button(text='click to open popup')
b.bind(on_click=self.view_popup())
return b
def view_popup(self):
a=PopView()
a.data=[1,2,3,4] #e.g.
a.open()
class PopView(Popup):
def __init__(self):
self.data = ListProperty()
def save_data(self):
#db.query(self.data)
pass
if __name__ in ('__main__', '__android__'):
MainApp().run()
Here are a couple of things.
First, if you are going to overite __init__ remember to call super
But in this simple case you dont need __init__
Then, there is no on_click event on Button. Use on_press or on_release
And last but not least: You dont need to call the method in the bind function. Only pass it (without ())
So now your example looks like this.
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.properties import ListProperty
from kivy.lang import Builder
Builder.load_string('''
<PopView>:
title: 'Popup'
size_hint: (.8, .8)
Button:
text: 'Save'
''')
class MainApp(App):
def build(self):
b = Button(text='click to open popup')
b.bind(on_release=self.view_popup)
return b
def view_popup(self,*args):
a = PopView()
a.data=[1,2,3,4] #e.g.
a.open()
class PopView(Popup):
data = ListProperty()
def save_data(self):
#db.query(self.data)
pass
if __name__ in ('__main__', '__android__'):
MainApp().run()
I want to show in a button and a label in a widget at left,center position and right,bottom without using .kv code . Here is my code and i am not able to figure out how to do it Can someone give advice ?
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
class Container(AnchorLayout):
def __init__(self, **kwargs):
super(Container, self).__init__(**kwargs)
btn = Button(text='Hello World',anchor_x='right',anchor_y='bottom')
self.add_widget(btn)
lbl = Label(text="Am i a Label ?",anchor_x='left',anchor_y='center')
self.add_widget(lbl)
class MyJB(App):
def build(self):
parent = Container()
return parent
if __name__ == '__main__':
MyJB().run()
The AnchorLayout aligns all widgets to a given point, not each widget to its own point. If you want widgets anchored in different locations, you need to use multiple AnchorLayouts. You also probably want to specify size and size_hint on either the AnchorLayout or the content widgets.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button
class Container(FloatLayout):
def __init__(self, **kwargs):
super(Container, self).__init__(**kwargs)
anchor_rb = AnchorLayout(anchor_x='right', anchor_y='bottom')
btn = Button(text='Hello World', size=(100, 100), size_hint=(None, None))
anchor_rb.add_widget(btn)
self.add_widget(anchor_rb)
anchor_lc = AnchorLayout(anchor_x='left', anchor_y='center')
lbl = Label(text="Am i a Label ?", size=(100, 100), size_hint=(None, None))
anchor_lc.add_widget(lbl)
self.add_widget(anchor_lc)
class MyJB(App):
def build(self):
parent = Container()
return parent
if __name__ == '__main__':
MyJB().run()
Personally, I find kv to be cleaner than manual widget creation, and it helps provide a definite separation between the UI and behavior.
kv version:
from kivy.app import App
from kivy.lang import Builder
root = Builder.load_string('''
FloatLayout:
AnchorLayout:
anchor_x: 'right'
anchor_y: 'bottom'
Button:
text: 'Hello World'
size: 100, 100
size_hint: None, None
AnchorLayout:
anchor_x: 'left'
anchor_y: 'center'
Label:
text: 'Am i a Label ?'
size: 100, 100
size_hint: None, None
''')
class MyJB(App):
def build(self):
return root
if __name__ == '__main__':
MyJB().run()