the code in question
txt = TextInput(text='%s'%default, multiline=False, size_hint=(0.5,1))
txt.font_name = gAssets + "FreeSans.ttf"
Txt.font_size = 14
If I comment out the font_name attribute the text in the input lines up about right. (still sits a little bit high in the box but workable)
(using the normal TextInput with the default font (DroidSans.ttf))
However once I uncomment the line that sets it to FreeSans.ttf (larger character set) It now sits way to high in the text field
(using normal TextInput with FreeSans.ttf)
I am using kivy 1.3 and have been unsuccessful at getting the padding attribute to work(however I would be happy to use it if someone could demonstrate how to use it with a TextInput.)
You can alter padding inside your code using VariableListPropery. Example:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.properties import VariableListProperty
class MyTextInput(TextInput):
padding = VariableListProperty(['24dp', '48dp'])
class MyApp(App):
def build(self):
return MyTextInput(text='This is an example text', multiline=False)
if __name__ == '__main__':
MyApp().run()
This code requires 1.7 version, as noted in documentation of the widget. I recommend uprgrading as I don't even see any API archive anywhere to check how it was setted before.
Related
I have a kivy app with some textinput and I want to show in my smartphone a numeric keyboard. I've been reading about it and I think that with the property input_type=number I could get the right result but I realised that with the kivy updates doesn't work nowadays. How could I get the numeric keyboard when my textinput is focused? With the app in landscape mode it could be useful or the keyboard still will take half screen? Here do you have the code:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
class LoginScreen(GridLayout):
def __init__(self,**kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols=2
self.add_widget(Label(text='Subject'))
self.add_widget(Label(text=''))
self.add_widget(Label(text='1'))
self.add_widget(TextInput(multiline=False))
self.add_widget(Label(text='2'))
self.add_widget(TextInput(multiline=False))
self.add_widget(Label(text='3'))
self.add_widget(TextInput(multiline=False))
self.add_widget(Label(text='4'))
self.add_widget(TextInput(multiline=False))
b1=Button(text='Exit',background_color=[0,1,0,1],height=int(Window.height)/9.0) #doesn't work properly
self.add_widget(b1)
b2=Button(text='Run',background_color=[0,1,0,1],height=int(Window.height)/9.0) #doesn't work properly
self.add_widget(b2)
b1.bind(on_press=exit)
class SimpleKivy(App):
def build(self):
return LoginScreen()
if __name__=='__main__':
SimpleKivy().run()
I think is a bit late, bu maybe someone looks for it tomorrow.
Is true you should change the input_type propery of your TextInput, in your case for example:
self.add_widget(TextInput(multiline=False, input_type = 'number'))
I suggest you create a new custom widget for that in order works in android and desktop, like this that implement a maxdigits property:
class IntegerInput(TextInput):
def __init__(self, **kwargs):
super(IntegerInput, self).__init__(**kwargs)
self.input_type = 'number'
def insert_text(self, substring, from_undo=False):
if substring.isnumeric():
if hasattr(self, "maxdigits"):
if len(self.text) < self.maxdigits:
return super(IntegerInput,self).insert_text(substring, from_undo=from_undo)
else:
return super(IntegerInput, self).insert_text(substring, from_undo=from_undo)
Background: I am using solely Python to implement the Kivy screens. I have two screens that both contain a list, and two rows of buttons. I thought it would be good programming practice to create a screen class that has those layouts, and then use inheritance to create the two screens and add buttons to the layouts as needed.
The Problem: However, when I do this I find that in the child screens I cannot access self.manager.current <-- specifically '.current' It also does not have access to self.manager.transition. I wish to understand why this happens, and how/what things are inherited here.
Question: Does anybody know why or how it is not inheriting the parent screen's manager's properties?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.listview import ListView, ListItemButton
from kivy.adapters import listadapter
from kivy.uix.button import Button
from kivy.properties import ListProperty, StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class ListScreen(Screen): # This is the super class that I am trying to inherit through
itemList = ListProperty([])
selected_value = StringProperty()
layout = BoxLayout(orientation ='vertical')
top_buttons=BoxLayout(size_hint_y=0.1)
scrollable_list=ListView(adapter=listadapter, size_hint_y=0.8)
scrollable_list.data=itemList
scrollable_list.selection_mode='single'
scrollable_list.allow_empty_selection=False
# scrollable_list.cls=ListItemButton <-- Unrelated bug here, ignore this line
bot_buttons=BoxLayout(size_hint_y=0.1)
def __init__(self, **kwargs):
super(ListScreen, self).__init__(**kwargs)
def finalize_widgets(self):
self.layout.add_widget(self.top_buttons)
self.layout.add_widget(self.scrollable_list)
self.layout.add_widget(self.bot_buttons)
self.add_widget(self.layout)
def change(self,change):
self.selected_value = 'Selected: {}'.format(change.text)
def change_screen(self, screen_name):
self.manager.current = screen_name # <-- Here is the problem
class SubScreen(ListScreen):
# This is one of the child classes, intended to inherit Screen through the parent ListScreen class.
def __init__(self, **kwargs):
super(SubScreen, self).__init__(**kwargs)
save = Button(text='Save')
load = Button(text='Load')
new_d = Button(text='New')
new_s = Button(text='New Search')
self.top_buttons.add_widget(save)
self.top_buttons.add_widget(load)
self.top_buttons.add_widget(new_d)
self.top_buttons.add_widget(new_s)
new_s.bind(on_press = self.change_screen('search'))
class ListBuilderApp(App):
def build(self):
sm = ScreenManager(transition=SlideTransition())
sm.add_widget(SubScreen(name='list'))
sm.add_widget(SearchResults(name='results'))
sm.add_widget(SearchScreen(name='search'))
return sm
if __name__ == "__main__":
ListBuilderApp().run()
Well, I don't see ScreenManager which is basically what you get with self.manager(object), so...
No ScreenManager with Screens added either in python or kv like widgets(add_widget()), no self.manager inside any of the Screens - you can't access something that isn't there.
Add some class which will be a root for your Screens and make it ScreenManager + add Screens as children.
Edit:
I was blind probably, but I didn't see on_press=.. stuff. There is the problem, because you didn't assign the function to an event, rather called the function right when you put ('search') at the end. (try do self.parent and you'll see)
Kivy events(at least "on_") catch the function, but not the parameters, not directly. That's why you need to use partial
from functools import partial
new_s.bind(on_press = partial(self.change_screen,'search'))
With this the error is gone, but some adapter binding jumps out which I really don't have a clue how to fix as I don't use it that much.
So earlier today I asked about a widget error to which inclement responded to.
His answer worked, but not perfectly. My original problem was adding a widget from a function after a button click, but every time I click the button it adds one more of itself. So first click it says "hi", second click it says "hi hi" and so on.
Here is my code(example script):
import kivy
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
textshow = BoxLayout()
def answer(answer):
text = Label(text=str(answer))
textshow.add_widget(text)
Builder.load_string('''
<main>:
Button:
on_release: root.show()
''')
class main(BoxLayout):
def show(self):
answer("test")
App.get_running_app().popup.open()
class apprun(App):
def build(self):
self.popup = Popup(content=textshow)
return main()
apprun().run()
It's because your answer function adds a widget to textshow, but you never remove any widgets so you just get more and more.
You'd be better off putting this all in a specific class rather than in these global scope variables. For instance, you could make your own popup class displaying some text however you like, and simply set this text with a StringProperty. Then you could either store one or just make a new instance each time with the text property you want.
I would like to create a function which only returns its value once the user input text into a TextInput and click on an ok button. For example
n = PopupInput("What number should I add?")
print 5+n
I can't figure out how to write a kivy dialog which will pause execution and wait until the user closes it. In other GUI toolkits, I would have used something like
while True:
if dialog.visable == False:
return int(textbox.text)
else:
wx.Yield()
To allow my code to just sit in one spot while allowing the GUI framework to do its thing. However, I can find no equivalent method for Kivy.
EDIT:
Here's my unsuccessful attempt (its messy)
def PopupOk(text, title='', btn_text='Continue'):
btnclose = Button(text=btn_text, size_hint_y=None, height='50sp')
content = BoxLayout(orientation='vertical')
p = Popup(title=title, content=content, size=('300dp', '300dp'),
size_hint=(None, None))
content.add_widget(Label(text=text))
ti = TextInput(height='50sp', font_size='50sp', input_type='number')
content.add_widget(ti)
def _on_d(*args):
p.is_visable = False
p.bind(on_dismiss=_on_d)
p.is_visable = True
content.add_widget(btnclose)
btnclose.bind(on_release=p.dismiss)
p.open()
while not p.is_visable:
EventLoop.idle()
return ti.text
I would think about this the other way around - what you really want to do is print the number when the popup is closed.
Assuming you have a popup with a textinput for the user to write in, you can do popup.bind(on_dismiss=some_function) to run that some_function when the popup is closed. That means all you need to do is write a function that takes a popup, retrieves the textbox text, and prints whatever answer you want.
I'm not sure how directly this fits with whatever you're really trying to do, but it's a more natural way to work with Kivy's event system. I can maybe answer differently if you have some strongly different requirement.
Edit: Seeing your edit, this is almost what you do, but I think it is a bad idea to try and beat the eventloop into submission this way rather than going with the flow. I would create a new function (as I said above) that takes a textinput and does whatever you really want. By binding on_dismiss to this function, you let kivy take care of starting your computation later whenever the user gets around to dismissing the popup.
Kivy is really built around the principle of events and async callbacks. Because it uses OpenGL and relies upon frames rendered on the GPU, not the CPU, you never want to use blocking code. So kivy uses event binding to circumvent the issue.
Here is one approach.
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class MainApp(App):
def build(self):
self.button = Button(text="Click",
on_release=self.get_caption)
return self.button
def get_caption(self, btn):
Popup(title="Enter text here",
content=TextInput(focus=True),
size_hint=(0.6, 0.6),
on_dismiss=self.set_caption).open()
def set_caption(self, popup):
self.button.text = popup.content.text
MainApp().run()
You place content in a popup, when give it a "set_caption" function to call when it's dismissed. There you respond to the change. No blocking. No waiting. Having worked with threading to stop GUI blocking in wxWidgets, I really think this is a better way...;-)
Cheers
What you are looking for can be achieved with the following code. You need to specify routines as methods in the main program:
import kivy
kivy.require('1.5.0') # replace with your current kivy version !
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.app import App
from kivy.clock import Clock
class YourApp(App):
def build(self):
return Button(text='Press for popup!', on_press=self.callpopup)
def callpopup(self, event):
dlg = MessageBox(titleheader="Titel Header", message="Any Message", options={"YES": "printyes()", "NO": "printno()"})
print "Messagebox shows as kivy popup and we wait for the \nuser action and callback to go to either routine"
def printyes(self):
# routine for going yes
print "You chose the Yes routine"
def printno(self):
# routine for going no
print "You chose the No routine"
class MessageBox(YourApp):
def __init__(self, titleheader="Title", message="Message", options={"OK": "self.ok()", "NO": "self.no()"}):
def popup_callback(instance):
"callback for button press"
# print('Popup returns:', instance.text)
self.retvalue = instance.text
self.popup.dismiss()
self.retvalue = None
self.options = options
box = BoxLayout(orientation='vertical')
box.add_widget(Label(text=message, font_size=20))
b_list = []
buttonbox = BoxLayout(orientation='horizontal')
for b in options:
b_list.append(Button(text=b, size_hint=(1,.35), font_size=20))
b_list[-1].bind(on_press=popup_callback)
buttonbox.add_widget(b_list[-1])
box.add_widget(buttonbox)
self.popup = Popup(title=titleheader, content=box, size_hint=(None, None), size=(400, 400))
self.popup.open()
self.popup.bind(on_dismiss=self.OnClose)
def OnClose(self, event):
self.popup.unbind(on_dismiss=self.OnClose)
self.popup.dismiss()
if self.retvalue != None:
command = "super(MessageBox, self)."+self.options[self.retvalue]
# print "command", command
exec command
if __name__ == '__main__':
YourApp().run()
Please i am looking for a work around to get access Android camera through kivy, or a library that i can integrate with kivy in order to access the Camera.
I am developing an application for android but using python-kivy for the UI,
anything will be really appreciated,
thanks alot.
Here's my sample code, that works on Android. Just import that file https://github.com/kivy/plyer/blob/master/plyer/platforms/android/camera.py
Also, don't forget to add CAMERA permissions to manifest.
main.py:
__version__ = '1.0'
import kivy
# importing file from https://github.com/kivy/plyer/blob/master/plyer/platforms/android/camera.py
# I downloaded it and saved it in the same directory:
from camera import AndroidCamera
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty, StringProperty
import base64
class MyCamera(AndroidCamera):
pass
class BoxLayoutW(BoxLayout):
my_camera = ObjectProperty(None)
# /sdcard means internal mobile storage for that case:
image_path = StringProperty('/sdcard/my_test_photo.png')
def __init__(self, **kwargs):
super(BoxLayoutW, self).__init__()
self.my_camera = MyCamera()
def take_shot(self):
self.my_camera._take_picture(self.on_success_shot, self.image_path)
def on_success_shot(self, loaded_image_path):
# converting saved image to a base64 string:
image_str = self.image_convert_base64
return True
#converting image to a base64, if you want to send it, for example, via POST:
def image_convert_base64(self):
with open(self.image_path, "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
if not encoded_string:
encoded_string = ''
return encoded_string
if __name__ == '__main__':
class CameraApp(App):
def build(self):
main_window = BoxLayoutW()
return main_window
CameraApp().run()
camera.kv:
<BoxLayoutW>:
Button:
text: 'shot'
on_release: root.take_shot()
Kivy has some native support for calling the camera. Check out this page from the new programming guide for a core provider or this page from the new programming guide for a uix widget. In theory, the core should be able to adapt between platforms and the widget should then be able to use the camera.
This links to a discution where a custom implementation can be found. It is based on PyJNIus's automatic wrapping of the android API's Camera class.
Didn't try myself but you can give it a try...
thanks to this post i was able to solve a critical problem in my app thanks a lot guys here is my code that i used i hope that you guys can use it somewhere.
I made a screen and used the plyer camera function
from os import getcwd
from os.path import exists
from os.path import splitext
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.logger import Logger
from plyer import camera
i also used some other imports for the screens and the labels and popups etc which you can definatly look into depending upon your requirment
class ScreenFive(Screen): #camera screen
def gg1back(self):
self.parent.current = 'First'
def do_capture(self):
filepath = 'IMG_1.jpg'
ext = splitext(filepath)[-1].lower()
try:
camera.take_picture(self.camera_callback,filepath)
except NotImplementedError:
popup = MsgPopup(
"The Face_rec_image feature has not yet \n been implemented for this platform :(")
popup.open()
def camera_callback(self, filepath):
if(exists(filepath)):
popup = MsgPopup("Picture saved!")
popup.open()
else:
popup = MsgPopup("Could not save your picture!")
popup.open()
As it was hard for me to find the answer how to use camera on android I thought I'll share my journey to the answer to save next person's time.
I couldn't find the way to make work Camera class straight from Kivy:
https://kivy.org/docs/examples/gen__camera__main__py.html
finally I found the solution posted above, and after wasting some time implementing it in my app it turned out it was impossible for me to return to the app after photo being taken - the app was terminated, so I couldn't go back to the app to make use of the picture (I was using Kivy Launcher).
Just recently I found out this way of accessing Camera was abandoned (https://github.com/kivy/plyer/issues/16#issuecomment-54094174 )
But then I found the solution below and by just running the example code it looks like I will be able to get results I want (it just needs a little tweaking not to crash when android camera is canceled/no photo has been taken)
https://github.com/kivy/kivy/tree/master/examples/android/takepicture
EDIT:
appears my app was terminated because I didn't implement on_pause: return True in topmost widget. Nevertheless the text above still might be helpful
Some years later, the Android API has changed as to how it deals with permissions and storage providers.
I have a full working example for the Android camera through Kivy here. It basically requires some tweaking of the compiled manifest file in python-for-android, as well as working directly with the FileProvider.