Forum Archive

Delegate example

donnieh

I wanted to make a minimalist example of a working delegate to help me understand them. Please look at my example below and show me how to make this example work.


import ui

tv = ui.TextView()
tv.present()


class MyTextViewDelegate (object):
    def textview_did_begin_editing(self, tv):
        tv.text = 'it worked'

omz

There's basically just one thing missing in your code: You have to create an instance of your delegate class, and then assign it to the delegate attribute of the text view:

import ui

class MyTextViewDelegate (object):
    def textview_did_begin_editing(self, tv):
        tv.text = 'it worked'

tv = ui.TextView()
tv.delegate = MyTextViewDelegate()
tv.present()
donnieh

What if tv was created in a method/function? What is a proper way to access it in a class, especially cause the class is always in the main thread(I believe)? Do I make tv global?

Global seems like the wrong way to do it...

For example will the code below work?:

import ui

class MyTextViewDelegate (object):
    def textview_did_begin_editing(self, tv):
        tv.text = 'it worked'

def update(sender):
    tv = ui.TextView()
    tv.delegate = MyTextViewDelegate()
    tv.present()
JonB

The variable passed to the delegate method is all handled for you -- the thread handling ui events sees that you are trying to edit the textview, and calls the textview's delegate method, with the TextView object as the argument. So the fact that you used tv as the name in both places makes no difference -- you could have twenty textview's on a page all set to the same delegate instance.

I'm not sure if your specific example would work, if update is a Button action for example -- mostly because I'm not sure if you can call present from within a callback like that. You might need @in_background or a ui.delay. Generally, I'd recommend against presenting a new view from within an action, except for popovers. Another option is to have one root view, and replace out the subviews if you want to change what is presented.

Note also that once you present a textview like this (created/presented inside a method), you have no access to that textview anymore except from its delegate methods. That's probably ok.

A common pattern you will see, is that people will make their delegate class the same as their custom View class, then any "shortcut" variables to the various components of the ui can be attributes of your custom class. This keeps things out of the global namespace where they can be accidentally overwritten, but still lets you have easy access to key parts of the ui, without having to traverse the hierarchy in your delegate methods (e.g. you can use self.textview1 instead of tv.superview.superview['panel']['textview1'])

Here's a simple example with two components on a custom root view. Both components are created entirely within the class init method, but are easily accessible (as instance attributes) from the other class methods.


import ui
def MyView(ui.View):
   def __init__(self):
      self.width, self.height = ui.get_screen_size()
      self.tv = ui.TextView(frame=(10,10,400,400))
      self.tv.delegate = self

      self.but = ui.Button(title='Submit', frame=(10,420,100,100), bg_color='red')
      self.but.enabled = False
      self.but.action = self.button_action

      self.add_subview(self.tv)
      self.add_subview(self.but)

   def textview_did_change(self,tv): 
      if tv.text:
         self.but.enabled = True

   def button_action(self, sender):
      console.hud_alert('Message sent')
      self.tv.text = ''    
      sender.enabled = False

v = MyView()
v.present()
donnieh

Thank you for the explanation and your time. I think I get it.

By the way, I tried to run your example and it had an error...