I am trying to add Numeric Keyboard in UI
Which will be display as clicked on the text on filed
But some how Numeric keyboard not show in the UI
I use numeric.json file to open the numeric keyboard as per the kivy Documentation json file
and link is [https://github.com/kivy/kivy/blob/master/examples/keyboard/numeric.json]
here is my code below
enter code here
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.screenmanager import ScreenManager
from kivy.core.window import Window
KV= '''
<REGITRATION_Window>:
name:'regitration_window1'
RelativeLayout:
MDToolbar:
title: 'Registraion'
elevation: 10
left_action_items: [['arrow-left']]
pos_hint: {"left":1, "top":1}
MDLabel:
text: 'Country Code '
font_size: 15
pos_hint : {'x':0.0322, 'y':0.272}
MDTextFieldRound:
int_text: 'For Eg:- +91'
pos_hint : {'x':0.0322, 'y':0.710}
size_hint : 0.08, .045
on_text: app.setup_key()
MDLabel:
text: 'Mobile Number'
font_size: 15
pos_hint : {'x':0.305, 'y':0.272}
MDTextFieldRound:
hint_text: 'For Eg:- 987654321'
pos_hint :{'x':0.305, 'y':0.710}
size_hint : 0.35, .045
MDFillRoundFlatButton:
text:'REGISTER'
pos_hint: {'x':.1, 'y':.1}
MDFillRoundFlatButton:
text:'Cancel'
pos_hint: {'x':.3, 'y':.1}
RelativeLayout:
id: data_layout
WindowManager:
REGITRATION_Window:
id: key_num
'''
class REGITRATION_Window(MDScreen):
pass
class WindowManager(ScreenManager):
pass
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
def close_key(self):
pass
def setup_key(self):
NumKB = Window.request_keyboard(self.close_key, self)
if NumKB.widget:
NumKB.widget.layout = 'numeric.json'
self.root.ids.key_num.ids.data_layout.add_widget(self.NumKB)
if __name__ == '__main__':
MainApp().run()
Well I took a look at your code and the Vkeyboard implementation on kivy github repo, it was a little complicated. but i came up with something. it was a little tricky but this should work.
I had to modify the numeric.json file a little so, here's my link to it and my github repo: numeric.json
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.vkeyboard import VKeyboard
from kivy.core.window import Window
from kivy.properties import ObjectProperty
KV = '''
<NumericKeyboardScreen>:
name: 'numeric_screen'
RelativeLayout:
MDToolbar:
title: 'Numeric Keyboard Implementation'
elevation: 10
y: self.parent.height - self.height
MDLabel:
text: 'Number TextField'
font_size: 15
y: self.parent.height - self.height - dp(90)
pos_hint :{'center_x':0.5}
halign: 'center'
size_hint_y: None
height: dp(20)
MDTextField:
id: text_field
hint_text: 'For Eg:- 987654321'
y: self.parent.height - self.height - dp(135)
pos_hint :{'center_x':0.5}
size_hint_x : 0.35
mode: 'rectangle'
input_filter: 'int'
on_focus: root.set_layout(keyboard_anchor, self)
RelativeLayout:
id: keyboard_anchor
size_hint_y: 0.5
WindowManager:
NumericKeyboardScreen:
id: key_num
'''
class WindowManager(ScreenManager):
pass
class NumericKeyboardScreen(MDScreen):
focus_count = 0
def set_layout(self, keyboard_anchor, target_textfield):
self.focus_count += 1
v_keyboard = NumericKeyboard(
text_field = target_textfield
)
keyboard_anchor.clear_widgets()
keyboard_anchor.add_widget(v_keyboard)
if self.focus_count == 2:
keyboard_anchor.clear_widgets()
self.focus_count = 0
class NumericKeyboard(VKeyboard):
text_field = ObjectProperty()
custom_vk_layout = ObjectProperty('numeric.json')
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.available_layouts['numpad'] = self.custom_vk_layout
self.layout = self.custom_vk_layout
self.pos_hint = {'center_x': 0.5}
def on_key_down(self, keyboard, keycode, text, *args):
""" The callback function that catches keyboard events. """
if isinstance(keycode, tuple):
keycode = keycode[1]
if keycode == "bs":
if len(textfield_data) > 0:
self.text_field.text = textfield_data[:-1]
else:
self.text_field.text += u"{0}".format(keycode)
def on_key_up(self, keyboard, keycode, *args):
""" The callback function that catches keyboard events. """
textfield_data = self.text_field.text
if isinstance(keycode, tuple):
keycode = keycode[1]
if keycode == "bs":
if len(textfield_data) > 0:
self.text_field.text = textfield_data[:-1]
else:
self.text_field.text += u"{0}".format(keycode)
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
if __name__ == '__main__':
MainApp().run()
Related
I have a case where I need 2 Kivy windows each on a separate monitor to display keyboard press events simultaneously. I have a simple toy example of the code for 'app1.py' and 'app2.py' below.
I was able to successfully use 'subprocess' and kivy.config so that when you press the 'Press to open second window' button in my main application (i.e., app1) a second window (i.e., app2) opens on my second monitor. However, I am stuck on to how I can simultaneously display keyboard events to both application windows when the spacebar is pressed.
Any ideas on how this can be achieved, is it even possible in Kivy?
Best,
Tom
File name: app1.py
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.properties import StringProperty
from subprocess import Popen
Window.size = (1920, 1080)
Window.borderless = True
Builder.load_string('''
<FirstWindow>:
id: _FirstWindow
FloatLayout:
Label:
text: "First Window"
size_hint: None, None
font_size: 50
pos: (900,940)
Label:
text: _FirstWindow.key_down
size_hint: None, None
font_size: 30
pos: (900,800)
Button:
text: "Press to open second window"
size_hint: None, None
font_size: 30
size: (450, 60)
pos: (720, 600)
on_press: root.OpenSecondWindow()
''')
class FirstWindow(FloatLayout):
key_down = StringProperty() # perform button state
def __init__(self, **kwargs):
super(FirstWindow, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
self._keyboard.bind(on_key_down=self.on_keyboard_down, on_key_up=self.on_keyboard_up)
def OpenSecondWindow(self):
p = Popen(['python ./app2.py'], shell=True)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'spacebar':
self.key_down = 'spacebar pressed!'
def on_keyboard_up(self, keyboard, keycode):
if keycode[1] == 'spacebar':
self.key_down = ''
class App1(App):
def build(self):
return FirstWindow()
if __name__ == '__main__':
App1().run()
File name: app2.py
from kivy.config import Config
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'position', 'custom')
Config.set('graphics', 'top', '-900')
Config.set('graphics', 'left', '0')
Config.set('graphics', 'borderless', '1')
Config.set('graphics', 'fullscreen', 'auto')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
from kivy.lang import Builder
Window.size = (1920, 1080)
Window.borderless = True
Builder.load_string('''
<SecondWindow>:
id: _SecondWindow
FloatLayout:
Label:
text: "Second Window"
size_hint: None, None
font_size: 50
pos: (900,940)
Label:
text: _SecondWindow.key_down
size_hint: None, None
font_size: 30
pos: (900,800)
''')
class SecondWindow(FloatLayout):
key_down = StringProperty() # perform button state
def __init__(self, **kwargs):
super(SecondWindow, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
self._keyboard.bind(on_key_down=self.on_keyboard_down, on_key_up=self.on_keyboard_up)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'spacebar':
self.key_down = 'spacebar pressed!'
def on_keyboard_up(self, keyboard, keycode):
if keycode[1] == 'spacebar':
self.key_down = ''
class App2(App):
def build(self):
return SecondWindow()
if __name__ == '__main__':
App2().run()
From app1, you can write to the stdin of app2. Here are the changes to make that happen. In your OpenSecondWindow() method add stdin=PIPE and save a reference to the Popen object:
def OpenSecondWindow(self):
self.p = Popen(['python3 ./app2.py'], shell=True, stdin=PIPE, universal_newlines=True)
Then, in your on_keyboard_down() method, write to the stdin of app2:
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'spacebar':
self.key_down = 'spacebar pressed!'
self.p.stdin.write('spacebar pressed\n')
self.p.stdin.flush()
And in your app2, you must listen for input on stdin. Add this code to your SecondWindow:
def __init__(self, **kwargs):
super(SecondWindow, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
self._keyboard.bind(on_key_down=self.on_keyboard_down, on_key_up=self.on_keyboard_up)
Thread(target=self.listen_for_input).start()
def listen_for_input(self):
while True:
data = input()
self.set_label(data)
#mainthread
def set_label(self, data):
self.ids.label.text = data
And the above requires an id in the kv for app2:
Label:
id: label
And you can add stdout=PIPE to the Popen, and use a similar construct to allow communication in the opposite direction.
I am working on the same issue from my previous post. Now I added screen manager, and I can switch to different pages.
why is my kivy program not calling the function from another class?
I am still confused about OOP with GUIs, however I tried the following, and none of them worked.
I tried to add an instance of Screen 1() in the main app(), and it did nothing. Then, I tried to add the contractor method init into Screen_1() and it says I don't have a build method. And few other ideas that didn't work at all.
Then I realized that there is no link between Screen_Manager() and Screen_1() because all of my methods are in Screen_1(), but the build method is returning Screen_Manager(). On my kv file, there is this code:
<Screen_Manager>:
Screen_1:
Screen_2:
isn't this is where the program "links" between the Screen_Manager() class to other classes?
if someone can help me understand what I am not understanding and help me correct my problem, it would help me to learn about kivy. I understand, <> is like apply to rules, which has 2 widgets screen 1 and screen 2, and also have their own rules.
here is my main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.lang.builder import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.modules import keybinding
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
class Screen_Manager(ScreenManager):
pass
class Screen_1(Screen):
main_display = ObjectProperty()
text_input = ObjectProperty()
def plus_1(self):
self.value = int(self.main_display.text)
self.main_display.text = str(self.value + 1)
def minus_1(self):
self.value = int(self.main_display.text)
self.main_display.text = str(self.value - 1)
def up(self):
self.main_display.text = self.text_input.text
self.text_input.text = ''
class Keyboard(Widget):
def __init__(self, instance):
super().__init__()
self.a = instance
self.keyboard = Window.request_keyboard(None, self)
self.keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'enter':
self.a.up()
return True
class Screen_2(Screen):
pass
class MainApp(App):
def build(self):
self.title = "Number Control App"
self.sm = Screen_Manager()
key = Keyboard(self.sm)
return self.sm
if __name__=="__main__":
MainApp().run()
my kv file
<Screen_Manager>:
Screen_1:
Screen_2:
<Screen_1>:
name: "first"
main_display: display_1
text_input: text_input_1
#------inherenting from BoxLayout
BoxLayout:
orientation: "vertical"
#------begining of conent--
BoxLayout:
size_hint_y: 1
#-nexted content------
Label:
id: display_1
text: "0"
font_size: "150sp"
background_color: 0.1, 0.5, 0.6,
#--------
BoxLayout:
size_hint_y: .35
orientation: "horizontal"
#-nexted content------
Button:
text: "-"
font_size : "60sp"
on_press: root.minus_1()
#-nexted content------
Button:
text: "+"
font_size : "35sp"
background_color: (0, 1, 0, 1)
on_press: root.plus_1()
#--------
BoxLayout:
size_hint_y: .15
orientation: "horizontal"
#-nexted content-------
Button:
text: "Config"
size_hint_x: .25
on_release:
root.manager.current = "second"
root.manager.transition.direction = "left"
#-nexted content-------
TextInput:
id: text_input_1
size_hint_x: 1
hint_text: "Enter your initial # here"
multiline: False
#-nexted content-------
Button:
text: "Up"
size_hint_x: .25
on_press: root.up()
<Screen_2>:
name: "second"
Button:
text: "Go Back"
on_press:
app.root.current = "first"
root.manager.transition.direction = "right"enter code here
thanks again for taking the time to help.
Not sure I understand your question, but pressing Enter in your TextInput executed your code:
self.a.up()
but a in your KeyBoard is the Screen_Manager as set at the line:
self.sm = Screen_Manager()
key = Keyboard(self.sm)
and Screen_Manager has no up method. You can fix that by changing the code in your KeyBoard code to:
self.a.current_screen.up()
Note that this will only work when the current screen is Screen_1.
Am working on a Project that has a RecycleView that contains details of patients.My aim is that when i click on a specific patient on the recycleView row, it should take me to specific dynamic page layout containing specific details of the selected patient in the RecycleView without using the Screen Manager, the switching of dynamic pages.how can i go about this?
i have created a method called change_dynamic_Layout() for switching dynamic pages and it works fine when using the normal button to call it. I have used a print statement in the method to show if the method is executed or not. But when i use the SelectableButton,the print statement is executed but the statement for changing page-layout is not. No errors is shown and the dynamic page does not change. Here is the code try to run it and see what am talking about?
Demo.py
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, ListProperty,
NumericProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.graphics import Color, Rectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.factory import Factory
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
lost = Builder.load_file('Demo.kv')
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
#selectablebutton to call the change_dynamic_Layout() method in patient class
def on_enter(self):
layout=Patient()
layout.change_dynamic_Layout()
class victor(BoxLayout):
pass
class Patient(Screen):
manage_prescription: ObjectProperty(None)
#Method to change the dynamic pagelayout
def change_dynamic_Layout(self):
layout = Factory.victor()
self.manage_prescription.clear_widgets()
self.manage_prescription.add_widget(layout)
print ('pressed')
class DemoApp(App):
title = 'Hospital Management System'
def build(self):
n= Patient()
return n
if __name__ == "__main__":
DemoApp().run()
demo.kv
<Patient>:
manage_prescription:manage_prescription
BoxLayout:
GridLayout :
cols:1
BoxLayout:
id:manage_prescription
orientation:'vertical'
BoxLayout:
size_hint_y:None
height:40
Button:
text:"NO."
font_size: 25
Button:
text:"Date"
font_size: 25
Button:
text:"Patient"
font_size: 25
Button:
text:"Doctor"
font_size: 25
on_press: root.change_dynamic_Layout()
BoxLayout:
RecycleView:
bar_width: 10
bar_color: 1, 0, 0, 1 # red
bar_inactive_color: 0, 0, 1, 1 # blue
#effect_cls: "ScrollEffect"
scroll_type: ['bars']
viewclass: 'SelectableButton'
data:[{'text': str(x)} for x in range(20)]
SelectableRecycleGridLayout:
cols:4
default_size: None, dp(56)
default_size_hint:1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
<victor>:
Label:
text:" Switched to specific page for patient's details"
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
on_press: root.on_enter()
Any insight or help is much appreciated, thanks in advance.
The problem is that your on_enter method of the SelectableButton is creating a new Patient layout (Screen), and calling the change_dynamic_Layout method of that new Patient Screen. That newly created Patient Screen is not the one displayed in your app, so it has no effect on what you see. You actually want to call change_dynamic_Layout on the displayed Patient Screen. One way of doing this is to access it via App.get_running_app().root. So that your on_enter method can be changed to:
def on_enter(self):
#layout=Patient()
layout = App.get_running_app().root
layout.change_dynamic_Layout()
Here is the entire python file:
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, ListProperty, NumericProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.graphics import Color, Rectangle
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.factory import Factory
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
lost = Builder.load_file('Demo.kv')
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
#selectablebutton to call the change_dynamic_Layout() method in patient class
def on_enter(self):
#layout=Patient()
layout = App.get_running_app().root
layout.change_dynamic_Layout()
class victor(BoxLayout):
pass
class Patient(Screen):
manage_prescription: ObjectProperty(None)
#Method to change the dynamic pagelayout
def change_dynamic_Layout(self):
layout = Factory.victor()
self.manage_prescription.clear_widgets()
self.manage_prescription.add_widget(layout)
print ('pressed')
class DemoApp(App):
title = 'Hospital Management System'
def build(self):
n= Patient()
return n
if __name__ == "__main__":
DemoApp().run()
And here is the Demo.kv:
<Patient>:
manage_prescription:manage_prescription
BoxLayout:
GridLayout :
cols:1
BoxLayout:
id:manage_prescription
orientation:'vertical'
BoxLayout:
size_hint_y:None
height:40
Button:
text:"NO."
font_size: 25
Button:
text:"Date"
font_size: 25
Button:
text:"Patient"
font_size: 25
Button:
text:"Doctor"
font_size: 25
on_press: root.change_dynamic_Layout()
BoxLayout:
RecycleView:
bar_width: 10
bar_color: 1, 0, 0, 1 # red
bar_inactive_color: 0, 0, 1, 1 # blue
#effect_cls: "ScrollEffect"
scroll_type: ['bars']
viewclass: 'SelectableButton'
data:[{'text': str(x)} for x in range(20)]
SelectableRecycleGridLayout:
cols:4
default_size: None, dp(56)
default_size_hint:1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
<victor>:
Label:
text:" Switched to specific page for patient's details"
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (1, 1, 1, 1)
Rectangle:
pos: self.pos
size: self.size
on_press: root.on_enter()
So, I'm new to kivy and can't get this code to work. I'm trying to update a button text with a popup text input. The popup shows when the button is pressed, and when it's dismissed it should update the text on the button with whatever text was typed in it.
I've tried many variations of this code, but no one have worked. Either nothing happens or I get this error:
AttributeError: 'super' object has no attribute '__getattr__'
Here it is:
main.py
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.popup import Popup
class MainWidget(GridLayout):
pass
class PopText(Popup):
def textChange(self):
MyButton().change()
def getText(self):
text = self.display
return text
class MyButton(AnchorLayout):
def change(self):
self.ids.equip_bt.text = PopText().getText()
print(self.ids.my_bt.text)
class MyApp(App):
def build(self):
return MainWidget()
if __name__ == "__main__":
MyApp().run()
my.kv
#:kivy 1.10.0
#:import F kivy.factory.Factory
<PopText>:
size_hint: .7, .3
title: "Input Text"
on_dismiss: self.textChange()
display: pop_text.text
TextInput:
id: pop_text
focus: True
multiline: False
on_text_validate: root.dismiss()
<MyButton>:
anchor_y: "top"
anchor_x: "right"
Button:
id: my_bt
text: "Input Text"
on_release: F.PopText().open()
<MainWidget>:
cols: 1
rows: 2
MyButton:
MyButton:
Any ideas on how to solve this?
Here is a minimum example of what you are trying to achieve. The hard part is connection the button from the Popup to the Button which opened it. I am going through the app class to achieve that. I got to admit it is not a pretty solution.
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
class PopupBttn(Button):
def openPopup(self):
Pop = TextPopup().open(self.text)
class TextPopup(Popup):
def open(self, text, **kwargs):
super(TextPopup, self).open(**kwargs)
self.ids.txtipt.text = text
class MyApp(App):
pass
if __name__ == "__main__":
MyApp().run()
kv file:
BoxLayout:
PopupBttn:
id: bttn
text: 'open Popup'
on_press: self.openPopup()
<TextPopup>:
BoxLayout:
orientation: "vertical"
TextInput:
id: txtipt
Button:
text: "OK"
on_release: app.root.ids.bttn.text=root.ids.txtipt.text
on_release: root.dismiss()
Here is an updated version to use multiple buttons. Unfortunately, you will need to set ids and name to the string of id per Button.
python file
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.properties import StringProperty
class PopupBttn(Button):
def openPopup(self):
print(self.name)
Pop = TextPopup().open(self.text, self.name)
class TextPopup(Popup):
bttnid = StringProperty()
text = StringProperty()
def open(self, text, id, **kwargs):
super(TextPopup, self).open(**kwargs)
self.ids.txtipt.text = text
self.bttnid = id
def setText(self):
App.get_running_app().root.ids[self.bttnid].text = self.text
class MyApp(App):
pass
if __name__ == "__main__":
MyApp().run()
kv file
BoxLayout:
orientation: 'vertical'
PopupBttn:
name: 'one'
id: one
text: 'I am the first Button'
PopupBttn:
name: 'two'
id: two
PopupBttn:
name: 'three'
id: three
PopupBttn:
name: 'four'
id: four
text: 'I am the fourth button'
<PopupBttn>:
text: 'open Popup'
on_press: self.openPopup()
<TextPopup>:
text: txtipt.text
BoxLayout:
orientation: "vertical"
TextInput:
id: txtipt
Button:
text: "OK"
on_release: root.setText()
on_release: root.dismiss()
In order to update both buttons, you need to assign unique id to each of them. Please refer to the example below for details.
Example
main.py
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
class MainWidget(GridLayout):
btn_top = ObjectProperty()
btn_bottom = ObjectProperty()
class PopText(Popup):
pass
class MyButton(AnchorLayout):
my_btn = ObjectProperty()
class TestApp(App):
title = "Changing button text with popup text input Kivy"
def build(self):
return MainWidget()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
#:import F kivy.factory.Factory
<PopText>:
size_hint: .7, .3
title: "Input Text"
TextInput:
focus: True
multiline: False
on_text_validate:
app.root.btn_top.my_btn.text = self.text
app.root.btn_bottom.my_btn.text = self.text
root.dismiss()
<MyButton>:
my_btn: my_bt
anchor_y: "top"
anchor_x: "right"
Button:
id: my_bt
text: "Input Text"
on_release: F.PopText().open()
<MainWidget>:
btn_top: btn_top
btn_bottom: btn_bottom
cols: 1
rows: 2
MyButton:
id: btn_top
MyButton:
id: btn_bottom
Output
I am trying to make a listview in which the selected buttons produce a popup with different information depending on which list button was selected. Any suggestions? Thank you
ListView has been deprecated since Kivy version 1.10.0. In the example below, we are using Recycleview.
Example
main.py
from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.properties import ListProperty, StringProperty, ObjectProperty
class MessageBox(Popup):
def popup_dismiss(self):
self.dismiss()
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior, RecycleBoxLayout):
""" Adds selection and focus behaviour to the view. """
selected_value = StringProperty('')
btn_info = ListProperty(['Button 0 Text', 'Button 1 Text', 'Button 2 Text'])
class SelectableButton(RecycleDataViewBehavior, Button):
""" Add selection support to the Label """
index = None
def refresh_view_attrs(self, rv, index, data):
""" Catch and handle the view changes """
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_press(self):
self.parent.selected_value = 'Selected: {}'.format(self.parent.btn_info[int(self.id)])
def on_release(self):
MessageBox().open()
class RV(RecycleView):
rv_layout = ObjectProperty(None)
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.data = [{'text': "Button " + str(x), 'id': str(x)} for x in range(3)]
class TestApp(App):
title = "RecycleView Button Popup Demo"
def build(self):
return RV()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
<MessageBox>:
title: 'Popup Message Box'
size_hint: None, None
size: 400, 400
BoxLayout:
orientation: 'vertical'
Label:
text: app.root.rv_layout.selected_value
Button:
size_hint: 1, 0.2
text: 'OK'
on_press:
root.dismiss()
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (0.0, 0.9, 0.1, 0.3)
Rectangle:
pos: self.pos
size: self.size
<RV>:
rv_layout: layout
viewclass: 'SelectableButton'
SelectableRecycleBoxLayout:
id: layout
default_size: None, dp(56)
default_size_hint: 0.1, None
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
Output