Python : How to remove focus from button when click anywhere on window - python

I am using python-2.7 and kivy .When i run test.py then i set focus on button.After that i click anywhere on window using mouse then focus does not remove . Because after click on window i press enter then it call def self.add().
Can someone tell me how to remove focus from button when click anywhere on
window ?
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ObjectProperty
from kivy.clock import Clock
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 150)
class User(Screen):
name = ObjectProperty(None)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
Window.bind(on_key_down=self._on_keyboard_down)
Clock.schedule_once(self.name_focus, 1)
def name_focus(self, *args):
self.postUser.focus = True
self.postUser.background_color = [0.5, 0.5, 0.5, 1]
def _on_keyboard_down(self, instance, keyboard, keycode, text, modifiers):
if (hasattr(self.postUser, 'focus') and self.postUser.focus) and keycode == 40:
self.add()
def add(self):
print('button Event Call')
class Test(App):
def build(self):
return self.root
if __name__ == '__main__':
Test().run()
test.kv
#:kivy 1.10.0
User:
name: name
postUser : postUser
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
padding: 20, 20
spacing: 10, 10
Label:
text: "Name"
text_size: self.size
valign: 'middle'
TextInput:
id:name
text_size: self.size
GridLayout:
cols: 2
padding: 0, 0
spacing: 5, 0
size_hint: .5, .35
pos_hint: {'x': .25, 'y': 0}
Button:
id:postUser
size_hint_x: .5
text: "Ok"
focus: False
on_release:
root.add()

You can add on_touch_up method in your User class.
def on_touch_up(self, touch):
if (hasattr(self.postUser, 'focus') and self.postUser.focus):
self.postUser.focus = False
self.postUser.background_color = [1, 1, 1, 1]
I am posting complete code.
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ObjectProperty
from kivy.clock import Clock
Window.clearcolor = (0.5, 0.5, 0.5, 1)
Window.size = (500, 150)
class User(Screen):
name = ObjectProperty(None)
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
Window.bind(on_key_down=self._on_keyboard_down)
Clock.schedule_once(self.name_focus, 1)
def name_focus(self, *args):
self.postUser.focus = True
self.postUser.background_color = [0.5, 0.5, 0.5, 1]
def _on_keyboard_down(self, instance, keyboard, keycode, text, modifiers):
if (hasattr(self.postUser, 'focus') and self.postUser.focus) and keycode == 40:
self.add()
def add(self):
print('button Event Call')
def on_touch_up(self, touch):
if (hasattr(self.postUser, 'focus') and self.postUser.focus):
self.postUser.focus = False
self.postUser.background_color = [1, 1, 1, 1]
class Test(App):
def build(self):
return self.root
if __name__ == '__main__':
Test().run()
test.kv
#:kivy 1.10.0
User:
name: name
postUser : postUser
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
padding: 20, 20
spacing: 10, 10
Label:
text: "Name"
text_size: self.size
valign: 'middle'
TextInput:
id:name
text_size: self.size
GridLayout:
cols: 2
padding: 0, 0
spacing: 5, 0
size_hint: .5, .35
pos_hint: {'x': .25, 'y': 0}
Button:
id:postUser
size_hint_x: .5
text: "Ok"
focus: False
on_release:
root.add()

Related

Kivy - Calling a pulsing method from one class to another

