Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
checking for integers inside of a ui textfield
-
I'm trying to check if a textfield in my ui has any numbers in it when I press on a button. When I use the same code on a string it works. When I use the code for textfield within a button's action it doesn't work. Please help? Here's what my code is like:
import ui import console def contains_digits(d): for char in d: if char.isdigit(): return True return False test='test3' print(contains_digits(test)) #this works - it prints TRUE! #below always prints failed even though it should print whatever is in the textfield?! def button_pushed(sender): if contains_digits(textfield1): print(textfield1) print('failed') v=ui.load_view() textfield1 = str(v['textfield1'].text) v.present('fullscreen')
-
To debug this problem, print textfield when entering button_pushed.
As a reminder, strings in pythons are their own object, not pointers.>a='hello' >b=a >a='world' >print(a==b) False
By the way, in case you have never used pdb before, this can really be useful.
def button_pushed(sender): import pdb pdb.set_trace()
now, when you push the button, type
print(textfield)
print(v['textfield1'].text) -
Thanks so much for your help here. It seems that it's a problem with the variable - textfield1
Doing what you said - textfield1 prints nothing to the console and v['textfield1'].text prints whatever was typed into the textfield
Do you happen to know anyway in which I can use a variable to print to the console using the button?
I think I understand the issue from how you've explained it - the variable textfield1 starts of as "" and so even when it changes it's always going to remain as "", in order for me to put it into a variable - I'd have to put it into a variable within the function, when it's already set as whatever the user has set it as.
I think I may have answered my own question there?
-
Yep. Just use v['textfield1'].text, or store a refernce to the actual textfield object, then you can print the .text attribute.
-
@wenchoheelio , below is another way to consider filtering your TextField. Ie using a TextField Delegate. This way you are getting a peek at the key before it makes it into the TextField(you can accept or reject it, by either returning True or False). Below I have just copied the standard Delegate from the Pythonista Documentation. I just modified the textfield_should_change callback.
I could have deleted all the other methods in the class as in this case I am not using them. They will just do their default behaviour if they are not there. I point that out because the code looks longer and more complicated that it needs to to handle your case. I left them in so it was easy to see the other events you can take control of. Basically meaning you can have a lot of control over the data entry into the TextField.Btw, I am looping over the replacement as it maybe a string that is being pasted into the textfield. You can try it by copying say '123456' and pasting it into your field. It will appear. But then try pasting '123456R' into the field, that will not work.
Hope it helps.
import ui class MyTextFieldDelegate (object): def textfield_should_begin_editing(self, textfield): return True def textfield_did_begin_editing(self, textfield): pass def textfield_did_end_editing(self, textfield): pass def textfield_should_return(self, textfield): textfield.end_editing() return True def textfield_should_change(self, textfield, range, replacement): for c in replacement: if not c.isdigit(): return False return True def textfield_did_change(self, textfield): pass class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): tf = ui.TextField(frame=(0, 0, self.width, 32)) tf.delegate = MyTextFieldDelegate() self.add_subview(tf) if __name__ == '__main__': f = (0, 0, 300, 400) v = MyClass(frame=f) v.present(style='sheet', animated=False)
-
@Phuket2 Thanks, I really appreciate the time you've taken to write this.
-
super().init(*args, **kwargs)
I don't fully understand the super() part here. Not sure I really need to understand or use it early on? Also, I understand arguments/parameters - but what's *args, **kwargs ?Does that mean something? Arguments and KW arguments?!
(frame=f)
What is this code for? It doesn't look like the function requires a parameter? (obviously it does.. I just don't understand it)
Thanks.
-
@wenchoheelio
MyClass
is a subclass ofui.View
.ui.View
already has its own__init__
method, and now we also define an__init__
method in our subclass. By default, our subclass__init__
would completely replace the__init__
fromui.View
. This would not be good, because then the code inui.View.__init__
would never run for ourMyClass
views, and they would not be set up properly. To avoid this, we callsuper().__init__(*args, **kwargs)
, which is (in this case) a shortcut forui.View.__init__(self, *args, **kwargs)
. That is, we letui.View
initialize our custom view before we do our own initialization.The
*args
and**kwargs
syntax is used here to pass all arguments from our own__init__
to the superclass__init__
. In a function/method definition,*args
stands for "accept any number of positional (unnamed) arguments and put them intoargs
as a tuple", and**kwargs
stands for "accept any number of keyword (named) arguments and put them intokwargs
as a dictionary". In a function/method call, they do basically the opposite, and pass the contents of the given tuple/dictionary as arguments.