Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Adding onClick listener in Editor script

Discussion in 'UGUI & TextMesh Pro' started by chanfort, Feb 28, 2015.

  1. chanfort

    chanfort

    Joined:
    Dec 15, 2013
    Posts:
    641
    I am trying to add listener, which would react into clicks via this way:

    Code (CSharp):
    1.  UnityEditor.Events.UnityEventTools.AddPersistentListener(myButton.onClick,
    2.     delegate {
    3.         MyFunction();
    4.     }
    5. );
    However, it reports an error:

    Code (CSharp):
    1. ArgumentException: Could not register callback <>m__1E on . The class null does not derive from UnityEngine.Object
    2. UnityEngine.Events.UnityEventBase.ValidateRegistration (System.Reflection.MethodInfo method, System.Object targetObj, PersistentListenerMode mode, System.Type argumentType)
    3. UnityEngine.Events.UnityEventBase.ValidateRegistration (System.Reflection.MethodInfo method, System.Object targetObj, PersistentListenerMode mode)
    4. UnityEngine.Events.UnityEventBase.RegisterPersistentListener (Int32 index, System.Object targetObj, System.Reflection.MethodInfo method)
    5. UnityEngine.Events.UnityEvent.RegisterPersistentListener (Int32 index, UnityEngine.Events.UnityAction call)
    6. UnityEngine.Events.UnityEvent.AddPersistentListener (UnityEngine.Events.UnityAction call)
    7. UnityEditor.Events.UnityEventTools.AddPersistentListener (UnityEngine.Events.UnityEvent unityEvent, UnityEngine.Events.UnityAction call)
    Do I miss something here?
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    IIRC, you want to use AddListener() to add a listener at runtime. AddPersistentListener() is for use in the editor, and won't let you add a listener of a type that you can't normally add through the GUI (hence the complaint that the listener you're adding does not derive from UnityEngine.Object).
     
  3. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,683
    @Antistone is completely correct. Are you trying to add the listener in the Editor or not.

    The main ways for configuring events is:
    • In the editor via the UnityEvent property drawer
    • Through <event>.AddListener(<UnityAction or delegate>) (e.g. onClick.Addlistener(() => Debug.Log("Clicked"));
    • By implementing a script with one of the HANDLER interfaces
    Alternatively is you are trying to instantiate in Editor Script you can use the AddPersistantlistener. However this is really tricky to setup and took me ages to figure out. You can check the UI Extensions bitbucket repo for an example of this in the Editor\UIExtensionsMenuOptions class
    https://bitbucket.org/ddreaper/unit.../Editor/UIExtensionsMenuOptions.cs?at=default
     
  4. chanfort

    chanfort

    Joined:
    Dec 15, 2013
    Posts:
    641
    Yes, exactly, I am making editor, not runtime script. In runtime I know that AddListener() works, but I can't get working it in editor with AddPersistentListener()
     
  5. chanfort

    chanfort

    Joined:
    Dec 15, 2013
    Posts:
    641
    To make things a bit more clear, here is what I am trying to do

    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     UnityEditor.Events.UnityEventTools.AddPersistentListener(myButton.onClick,
    3.         delegate {
    4.             MyFunction();
    5.         }
    6.     );
    7. #endif
    P.S. Thanks for Extension class - it looks really interesting and useful.
     
    uygulamayazilim likes this.
  6. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    Give this a try. Haven't tried it myself, but it should work. Basically, the idea is to create a UnityAction to give as an argument, rather than a delegate.
    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     UnityEditor.Events.UnityEventTools.AddPersistentListener(myButton.onClick, new UnityAction(MyFunction));
    3. #endif
     
    uygulamayazilim likes this.
  7. chanfort

    chanfort

    Joined:
    Dec 15, 2013
    Posts:
    641
    This one works nicely. However, do you know if it would be possible to do something else than call a function, i.e. set gameobject to be inactive like that:
    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     GameObject go = new GameObject("myObject");
    3.     UnityEditor.Events.UnityEventTools.AddPersistentListener(myButton.onClick, new UnityAction(go.SetActive(false)));
    4. #endif
    P.S. What about functions, when I want to pass arguments?
     
    uygulamayazilim likes this.
  8. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    It probably has to be a function, but you can use Anonymous Functions inline if you just have a simple thing you want to do and don't want to write a full formal definition.

    For example, this expression:
    Code (CSharp):
    1. () => go.setActive(false)
    evaluates to a function that takes no arguments and calls go.setActive(false) when invoked. (See Lambda Expressions for more information on this syntax.)

    So you can (probably; untested) write:
    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     GameObject go = new GameObject("myObject");
    3.     UnityEditor.Events.UnityEventTools.AddPersistentListener(myButton.onClick, new UnityAction(() => go.SetActive(false)));
    4. #endif
     
  9. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,683
    If you want a persistent one created for the editor. Check in the UIExtensions bitbucket repo.
    The Editor menu options script (for the combo box control) has the definitions for creating one.
    Took a fair while to piece that together. Enjoy
     
  10. martt_1er

    martt_1er

    Joined:
    Mar 9, 2015
    Posts:
    6
    Hey guys.

    Thanks for pointing the problem.
    But the solution given by @Antistone do not work.

    Code (CSharp):
    1. UnityEditor.Events.UnityEventTools.AddPersistentListener(myButton.onClick, new UnityAction(() => Debug.Log ("hello")))
    Produces the error :

    I just want to give a parameter to know what button has been clicked
     
    Last edited: Apr 8, 2016
  11. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @martt_1er

    Hi, are you trying to create an Editor Script?

    If not then using AddPersistentListener won't work.

    If you need to add listener to a button in non-editor script (runtime) you have to use non-persistent listeners.
     
  12. martt_1er

    martt_1er

    Joined:
    Mar 9, 2015
    Posts:
    6
    Hi @eses, thanks for your answer.
    I'm trying to create an Editor Script.

    My Editor script creates a bunch of Buttons, with predefined values. This is for helping the guy who will integrate the scene (integrator).

    So my Buttons are created at EditorTime, and with AddListener, the OnClick event is lost at RunTime. That's why i'm using AddPersistentListener.

    So i have this method

    Code (CSharp):
    1.  
    2.     public void LaunchGame (GameObject gamePrefab) {
    3.         Debug.Log (gamePrefab);
    4.     }
    5.  
    How to call it using AddPersistentListener ?
     
    Last edited: Apr 8, 2016
  13. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @martt_1er

    I'm relatively new to coding and just learning Editor script
    but you can try something like this.
    I've got no idea if it's the best way.

    I've done something like this with Component Editors not with windows:
    1. Have a method in your MB Script (attached to object).
    2. Create an Editor for it.
    3. There, in OnInspectorGUI, do something like line below.
    4. B is your button, and t is your target (MB Script the editor is for).

    Code (csharp):
    1.  
    2. UnityEventTools.AddPersistentListener(b.onClick, t.MyMethod);
    3.  
     
  14. martt_1er

    martt_1er

    Joined:
    Mar 9, 2015
    Posts:
    6
    thanks @eses, but how do you pass a parameter to t.MyMethod ?

    I have many buttons, but each one correspond to a prefab. When I click on it, I would like to pass the prefab (a GameObject) to MyMethod. Is it possible ?
     
  15. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @martt_1er

    Yep - I noticed that after posting reply ... it actually isn't that simple in that case.

    I did some tests, can't remember what exactly I did, I'd say it's doable yet there seems to be no tutorials around, and manual is very short on information about this stuff...

    EDIT: I'll see if I can find my notes! / unless someone has answer available off the shelf.
     
    Last edited: Apr 8, 2016
  16. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @martt_1er

    I think this should work:

    Code (csharp):
    1.  
    2. UnityAction<GameObject> callback = new UnityAction<GameObject>(t.LaunchGame);
    3. UnityEventTools.AddObjectPersistentListener<GameObject>(b.onClick, callback, t.prefab);
    4.  
    Was that helpful enough? Let me know!
     
    Last edited: Apr 8, 2016
    MaZy, Bugges, Mahunreah and 2 others like this.
  17. martt_1er

    martt_1er

    Joined:
    Mar 9, 2015
    Posts:
    6
    Mister @eses... you saved my night !
    That's exactly what i was searching, and after my buttons generation, their inspector windows are like :


    Thanks, this one will be directly in my notes !
     
    eses likes this.
  18. better_walk_away

    better_walk_away

    Joined:
    Jul 12, 2016
    Posts:
    291
    If the type of the parameter that we want to pass to the function is "MyType", then the code would be like:
    Code (CSharp):
    1. UnityAction<MyType> callback = new UnityAction<MyType>(t.LaunchGame);
    2. UnityEventTools.AddObjectPersistentListener<MyType>(b.onClick, callback, the MyType parameter);
    I was using AddListener(), I thought it would be very straightforward, but it didn't work. Assigning OnClick function to button via custom editor script shouldn't be this complicated.
     
  19. dizzymediainc

    dizzymediainc

    Joined:
    Apr 6, 2014
    Posts:
    389
    It took forever to find this but if you want to simply set the SetActive action for a gameobject use

    Code (CSharp):
    1. UnityEditor.Events.UnityEventTools.AddBoolPersistentListener(button.onClick, someGameObject.SetActive, false);
    false being the true / false state value.

    Honestly it was ridiculous how hard it was to find this answer :p

    Here's some good references for different types

    https://docs.unity3d.com/ScriptReference/Events.UnityEventTools.html
     
    Last edited: Dec 28, 2022