I have the following classes in my kivy app, and i would like to call the blink method in my mainApp class. The start pulsing and blink methods enable the MainWindow background to pulse. However it's not working inside the MainWindow class and i need to call it in my mainApp class. Commented out (build method in mainApp) is what i tried, which results to the error Exception: Invalid instance in App.root. My python file:
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.core.window import Window
from kivymd.app import MDApp
from kivy.uix.image import Image
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.properties import ColorProperty
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from plyer import filechooser
data = ""
class MainWindow(Screen):
def analyze_data(self):
global data
data = self.ids.user_input.text
data = analyze(data)
animated_color = ColorProperty()
pulse_interval = 4
def blink(self):
x = Clock.schedule_once(self.start_pulsing, 5)
return x
def start_pulsing(self, *args):
d = self.pulse_interval / 2
anim = Animation(animated_color=(69/255, 114/255, 147/255, 1), duration=d) + Animation(animated_color=(1, 1, 1, 1), duration=d)
anim.repeat = True
anim.start(self)
class OutputScreen(Screen):
def on_enter(self, *args):
self.ids.output_label.text = data
class mainApp(MDApp):
def __init__(self):
super().__init__()
def choose_file(self):
try:
filechooser.open_file(on_selection = self.handle_selection)
except:
pass
def handle_selection(self,selection):
global path
selection_ls = selection[0]
path = selection_ls
#print(path)
def change_screen(self,screen):
screemanager = self.root.ids['screenmanager']
screemanager.current = screen
def change(self):
self.change_screen('output')
def back(self):
self.change_screen('main')
'''
def build(self):
x = MainWindow().blink()
return x'''
and my kv file:
#:import utils kivy.utils
GridLayout:
cols:1
ScreenManager:
id: screenmanager
MainWindow:
id: main
name: 'main'
OutputScreen:
id: output
name: 'output'
<MainWindow>:
BoxLayout:
orientation:'vertical'
MDBottomNavigation:
panel_color: utils.get_color_from_hex("#ffffff")
MDBottomNavigationItem:
name:'analytics'
text:'analytics'
icon:'account-circle'
FloatLayout:
size: root.width, root.height
canvas.before:
Color:
rgba: root.animated_color
Rectangle:
pos:self.pos
size:self.size
TextInput:
multiline:True
id: user_input1
pos_hint:{"x" : 0.05, "top" : 0.9}
size_hint: 0.9, 0.37
Label:
markup: True
id:input_label
pos_hint:{"x" : 0, "top":1}
size_hint: 1 ,0.08
font_size : 32
bold: True
canvas.before:
Color:
rgb: utils.get_color_from_hex("01121c")
Rectangle:
size: self.size
pos: self.pos
Button:
pos_hint:{"top" : 0.51, "x" : 0.05}
size_hint: (None,None)
width : 150
height : 40
font_size : 23
text:'Submit'
on_press: root.analyze_data()
on_release: app.change()
Button:
pos_hint:{"top":0.42, "x":0.05}
size_hint: (None,None)
width : 150
height : 40
font_size : 23
text:'Upload'
on_release:app.choose_file()
Button:
id:'info_button'
pos_hint:{"top":0.47, "x":0.8}
size_hint: (None,None)
width : 50
height : 22
font_size : 23
text:'i'
on_release:root.analytics_info()
<OutputScreen>:
ScrollView:
GridLayout:
cols:1
MDIconButton:
icon:'arrow-left'
pos_hint:{'top':1,'left':1}
size_hint: 0.1,0.1
user_font_size : '64sp'
on_release: app.back()
Label:
id: output_label
multiline:True
text_size: self.width, None
size_hint: 1, None
height: self.texture_size[1]
color: 0,0,0,1
padding_x: 15
Any help will be much appreciated.
The build() method of an App should return a Widget that will become the root of the App. But your build() method returns a ClockEvent (the return from Clock.schedule_once()). Try changing your build() method to:
def build(self):
x = MainWindow()
x.blink()
return x
Since you do not call Builder.load_file(), I assume that your kv file is named main.kv, and therefore will get loaded automatically. If that is true, then you do not need a build() method at all. Instead add an on_start() method to your mainApp class, like this:
def on_start(self):
self.root.ids.main.blink()

Kivy Screenmanager Issues -

