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.
Action being triggered twice
-
I have 2 different controls on the same form calling the same action. The 2 ways of triggering the action are a) Pressing enter after entering text into the textfield and b) clicking the Select button. Unfortunately, if you click the Select button, both actions are being triggered and I'm not sure how to fix this. The full code is available on [github][1]
The action being triggered twice is
self.process_speak_request
which is set once in a form and once below.class TextDelegate(object):``` def textfield_did_change(self, textfield): view = textfield.superview button = view['button_select'] button.enabled = textfield.text != '' class Menu: def prompt_speak(self, sender): """Prompt the user for the task(s) to speak.""" self.prompt_dialog = ui.load_view('dialogs/speak_task_number') self.prompt_dialog['button_select'].enabled = False td = TextDelegate() self.prompt_dialog['textfield1'].delegate = td self.prompt_dialog["segmentedcontrol1"].action = self.display_speak_options self.prompt_dialog['textfield1'].begin_editing() self.prompt_dialog['textfield1'].action = self.process_speak_request self.prompt_dialog.present('popover', popover_location=(500, 500)) def display_speak_options(self, sender): """Display the controls to enter a number""" if self.prompt_dialog["segmentedcontrol1"].selected_index == 0: self.prompt_dialog["label1"].hidden = False self.prompt_dialog["textfield1"].hidden = False if self.prompt_dialog["textfield1"].text == '': self.prompt_dialog['button_select'].enabled = False else: self.prompt_dialog["button_select"].enabled = True else: self.prompt_dialog["label1"].hidden = True self.prompt_dialog["textfield1"].hidden = True self.prompt_dialog['button_select'].enabled = True def enable_select(self, sender): """Enable the Select button after a task # has been provided.""" self.prompt_dialog['button_select'].enabled = True self.main_view.set_needs_display() def process_speak_request(self, sender): """""Determine which task(s) to recite""" recite = self.prompt_dialog["segmentedcontrol1"].selected_index if recite == 0: task_id = self._validate_task_id(self.prompt_dialog['textfield1'].text) if task_id: self.prompt_dialog.close() self.current_task = self.tasklist._find_task(task_id) self.speak_task(self.current_task) else: self.prompt_dialog['textfield1'].text = '' self.prompt_dialog['button_select'].enabled = False else: self.prompt_dialog.close() for task in self.tasklist.tasks: self.speak_task(task) speech.say('Recitation complete.', self.language, self.speech_rate) def speak_task(self, task): """""Recite the provided task""" if not task: return if len(task.tags) > 0: fmt = "Task number {}, priority: {}, {}, This task has the following tags: {}" msg = fmt.format(task.id, task.priority, task.note, ' and '.join(task.tags.split())) else: fmt = "Task number {}, priority: {}, {}, This task does not have any tags." msg = fmt.format(task.id, task.priority, task.note) speech.say(msg, self.language, self.speech_rate) [1]: http://github.com/robinsiebler/Task-List
-
when you call
display_speak_options
, you begin editing the text field. Since you set the action of the textfield, whenever you stop editing, it will trigger. I suspect if you click on another control, rather than pressing enter, it will speak too.
So once is from changing focus which ends editing, and the second is from the button itself.Instead of using action for the textfield, I think you want to instead use the
textfield_should_return
method of the delegate, which is only is called when you press Return, not when you change focus. That's not obvious from the docs, but since this is a wrapper around the native library, you can get descriptions of these events from apple -
How exactly would I do that? I added the below code to the TextDelegate() function, but it does nothing.
def textfield_should_return(self, textfield): return True
-
@robinsiebler You'd basically trigger the action from the
textfield_should_return
method, and returnTrue
afterwards.def textfield_should_return(self, textfield): self.process_speak_request(None) return True
(of course, you also have to remove the text field's action, as suggested by JonB)
-
Now I have the below and I get the following error: AttributeError: 'TextDelegate' object has no attribute 'process_speak_request
class TextDelegate(object): def textfield_did_change(self, textfield): view = textfield.superview button = view['button_select'] button.enabled = textfield.text != '' def textfield_should_return(self, textfield): self.process_speak_request(None) <-- AttributeError: ... return True
-
Don't make a special TextDelegate class but instead name your main class (the one that does have a
process_speak_request()
method) as the delegate. Then move the TextDelegate methods over to that main class. -
Thanks! I got that to work.