thank you for your time.
I have an APP I'm working on. I'm trying to automate something where every word I write in the MDTextField id: sent is turned into it's own MDChip id: chip to be selected later on by the user.
The closest I've gotten is using this:
class Main(Screen):
"""main application goes here"""
def my_callback(dt):
def __init__(self):
sent = self.ids.sentence.text.lower()
print(sent)
for word in sent.split():
c = MDChip(label=word, icon='check')
self.ids.chip.add_widget(c)
Clock.schedule_interval(my_callback, 0.5)
But it doesn't work. def init(self) never actually runs it seems... idk... I have verified that the my_callback function is getting called properly by the Clock but that's as far as it goes.
Any thoughts anyone..?
Maybe there is a better function inside Kivy that is called anytime something is typed in a textfield?? That would be perfect I think...
Ultimately I want to use one of the MDChip selected by the user and replace their sentence with a new word. I truly appreciate any help.
Your my_callback() method is just defining another method named __init__(), without actually calling that new method. That is an inner function and is not visible outside of my_callback().
Try changing my_callback() to:
def my_callback(self, dt):
sent = self.ids.sentence.text.lower()
print(sent)
for word in sent.split():
c = MDChip(label=word, icon='check')
self.ids.chip.add_widget(c)
Also, an __init__() method is the method used to initialize a Widget, and it's not good programming practice to use that method name for other purposes.
Here what I finally found with some help. Thanks all.
class Main(Screen):
def on_pre_enter(self):
Window.bind(on_key_down=self.call)
def call(self, *args):
self.ids.stack.clear_widgets()
sent = self.ids.sentence.text.lower()
for word in sent.split():
c = MDChip(label=word,
callback=self.do_something,
icon='checkbox-blank-outline',
color=[.1, .1, .1, .5],)
self.ids.stack.add_widget(c)
def do_something(self, inst, word, *args):
inst.icon = 'checkbox-marked-outline'
WORD = word
print(WORD)
return WORD
Using the Window.bind inside the on_pre_enter was the most important thing. Then it all worked. Here is my KV code:
MDStackLayout:
id: stack
orientation: 'lr-tb'
pos_hint: {'center_x': 0.5, 'center_y': 0.6}
padding: dp(8)
spacing: dp(8)
Related
So I have created Mobile App called PushApp using Python library Kivy. App lets user input number of how many pushups he wants to do. Then its supposed to decrement the number by one when chest hits screen(button). If screen is touched by multiple body parts it decrements many numbers. I would like to know how to disable multitouch function for Android phones at least.
Regards,
Highzivs
I have managed to solve this problem by creating function (BUTTON_DOWN()) that returns how many times button has been pushed down and function (BUTTON_UP) that returns button release times.
Then I created function (PUSH_UP) which returns true if BUTTON_DOWN()==BUTTON_UP()
in Python:
class CountScreen(Screen):
DOWN_COUNT=0
UP_COUNT=0
PUSH_UP_COUNT=0
def BUTTON_DOWN(self):
self.DOWN_COUNT=self.DOWN_COUNT+1
return self.DOWN_COUNT
def BUTTON_UP(self):
self.UP_COUNT=self.UP_COUNT+1
return self.UP_COUNT
def PUSH_UP(self):
if self.BUTTON_UP()==self.BUTTON_DOWN():
return True
in Kivy:
<CountScreen>:
name:"CountingWindow"
GridLayout:
cols:1
Label:
id:lbl_1
font_size:400
text:""
Button:
id:"btn_1"
background_color:(0,0,0,.1)
on_press:
root.BUTTON_DOWN()
on_release:
root.BUTTON_UP()
if root.PUSH_UP():lbl_1.text=str(int(lbl_1.text)-1) #DECREMENTS 1 FROM USER INPUT
if lbl_1.text == '0':app.root.current="FinalScreen" #GO TO FINAL WINDOW WHEN FINISHED
I have a kv segment that is within my python code.
What I want to do is select this button and animate it. The animation itself is triggered by pressing NoButton. NoButton has a class of itself that is child to the root widget class. Unfortunately despite having been able to successfully reference id out of the kv code, i can't seem actually make use of it.
Pressing NoButton results in absolutely nothing. No errors, nothing. If I try to print the id what i get is the location of the button it references:
<__main__.MainButton object at 0x7fd5db0d5590>
Here is a snippet of the kv code:
<MainClass>:
<MainScreen>:
id: main
AnchorLayout:
size: root.size
anchor_x: 'center'
anchor_y: 'center'
padding: 0, 0, 0, 50
MainButton:
id: pics
rgba: 1,5,1,1
size_hint_x: None
size_hint_y: None
height: main.height / 1.5
width: main.width / 1.5
and the python:
class MainScreen(Screen):
pass
class MainButton(Button):
pass
class NoButton(ButtonBehavior, Image, MainClass):
def on_press(self):
anim = Animation(x=300, y=300)
anim.start(MainButton())
print(MainScreen().ids.pics)
You'll notice anim.start references the class rather than the id here. Unfortunately it produces the same result; nothing at all.
Creating pics as an object property and declaring that in kv fails to work too.
I really am completely clueless here. I've looked through the few questions that are slightly similar but there really isn't much when it comes to help/guides for in depth kivy development.
I'm using Python 3.5.3 and Kivy 1.9.2-dev0
Would appreciate any help/advice or pointers in the right direction :)
You are creating new objects instead of referencing the exiting ones
anim.start(MainButton()) #new MainButton Object :(
print(MainScreen().ids.pics) #also a new MainScreen object
I don't see in your code where is NoButton, but should get a hold on the MainScreen instance and from it extract the MainButton instance
main_button = main_screen.ids.pics
ani.start(main_button)
If you'll post a runable example I'll might be able to help you more, I guess...
It's me again!
Well, that's really strange.
I'using kivy for make an App for Android.
I can use the camera, but or the app resets or do something strange.
Here is the problem:
def chamar_camera(nome,pc,objeto,label_passa,instance):
agora = datetime.now()
nome_arquivo = '%s_%s_%.4i_%.2i_%.2i_%.2i_%.2i_%.2i.jpg' % (nome,pc,agora.year,agora.month,agora.day,agora.hour,agora.minute,agora.second)
# Option 1 - These two lines work:
#def sair():print 'oi'
#camera.take_picture(nome_arquivo, sair)
# Option 2 - These two lines work too:
def sair(label_passa,nome_arquivo):print 'oi'
camera.take_picture(nome_arquivo,on_complete=sair(label_passa,nome_arquivo))
# Option 3 - But these don't:
#def sair(label_passa,nome_arquivo):label_passa.text = nome_arquivo
#camera.take_picture(nome_arquivo, on_complete=sair(label_passa,nome_arquivo))
def on_pause(self):return True
def on_resume(self):pass
On option 3, I write a text (nome_arquivo) on a label widget (label_passa), but what happens is that the text is wrote before the camera be activated. So the camera appear, I can take a picture and the App restarts. I also tried just a "def sair(): pass", but this doesn't work. The only thing working is an "print", but on my app I need to write something in that label and update an sqlite database. Any idea why the function is being called before the camera action?
Thanks!
on_pause and on_resume should be defined as methods of your App class, not (as you have here) functions defined locally within the chamar_camera function.
in Kivy, when I press the back button on my android device it throws me out of the application. is there a way to return back to the previous screen using the Kivy language and not python? this is what I have written in kivy:
<MyAppClass>:
AnchorLayout:
anchor_x : 'center'
anchor_y : 'top'
ScreenManager:
size_hint : 1, .9
id: _screen_manager
Screen:
name:'screen1'
StackLayout:
# irrelevant code
Screen:
name:'screen2'
StackLayout:
# irrelevant code
I need to manipulate the screen manager and its screens from python... if I can do so I will be ok with python.
Kivy on android binds the back button to the esc button so binding and listening to esc button in your app would help you handle how your app behaves when the back button is pressed.
In other words in your app when testing it on your desktop listen to the escape key from the system keyboard, this will be automatically be translated to being the back button on your android device. Something like::
def on_start():
from kivy.base import EventLoop
EventLoop.window.bind(on_keyboard=self.hook_keyboard)
def hook_keyboard(self, window, key, *largs):
if key == 27:
# do what you want, return True for stopping the propagation
return True
i guess that i have solved it but should thank both #inclement and #qua-non! your answers guys led me to the right way! so in kv i assume that i gave an id to my screen manager (please refer to my question where i have written the kv code) , in python i should do the following:
from kivy.core.window import Window
from kivy.properties import ObjectProperty
class MyAppClass(FloatLayout):#its a FloatLayout in my case
_screen_manager=ObjectProperty(None)
def __init__(self,**kwargs):
super(MyAppClass,self).__init__(**kwargs)
#code goes here and add:
Window.bind(on_keyboard=self.Android_back_click)
def Android_back_click(self,window,key,*largs):
if key == 27:
self._scree_manager.current='screen1'#you can create a method here to cache in a list the number of screens and then pop the last visited screen.
return True
class MyApp(App):
def build(self):
return MyAppClass()
if __name__=='__main__':
MyApp().run()
This is certainly possible. Here's a short example app with the method I use to do this:
from kivy.utils import platform
from kivy.core.window import Window
class ExampleApp(App):
manager = ObjectProperty()
def build(self):
sm = MyScreenManager()
self.manager = sm
self.bind(on_start=self.post_build_init)
return sm
def post_build_init(self, *args):
if platform() == 'android':
import android
android.map_key(android.KEYCODE_BACK, 1001)
win = Window
win.bind(on_keyboard=self.my_key_handler)
def my_key_handler(self, window, keycode1, keycode2, text, modifiers):
if keycode1 in [27, 1001]:
self.manager.go_back()
return True
return False
This should give the right basic idea, but a few notes:
ScreenManager doesn't keep track of the previous screens, it's up to you to implement this how you like. My example assumes you defined a class MyScreenManager with a go_back method.
It might not be necessary to bind to on_start and run post_build_init, this is just how the example I originally used did it (see below). It might be important sometimes though, possibly if the window is not initialised when build() is run, and the original mailing list post suggests the author needed it for some reason.
The example listens for keycodes 27 or 1001. As qua-non said while I was writing this, the former listens for esc, so you can get the same behaviour on desktop.
I didn't try without the android.map_key line, but it seems like it may not be necessary.
You mention you want to use kivy language and not python. You need to do some python to get this result, and I don't see a way around that (it's not really the domain of the kv language). I guess you could shift some stuff to kv by defining a 'go_back' event somewhere and triggering this when the key is pressed, along with binding your screenmanager to watch that event, but it seems like a long way around.
I based my code on the mailing list thread at https://groups.google.com/forum/#!topic/kivy-users/7rOZGMMIFXI . There might be a better way, but this is quite functional.
Now all the way in 2020 I'm using:
Clock.schedule_once(lambda x: Window.bind(on_keyboard=self.hook_keyboard))
in combination with a similar hook_keyboard method to the other answers, to delay the bind in my build method. Works fine, but none of these other ways ways seemed to work for me anymore.
I'd like to know how can I show simple and short data (eg: temperature data from a running script) in Android desktop using SL4A. My script gets temperature data from a web, and I tried showing it via notify, via toast and via dialogs, but I´d like it to remain accesible on the screen.
I undestand that webview is an option but I can´t write the xml code for a simple text box, as I undestand I should.
Is this right? Where could I get a (very) simple code example in xml to show text on screen (not full screen)?
Thanks!
I just re-read your question there are a few examples of full screen webviews however as far as I understand it webview is kind of an all or nothing deal. If you want to us Xml look into the Fullscreenwrapper2 as it allows you to use similar xml layouts to native java apps, from there you can look for examples of xml layouts and modify to fit.
Do you want a widget or just a dialog box? if you just want a dialog box you can just use a dialogCreateAlert
import android
droid = android.Android()
title=("Your Tittle")
content=("Your content")
droid.dialogCreateAlert(title, content)
droid.dialogShow()
However if you want it on a widget the simplest soloution I have found is to use a minimalistic text widget you can pass the data either through tasker or directly using a local intent.
Through Tasker:
import android, time
droid = android.Android()
class Task():
SET_VARIABLE = 547
def new_task(self):
self.action_cnt = 0
self.extras = {'version_number': '1.0', 'task_name': 'task' + str(time.time()), 'task_priority': 9 }
def set_var(self, varname, value):
self.action_cnt += 1
self.extras['action' + str(self.action_cnt)] = {'action': self.SET_VARIABLE, 'arg:1': varname, 'arg:2': value, 'arg:3': False, 'arg:4': False, 'arg:5': False}
def run_task(self):
taskIntent = droid.makeIntent('net.dinglisch.android.tasker.ACTION_TASK', None, None, self.extras).result
droid.sendBroadcastIntent(taskIntent)
def set_var_now(self, varname, value):
self.new_task()
self.set_var(varname, value)
self.run_task()
t = Task()
t.set_var_now("%Var", "Your variable value")
Directly via a Local intent (You select this in MT by using a Local variable field):
import android
droid = android.Android()
activity = 'com.twofortyfouram.locale.intent.action.FIRE_SETTING'
extras = {}
extras['de.devmil.minimaltext.locale.extras.VAR_NAME'] = 'Your Variable name'
extras['de.devmil.minimaltext.locale.extras.VAR_TEXT'] = 'Your Variable content'
packagename = 'de.devmil.minimaltext'
classname = 'de.devmil.minimaltext.locale.LocaleFireReceiver'
intent = droid.makeIntent(activity, None, None, extras, None, packagename, classname).result
droid.sendBroadcastIntent(intent)