I am currently struggling with Kivy's screenmanager function. While it works in the menus it just won't show the character. I didn't find any helpful Information in the Documentation.
This works just fine so that class isn't the problem:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
class Character(Widget):
pass
class Basic(Image):
def __init__(self, **kwargs):
super(Basic, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
print('Basic initialised')
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.x -= 10
print('pressed left')
elif keycode[1] == 'right':
self.x += 10
print('pressed right')
elif keycode[1] == 'up':
self.y += 10
print('pressed up')
elif keycode[1] == 'down':
self.y -= 10
print('pressed down')
else:
return False
return True
class HemeApp(App):
def build(self):
wimg = Basic(source='sprite.png')
m = Character()
m.add_widget(wimg)
return m
if __name__ == '__main__':
HemeApp().run()
But when I want to display that on my GameScreen from ScreenManager it's just a Blackscreen.
This is the code:
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.config import Config
from kivy.vector import Vector
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.animation import Animation
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file('heme.kv')
##############################################################################################################################
class HemeApp(App):
title = 'geme'
icon = 'custoicon.png'
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
sm.add_widget(CharacterCreationScreen(name='creationscreen'))
sm.add_widget(GameScreen(name='gameplay'))
return sm
def save(self, plrname):
fob = open('stats.txt', 'w+')
fob.write(plrname + "\n")
fob.close()
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class CharacterCreationScreen(Screen):
pass
class Character(Widget):
pass
class GameScreen(Screen):
def playy(self):
print ('playy fired')
wimg = Basic(source='sprite.png')
m = Character()
m.add_widget(wimg)
return m
def on_enter(self):
print ("on_enter fired")
self.playy()
class MyButton(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
self.source = 'button.png'
def on_press(self):
self.source = 'button_pressed.png'
def on_release(self):
self.source = 'button.png'
class Basic(Image):
def __init__(self, **kwargs):
super(Basic, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
print('Basic initialised')
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
print ('on_keyboard_down active')
if keycode[1] == 'left':
self.x -= 10
elif keycode[1] == 'right':
self.x += 10
else:
return False
return True
if __name__ == '__main__':
HemeApp().run()
Plus the Kivy code:
#; kivy 1.10.0
#:import Factory kivy.factory.Factory
<MenuScreen>:
FloatLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'bg.png'
MyButton:
pos: (330, 400)
allow_stretch: True
background_color: (0,1,0,1)
size_hint: (.2,.2)
text: 'Play'
on_release:
root.manager.transition.direction = 'right'
root.manager.current = 'creationscreen'
Label:
pos: (330, 450)
text: 'Play'
color: (1,0,0)
MyButton:
pos: (330, 300)
size_hint: (.2,.2)
text: 'Goto settings'
on_release:
root.manager.transition.direction = 'right'
root.manager.current = 'settings'
MyButton:
pos: (330, 200)
background_color: (1,0,0,1)
size_hint: (.2,.2)
text: 'Quit'
on_release: exit()
<SettingsScreen>:
FloatLayout:
MyButton:
pos: (330, 400)
size_hint: (.2,.2)
text: 'My settings button'
MyButton:
pos: (330, 300)
size_hint: (.2,.2)
text: 'Back to menu'
on_release:
root.manager.transition.direction = 'left'
root.manager.current = 'menu'
<CharacterCreationScreen>:
name: name_input
FloatLayout:
MyButton:
pos: (330, 400)
name: name_input
size_hint: (.2,.2)
text: 'Start game'
on_release:
root.manager.transition.direction = 'right'
root.manager.current = 'gameplay'
MyButton:
pos: (430, 300)
text: 'Save'
on_release: app.save(name_input.text)
size_hint: (.2,.2)
TextInput:
pos: (230, 300)
id: name_input
font_size: 20
multiline: False
size_hint: (.2,.2)
MyButton:
pos: (330, 200)
size_hint: (.2,.2)
text: 'Back to menu'
on_release:
root.manager.transition.direction = 'left'
root.manager.current = 'menu'
<GameScreen>:
game: game
Character:
id: game
pos: self.pos
Problem
The character was not displayed because no location was given to add the character.
Solution
Replaced return m with self.add_widget(m)
Snippet
class GameScreen(Screen):
def playy(self):
print('playy fired')
wimg = Basic(source='sprite.png')
m = Character()
m.add_widget(wimg)
self.add_widget(m)
Output

How to Change BG Color of Dynamically Created Widget with On_Press and Save with Pickle? (Python with Kivy)

Goal:
Change background color of dynamically created widget with on-press.
Save this state with pickle such that when I open the program back up, the new color change is preserved
Note: You'll see in my code that I haven't made an attempt on saving the button bg color state to a file yet, as I'm still trying to get the on-press event to function.
I get the following error:
File "C:/Users/phili/scrollablelabelexample.py", line 45, in create_button
button_share.bind(on_press = self.update_buttons_departoverride(self))
TypeError: update_buttons_departoverride() takes 1 positional argument but 2 were given
Python code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
from kivy.clock import Clock
import pandas as pd
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
class AnotherScreen(Screen):
pass
class BackHomeWidget(Widget):
pass
class Sequence(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class MainScreen(Screen):
pass
class CleanScreen(BoxLayout):
def __init__(self, **kwargs):
super(CleanScreen, self).__init__(**kwargs)
self.orientation = "vertical"
Clock.schedule_once(lambda *args:self.create_button(self.ids.box_share))
def create_button(self, box_share):
top_button_share = 1.1
color = [.48,.72,.23,1]
for i in range(len(parts)):
top_button_share -= .4
button_share = Button(background_normal = '', background_color = color, id = "part"+str(i+1),pos_hint={"x": 0, "top": top_button_share}, size_hint_y=None, height=60, text=str(i))
button_share.bind(on_press = self.update_buttons_departoverride(self))
box_share.add_widget(button_share)
def update_buttons_departoverride(self):
self.background_color = 1.0, 0.0, 0.0, 1.0
presentation = Builder.load_file("garagemainexample.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
Kv Code:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
Sequence:
<BigButton#Button>:
font_size: 40
size_hint: 0.5, 0.15
color: 0,1,0,1
<SmallNavButton#Button>:
font_size: 32
size: 125, 50
color: 0,1,0,1
<BackHomeWidget>:
SmallNavButton:
on_release: app.root.current = "main"
text: "Home"
pos: root.x, root.top - self.height
<MainScreen>:
name: "main"
FloatLayout:
BigButton:
on_release: app.root.current = "sequence"
text: "Sequence"
pos_hint: {"x":0.25, "top": 0.4}
<CleanScreen>:
ScrollView:
GridLayout:
id: box_share
cols: 1
size_hint_y: None
size_hint_x: 0.5
spacing: 5
padding: 90
height: self.minimum_height
canvas:
Color:
rgb: 0, 0, 0
Rectangle:
pos: self.pos
size: self.size
<Sequence>:
name: "sequence"
CleanScreen:
id: cleanscreen
BackHomeWidget:
With button_share.bind (on_press = self.update_buttons_departoverride (self)) you're calling the method, so you're trying to bind on_press with None (self.update_buttons_departoverride return None). If you want to pass arguments, use lambda or functools.partial:
from functools import partial
button_share.bind(on_press=partial(self.update_buttons_departoverride, arg1,...))
However, if you need to pass only the button's reference, it is already passed automatically. You just have to do:
button_share.bind(on_press=self.update_buttons_departoverride)
and:
def update_buttons_departoverride(self, button):
To store the configuration of your widgets you can use Storage. A simplified example using DictStore:
main.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.clock import Clock
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
from kivy.storage.dictstore import DictStore
class AnotherScreen(Screen):
pass
class BackHomeWidget(Widget):
pass
class Sequence(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class MainScreen(Screen):
pass
class CleanScreen(BoxLayout):
box_share = ObjectProperty()
config_file = DictStore('conf.dat')
def __init__(self, **kwargs):
super(CleanScreen, self).__init__(**kwargs)
self.orientation = "vertical"
Clock.schedule_once(self.create_button)
def create_button(self, *args):
top_button_share = 1.1
color = (.48, .72, .23, 1)
for i in range(5):
top_button_share -= .4
id_ = "part" + str(i + 1)
if self.config_file.exists(id_):
btn_color = self.config_file[id_]["background_color"]
else:
self.config_file.put(id_, background_color=color)
btn_color = color
button_share = Button(background_normal='',
background_color=btn_color,
id=id_,
pos_hint={"x": 0, "top": top_button_share},
size_hint_y=None,
height=60,
text=str(i))
button_share.bind(on_press=self.update_buttons_departoverride)
self.box_share.add_widget(button_share)
def update_buttons_departoverride(self, button):
button.background_color = 1.0, 0.0, 0.0, 1.0
self.config_file.put(button.id, background_color=(1.0, 0.0, 0.0, 1.0))
presentation = Builder.load_file("garagemainexample.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
garagemainexample.kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
Sequence:
<BigButton#Button>:
font_size: 40
size_hint: 0.5, 0.15
color: 0,1,0,1
<SmallNavButton#Button>:
font_size: 32
size: 125, 50
color: 0,1,0,1
<BackHomeWidget>:
SmallNavButton:
on_release: app.root.current = "main"
text: "Home"
pos: root.x, root.top - self.height
<MainScreen>:
name: "main"
FloatLayout:
BigButton:
on_release: app.root.current = "sequence"
text: "Sequence"
pos_hint: {"x":0.25, "top": 0.4}
<CleanScreen>:
box_share: box_share
ScrollView:
GridLayout:
id: box_share
cols: 1
size_hint_y: None
size_hint_x: 0.5
spacing: 5
padding: 90
height: self.minimum_height
canvas:
Color:
rgb: 0, 0, 0
Rectangle:
pos: self.pos
size: self.size
<Sequence>:
name: "sequence"
CleanScreen:
id: cleanscreen
BackHomeWidget:

Kivy/python : How to check checkbox from a .py file

I have written some code in Python (test.py) and kivy (test.kv).
When I run test.py then male checkbox shows checked and female checkbox unchecked because I am using in test.kv file:
active: root.male
But I want the same thing from a .py file. How to checked male checkbox from a .py file?
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import ObjectProperty
Window.size = (600, 325)
class UserGroup(Screen):
male = ObjectProperty(None)
female = ObjectProperty(None)
age = ObjectProperty(None)
def insert_data(self):
print('')
class FactUserGroup(App):
def build(self):
self.root = Builder.load_file('test.kv')
return self.root
if __name__ == '__main__':
FactUserGroup().run()
test.kv
<CustomLabel#Label>:
text_size: self.size
valign: "middle"
padding_x: 5
<SingleLineTextInput#TextInput>:
multiline: False
<GreenButton#Button>:
background_color: 1, 1, 1, 1
size_hint_y: None
height: self.parent.height * 0.120
UserGroup
male: chk_male
female: chk_female
GridLayout:
cols: 2
padding : 30,30
spacing: 20, 20
row_default_height: '30dp'
Label:
text: 'Male'
text_size: self.size
valign: 'middle'
CheckBox:
group: 'check'
id : chk_male
active: root.male
Label:
text: 'Female'
text_size: self.size
valign: 'middle'
CheckBox:
group: 'check'
id: chk_female
GreenButton:
text: 'Ok'
GreenButton:
text: 'Cancel'
on_press: app.stop()
Can someone help me?
The solution is to use BooleanProperty, and add active: root.female. In the example it illustrates when the Kivy app is running the checkbox for female is active (Figure 1), after 5 seconds, it will automatically switch to the checkbox for male (Figure 2) using Clock.schedule_once.
test.py
from kivy.properties import ObjectProperty, BooleanProperty
...
class UserGroup(Screen):
male = BooleanProperty(False)
female = BooleanProperty(True)
test.kv
CheckBox:
group: 'check'
id: chk_female
active: root.female
Example
test.py
from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import ObjectProperty, BooleanProperty
from kivy.clock import Clock
Window.size = (600, 325)
class UserGroup(Screen):
male = BooleanProperty(False)
female = BooleanProperty(True)
age = ObjectProperty(None)
def __init__(self, **kwargs):
super(UserGroup, self).__init__(**kwargs)
Clock.schedule_once(self.switch_checkbox, 5)
def switch_checkbox(self, dt):
self.female = False
self.male = True
def insert_data(self):
print('')
class FactUserGroup(App):
def build(self):
self.root = Builder.load_file('test.kv')
return self.root
if __name__ == '__main__':
FactUserGroup().run()
test.kv
#:kivy 1.10.0
<CustomLabel#Label>:
text_size: self.size
valign: "middle"
padding_x: 5
<SingleLineTextInput#TextInput>:
multiline: False
<GreenButton#Button>:
background_color: 1, 1, 1, 1
size_hint_y: None
height: self.parent.height * 0.120
UserGroup:
GridLayout:
cols: 2
padding : 30,30
spacing: 20, 20
row_default_height: '30dp'
Label:
text: 'Male'
text_size: self.size
valign: 'middle'
CheckBox:
group: 'check'
id : chk_male
active: root.male
Label:
text: 'Female'
text_size: self.size
valign: 'middle'
CheckBox:
group: 'check'
id: chk_female
active: root.female
GreenButton:
text: 'Ok'
GreenButton:
text: 'Cancel'
on_press: app.stop()
Output

Kivy Python TextInput display Bubble

I am trying to display numeric keyboard in bubble for TextInput in Kivy. Is it possible?
So far I have:
Builder.load_string('''
<NumericKeyboard>
size_hint: (None, None)
size: (160, 120)
pos_hint: {'center_x': .5, 'y': .6}
BubbleButton:
text: 'Cut'
BubbleButton:
text: 'Copy'
BubbleButton:
text: 'Paste'
''')
class NumericKeyboard(Bubble):
pass
class CustomTextInput(TextInput):
def __init__(self, **kwargs):
super(CustomTextInput, self).__init__(**kwargs)
def on_focus(self, instance, value):
self.bubb = NumericKeyboard()
self.add_widget(self.bubb)
But the bubble will not display.
Yes, it is possible to display numeric key pad using Kivy Bubble for TextInput widget. Please refer to the example below for details.
Note: The text input is not filtered.
Example
main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.bubble import Bubble, BubbleButton
from kivy.uix.label import Label
from kivy.properties import ObjectProperty
from kivy.lang import Builder
class CustomBubbleButton(BubbleButton):
pass
class NumericKeyboard(Bubble):
layout = ObjectProperty(None)
def __init__(self, **kwargs):
super(NumericKeyboard, self).__init__(**kwargs)
self.create_bubble_button()
def create_bubble_button(self):
numeric_keypad = ['7', '8', '9', '4', '5', '6', '1', '2', '3', '', '0', '.']
for x in numeric_keypad:
if len(x) == 0:
self.layout.add_widget(Label(text=""))
else:
bubb_btn = CustomBubbleButton(text=str(x))
self.layout.add_widget(bubb_btn)
class BubbleShowcase(FloatLayout):
text_input = ObjectProperty(None)
def show_bubble(self, *l):
if not hasattr(self, 'bubb'):
self.bubb = bubb = NumericKeyboard()
self.bubb.arrow_pos = "bottom_mid"
self.add_widget(bubb)
Builder.load_file("test.kv")
class TestBubbleApp(App):
title = "Numeric Key Pad - Using Bubble"
def build(self):
return BubbleShowcase()
if __name__ == '__main__':
TestBubbleApp().run()
test.kv
#:kivy 1.10.0
<CustomBubbleButton>:
on_release:
app.root.text_input.text += self.text
<NumericKeyboard>:
layout: layout
size_hint: (None, None)
size: (160, 120)
pos_hint: {'center_x': .5, 'y': .6}
GridLayout:
id: layout
cols: 3
<BubbleShowcase>:
text_input: text_input
canvas:
Color:
rgba: 0, 1, 1, 1
Rectangle:
size: self.width, self.height
TextInput:
id: text_input
pos_hint: {'center_x': .5, 'y': .54}
size_hint: (0.2, 0.06)
cursor_blink: True
font_size: 20
multiline: False
on_focus:
root.show_bubble()
Output
thank you #ikolim code and explain, I made some improvements and share with you。
Replaced the picture background which kivy provide
canvas and padding Specified,to make a rounded rectangle Appearance
Remember: customer widgets add in Bubble Widget, Bubble Widget must add in FloatLayout
code is running in win10-64,kivy2.0.0,py366(If there is a problem, please make a small modification)bubble_arrow_up.png
Show resultsbubble_down.png
delete.png
mycalculate.py
# !/usr/bin/env python
# -*- coding: utf-8 -*-
from functools import partial
from kivy.app import App
from kivy.core.window import Window
from kivy.core.text import LabelBase
from kivy.uix.bubble import Bubble, BubbleButton
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
class NumBubbleButton(BubbleButton):
pass
class Calculate(Bubble):
content = ObjectProperty("")
def __init__(self, **kwargs):
super(Calculate, self).__init__(**kwargs)
self.create_keyboard()
def create_keyboard(self):
num_key = ['7', '8', '9', '4', '5', '6', '1', '2', '3', ' ', '0', '⌫']
for x in num_key:
btn = NumBubbleButton(text=str(x))
btn.bind(on_press=partial(self.add_text, str(x)))
if x == " ":
btn.disabled = True
btn.background_disabled_normal = ""
elif x == "⌫":
btn.text = ""
btn.background_normal = "delete.png"
self.ids.calculator.add_widget(btn)
#staticmethod
def add_text(text, *args):
print(text)
class Cale(BoxLayout):
def __init__(self, **kwargs):
super(Cale, self).__init__(**kwargs)
self.cale = Calculate()
self.cale.width, self.cale.height = 200, 400
self.ids.float_grid.add_widget(self.cale)
class MyCalculateApp(App):
def __init__(self, **kwargs):
super(MyCalculateApp, self).__init__(**kwargs)
def build(self):
# Window.fullscreen = False
# Window.left, Window.top, Window.size = 10, 0, (300, 500)
return Cale()
if __name__ == "__main__":
MyCalculateApp().run()
mycalculate.kv
<NumBubbleButton>:
background_normal: ""
background_color: 1, 1, 1, 1
color: 0, 0, 0, 1
bold: True
font_size: "48px"
<Calculate>:
size_hint: None, None
orientation: "vertical"
arrow_image: "bubble_arrow_up.png"
background_image: "bubble_down.png"
arrow_pos: "top_mid"
BoxLayout:
padding: 5, 5, 5, 0
size_hint: 1, 1
GridLayout:
id: calculator
canvas:
Color:
rgba: 232/255, 232/255, 232/255, 1
Rectangle:
pos: self.pos
size: self.size
spacing: 2
rows: 5
cols: 3
BoxLayout:
size_hint: 1, 0.2
padding: 5
canvas.before:
Color:
rgba: 199/255, 31/255, 58/255, 1
RoundedRectangle:
pos: self.pos
size: self.size
radius: [0, 0, 10, 10]
Button:
background_normal: ""
background_color: 199/255, 31/255, 58/255, 1
font_size: "32px"
text: t.t("Confirm")
markup: True
on_press: print("Confirm")
<Cale>:
FloatLayout:
id: float_grid
GridLayout:
id: grid_goods
You cannot add a widget to a text input because it is not a layout. You should add your text input to a layout then add your bubble to this layout. Try this:
from kivy.app import App
from kivy.uix.bubble import Bubble
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
Builder.load_string('''
<NumericKeyboard>
size_hint: (None, None)
size: (160, 120)
pos_hint: {'center_x': .5, 'y': .6}
BubbleButton:
text: 'Cut'
BubbleButton:
text: 'Copy'
BubbleButton:
text: 'Paste'
''')
class NumericKeyboard(Bubble):
pass
class CustomTextInputLayout(FloatLayout):
def __init__(self, **kwargs):
super(CustomTextInputLayout, self).__init__(**kwargs)
self.add_widget(CustomTextInput(self))
class CustomTextInput(TextInput):
def __init__(self, layout,**kwargs):
super(CustomTextInput, self).__init__(**kwargs)
self.layout = layout
def on_focus(self, instance, value):
self.bubb = NumericKeyboard()
self.layout.add_widget(self.bubb)
class MyTestApp(App):
def build(self):
return CustomTextInputLayout()
if __name__ == '__main__':
MyTestApp().run()

Categories