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.
Slight problem with template
-
Hi All
Got to the stage of putting my app into Xcode but have a strange problem that I'm sure someone out there must have come across before.
when entering a new value in a textfield its not transferring the number into the program.
it works perfectly in pythonista every time but when I run it through Xcode I get...
My App[816:331016] [MC] Reading from public effective user settings. My App[816:331016] [Snapshotting] Snapshotting a view (0x107fd0170, UIInputSetHostView) that has not been rendered at least once requires afterScreenUpdates:YES. My App[816:331016] [Snapshotting] Snapshotting a view (0x108840a00, UIKeyboardImpl) that is not in a visible window requires afterScreenUpdates:YES.
any one help as to where to put in the afterScreenUpdates:YES or somewhere in my python code to do the same trick, I have tried a few different places but it just kicks up more errors every time.
-
When you say textfield is not transferred into the program, what specifically do you mean? The delegates methods are not running? Querying the text property returns None?
Those errors look unrelated to me...
-
HI
I can select the textfield and enter new value into it, press return and dismiss the keyboard. the new value remains in the textfield but the value is not passed into the program itself to update with the values created inside the UIView.
"nodes" : [ ], "frame" : "{{88, 104}, {145, 67}}", "class" : "TextField", "attributes" : { "uuid" : "4DA8C238-6892-48F7-8EF3-1D626569A9D0", "corner_radius" : 6, "frame" : "{{412, 368}, {200, 32}}", "border_width" : 1, "custom_attributes" : "", "alignment" : "center", "autocorrection_type" : "default", "action" : "change_time1", "text" : "120", "placeholder" : "", "font_name" : "MarkerFelt-Wide", "spellchecking_type" : "default", "class" : "TextField", "name" : "textfield1", "font_size" : 46 }, "selected" : false }, '''
.def change_time1(r1): timer1[1] = int(r1.text) timer1[2] = timer1[1] if timer1[1] <= 1 or timer1[1] >= 1801: timer1[1] = stdtime[0] tv1 = r1.superview['textfield1'] tv1.text = str(timer1[1]) if timer1[0] == 0: label4_action = r1.superview['label4'] label4_action.text = str(timer1[1])
its as if there is a disconnection between the screen process and passing back the changetimer1 action so the value doesn't update. looking at the Xcode console the snapshotting error is the one that's given. I can change the value many times but it always gives the error and doesn't perform the action. I have set breakpoints but they never trigger.
none this happens when I run it in pythonista.
Cheers
-
That is a warning and unrelated to your present issue.
Does the template let you print things to the console?
Try this:
- first, after you load your view, print out v['textfield'].action to make sure it exists and is callable.
- next, try calling it, directly. Put a print out at first line, or other way to tell it it is being called (change bgcolor, etc). This verifies that the function itself is not screwy.
- instead of using action, try using a delegate class, with the various textfield delegate methods. textfield_should_change, etc. There was one version of pythonista where action might not have existed yet.
- try using textview instead of textfield
Next, we can try adding objc_util delegates, but let's see if this works first.
-
Do you have other button actions that work?
-
hi JonB
I have 4 textfields none of which work in Xcode but all work in pythonista on my iPad
I have 5 switches and 5 buttons which all work perfectly in both Xcode and iPad Pythonista.
it's just TextField it has a problem with. Did this change from 2.7 to 3.5? as the original iPad Pythonista version was written in 3.5 and I converted it to 2.7 to run in Xcode, could it be that?
-
Yes I can change border colours and backgrounds ok.
Cheers
-
You can change bgcolor from within the action? If so, that means your action is having a problem inside.
Try a try/except in your action, then print/log the exception to console or another textview.
-
@Gadgettyke it is not about 2.7/3.5 (though you should run your code in 2.7 to make sure it works)... But some parts of
ui
were changed between pythonista2 and pythonista3. At one time, either textfield or textview did not have anaction
, and you had to use a delegate instead.I have pythonista2 still installed, if you want to share your code I could take a look.
-
that'll be great Jon,
let me try your other suggetions first then I'll have look up how to use the git again to send you the files if they don't work. I'm running it fine in 2.7 on my iPad Pro and really haven't had a problem until I tried putting it in Xcode.
Cheers
-
The easiest way to share files is to go to file library view (i.e This iPad), to the folder with your files, tap Edit, select the files, then tap the share button, and choose Gist.
Does XCode allow you to use print to print to the console? Are exception tracebacks displayed somewhere, or just fail silently?
If not, we can use NSLog statements to help figure things out. -
hi Jon
Gist coming up with error 0. am signed in ok but no joy. I have stripped most of the clutter out in another file that shows the problem nicely. its basically not calling the action textchange that's set as the action in the UI for the textfield. the colour changes were a bit of a red herring as I had another layer that changed colour not the textfield.
I have downloaded pythonista 3 again but still no joy.
can you send me an example of the app delegate solution.
here's where its going wrong
def textchange(sender): name=sender.name text=sender.text tfval[0]= name tfval[1]= text #print(name,text) # set timer 1 setval if name =='textfield1': timer1[1] = int(text) timer1[2] = timer1[1] if timer1[1] <= 1 or timer1[1] >= 1801: timer1[1] = stdtime[0] tf1 = sender.superview['textfield1'] tf1.text = str(timer1[1]) if timer1[0] == 0: label1_action = sender.superview['label1'] label1_action.text = str(timer1[1]) # set timer1 warval if name == 'textfield2': timer1[3] = int(text) if timer1[3] <= 0 or timer1[3] >= timer1[1]: timer1[3] = round(timer1[1] / 5) tf2 = sender.superview['textfield2'] tf2.text = str(timer1[3]) if timer2[0] == 0: label2_action = sender.superview['label2'] label2_action.text = str(timer2[1]) # set timer2 setval if name == 'textfield3': timer2[1] = int(text) timer2[2] = timer2[1] if timer2[1] <= 0 or timer2[1] >= 1801: timer2[1] = stdtime[1] tf3 = sender.superview['textfield3'] tf3.text = str(timer2[1]) if timer2[0] == 0: label3_action = sender.superview['label3'] label3_action.text = str(timer2[1]) #set timer2 warval if name == 'textfield4': timer2[3] = int(text) if timer2[3] <= 0 or timer2[3] >= timer2[1]: timer2[3] = round(timer2[1] / 5) tf4 = sender.superview['textfield4'] tf4.text = str(timer2[3]) if timer2[0] == 0: label4_action = sender.superview['label4'] label4_action.text = str(timer2[1]) # write back to the confer countdown display label 4 # if under warning time turn it red def label1_update(label1): label1_change = label1 label1_change.text = str(timer1[2]) if timer1[2] == timer1[3]: label1_change.text_color = '#ffffff' label1_change.background_color = '#ff0000' # write back to the pass countdown display label 5 # if under warning time turn it red def label3_update(label3): label3_change = label3 label3_change.text = str(timer2[2]) if timer2[2] == timer2[3]: label3_change.text_color = '#ffffff' label3_change.background_color = '#ff0000' # write back to label 2 def label2_update(label2): label2_change = label2 label2_change.text = str(timer1[3]) # write back to label 2 def label4_update(label4): label4_change = label4 label4_change.text = str(timer2[3]) def label5_update(label5): label5_change = label5 label5_change.text = tfval[0] def label6_update(label6): label6_change = label6 label6_change.text = tfval[1] def main(): #console.set_idle_timer_disabled(True) v = ui.load_view('main') v.background_color = sc_status[0] v.bar_color = sc_status[0] label6 = v['label6'] label5 = v['label5'] label4 = v['label4'] label3 = v['label3'] label2 = v['label2'] label1 = v['label1'] label4.font = ('markerfelt-wide', 20) label4.background_color='#ffffff' label3.font = ('markerfelt-wide', 20) label3.background_color='#ffffff' tv1 = v['textfield1'] tv2 = v['textfield2'] tv3 = v['textfield3'] tv4 = v['textfield4'] tv1.text=str(timer1[1]) tv2.text=str(timer1[3]) tv3.text=str(timer2[1]) tv4.text=str(timer2[3]) v.present('sheet') delta = time.clock() seconds[1] = int(delta) # timing loops engaged and running while True: #how_long(seconds) #if seconds[0] == 1 and (timer1[0] == 1 or timer2[0] == 1): # timer_update() # calling to update label values label1_update(label1) label2_update(label2) label3_update(label3) label4_update(label4) label5_update(label5) label6_update(label6) # seconds[0] = 0 # check if still on screen? if not then exit onscreen = v.on_screen if onscreen is False: # console.set_idle_timer_disabled(False) return False main()
runs beautifully on my iPad but it will not call textchange def from Xcode version.
Cheers
-
@Gadgettyke can you try it without the while True loop? That can cause some problems. The "right" way to do something like that is to have a thread, or at a minimum something like
def update(): #update labels here... # if onscreen: ui.delay(update, 0.1) #some suitable update rate #then in main... update() #start update
Also, your code above does not seem to complete, in the sense that i dont see
timers
defined, etc? -
actually, lets try greatly simplifying:
import ui, console def textchange(sender): console.hud_alert('textchange called {}'.format(sender.name)) class MyTextFieldDelegate (object): def textfield_should_begin_editing(self, textfield): console.hud_alert('shouldbegin called {}'.format(textfield.name)) return True def textfield_did_begin_editing(self, textfield): console.hud_alert('didbegin called {}'.format(textfield.name)) def textfield_did_end_editing(self, textfield): console.hud_alert('didend called {}'.format(textfield.name)) def textfield_should_return(self, textfield): textfield.end_editing() return True def textfield_should_change(self, textfield, range, replacement): console.hud_alert('shouldchange called {}'.format(textfield.name)) return True def textfield_did_change(self, textfield): console.hud_alert('didchange called {}'.format(textfield.name)) def main(): v=load_view('main') tv1 = v['textfield1'] tv2 = v['textfield2'] tv3 = v['textfield3'] tv4 = v['textfield4'] delegate=MyTextFieldDelegate() for tv in [tv1, tv2]: tv.action = textchange for tv in [tv3, tv4]: tv.action =None tv.delegate =delegate v.present('sheet') console.hud_alert('main complete') main()
Use this as your main script. Textfield1 and textfield2 will alert use when text change. 3 and 4 will alert you for each stage (when you start editing, when you type, and when you press enter)
If both types work, then we know the problem is elsewhere in your code, such as an exception in the callback itself, or the while True issue. If neither work, then we are back to basics.
can you confirm that textfield1, etc are TextField, and not TextView? TextViews do not (or at least didnt at one time) have action attributes, instead you had to use delegates (which are named differently)
-
hi jonB
sorry it was a much cut down listing from a much much larger program, The only problem I have is with the textfield so I isolated it for you.
the pyui file code is
] "frame" : "{{88, 104}, {145, 67}}", "class" : "TextField", "attributes" : { "uuid" : "4DA8C238-6892-48F7-8EF3-1D626569A9D0", "corner_radius" : 6, "frame" : "{{412, 368}, {200, 32}}", "border_width" : 1, "custom_attributes" : "", "alignment" : "center", "autocorrection_type" : "default", "action" : "change_time1", "text" : "120", "placeholder" : "", "font_name" : "MarkerFelt-Wide", "spellchecking_type" : "default", "class" : "TextField", "name" : "textfield1", "font_size" : 46 }, "selected" : false },
so it is selected as a textfield. the code is the same for all four fields 1,2,3,4
I'm new to python and have programmed PLC's mainly so a linear approach is something I tend to default to. not really done much with C previously.
all I can say is wow! many thanks, i'll get this into my test program and see if that cures it. if so I see a long weekend of getting into my main program.
I'll get back to you on the results.
Cheers -
Many Many thanks JonB, the class did the trick and its functioning perfectly.
I've put it in the main body of my program and its sorted out the issue fully.
the setting of the tv.action has made sure my function works a treat.
You mentioned that the while true may cause a problem, is this something you have come across before?
cheers
Gadgettyke -
i will point out that your textfield action was set to change_time1. maybe that is just because you created a simplified version?
while True will give you problems if you use ui.in_background, because it queues up those on the same thread running the while True. Probably not the problem here, but I wasnt sure if the Xcode template works differently.
-
Oops the pyui code snippet is from the full program not the simplified version I sent you. As you can tell not genius level at python unlike your good self. However i’m excellent at other things like 3D cad and printing so if ever I can repay the favour just let me know.
Ok I see what your saying, if I ever get my head round the class thing, the more I get out of the loop the better.
I do like the update suggestion as well and have included that now as well.
Cheers