Search Unity

4.6 - How to detect if any GUI element has been clicked on

Discussion in 'UGUI & TextMesh Pro' started by Melang, Aug 21, 2014.

  1. Melang

    Melang

    Joined:
    Mar 30, 2014
    Posts:
    166
    I know how to assign an On Click method to a button, etc... What I want to know, is how to detect if _any_ GUI element has been clicked on.

    For example, if I click somewhere (not on a GUI element), I want the player's target to reset, but if I clicked on some GUI element - a button, a text field, etc I want the target to stay as it is.

    Thanks in advance!
     
  2. tstpierre_nss

    tstpierre_nss

    Joined:
    Jul 3, 2012
    Posts:
    118
    Get the EventSystem component that exists in your scene stored.

    then:

    eventSystem.currentSelectedObject will either be == the GameObject instance last clicked or null
     
    vexe and ben-rasooli like this.
  3. tstpierre_nss

    tstpierre_nss

    Joined:
    Jul 3, 2012
    Posts:
    118
    Interesting to note, it also stores lastSelectedObject as well. I'm guessing you could force them back into an element quasi "modal" if currentSelectedObject goes null and set it back with lastSelectedObject.
     
  4. Melang

    Melang

    Joined:
    Mar 30, 2014
    Posts:
    166
    Thanks, I've also found a post by Tim C where he suggests IsPointerOverEventSystemObject. So I'm gonna use smth like this (it works):

    Code (csharp):
    1.  
    2. using UnityEngine.EventSystems;
    3. void Update () {
    4.  
    5.         if (Input.GetMouseButtonDown(0) )
    6.         {
    7.             if (EventSystemManager.currentSystem.IsPointerOverEventSystemObject())
    8.                 Debug.Log("left-click over a GUI element!");
    9.  
    10.             else Debug.Log("just a left-click!");
    11.         }
    12.  
    13.     }
    14.  
     
    Rachan and chrisbrkt like this.
  5. minirop

    minirop

    Joined:
    Feb 15, 2014
    Posts:
    5
    you can also add an "Event > Event Trigger" component. then "add new > Pointer Click" and you get the same list as the onClick list of a button.
     
    Xikini, krakendono, correia55 and 2 others like this.
  6. TheRobWatling

    TheRobWatling

    Joined:
    Feb 18, 2013
    Posts:
    45
    Thanks as the Above code has got me started.
    How does one detect a specific button press? Say I have 3 buttons that have individual functions.
     
  7. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    You can add a callback via the editor inspector, or via code. See the documentation for UnityEvent if you want more information.
     
  8. Diablo404

    Diablo404

    Joined:
    Mar 15, 2013
    Posts:
    136
    As Tim C explained in this post: http://forum.unity3d.com/threads/button-action-with-arguments.263613/

    You can do it like so ( UnityScript ) :

    Code (JavaScript):
    1. var iconT = (Transform)Instantiate(iconPrefab);
    2. var button = iconT.GetComponentInChildren<Button>();
    3. button.onClick.AddListener( function() {FunctionToCall(myargument);} );
     
  9. TheRobWatling

    TheRobWatling

    Joined:
    Feb 18, 2013
    Posts:
    45
    So before I saw this message I managed to do it the following way.

    I have my three buttons - I have a single script attached to each. The script checks for the object name its attached to so

    Code (CSharp):
    1. if(gameObject.name == "PlayButton")
    2. {
    3. //Play Button Code
    4. }
    5. else if(gameObject.name == "MiscButton")
    6. {
    7. //Misc Code
    8. }
    I then added a onclick event to the button UI and attached the object, then I could use the dropdown to find the function I wanted. It needed to be public but I'm sure Serialized will work too.
     
    devstudent14 likes this.
  10. Diablo404

    Diablo404

    Joined:
    Mar 15, 2013
    Posts:
    136
    Not bad!
     
  11. Ahmadhp

    Ahmadhp

    Joined:
    May 31, 2013
    Posts:
    33
    it's only work in Standalone Input Module class ... should check Allow Activation on Mobile Device property to force it work on touch devices ( where Touch Input Module expected to operate correctly ).
     
    Last edited: Aug 30, 2014
    SomeAlexander likes this.
  12. melkior

    melkior

    Joined:
    Jul 20, 2013
    Posts:
    199
    This post saved me HOURS of greif, thank you all!
     
  13. melkior

    melkior

    Joined:
    Jul 20, 2013
    Posts:
    199
    And now this is not working - the Beta 19 update , they removed access to the EventSystemManager.currentSystem.IsPointerOverEventSystemObject() and you can only do EventSystem.GameObject now .. and this technique does not seem to like that.

    Code (CSharp):
    1.         if (Input.GetMouseButton(0)) {
    2.             if (eventSystem.IsPointerOverGameObject()){
    3.                 //do something
    4.          
    5.             } else {
    6.                 //do something else
    7.             }
    8.         }
    Maybe the guys who removed this in Beta 19 should have read the Frequently Asked Questions and see that people were actually using EventSystemManager ! doh!

    Could be there's another way but I'm very new to Unity and C# so it was not immediately apparent to me.

    EDIT: [SOLVED] the recompile after updating had removed a public reference to the event system causing the problem (so my error)
     
    Last edited: Oct 8, 2014
  14. RKSandswept

    RKSandswept

    Joined:
    Apr 26, 2013
    Posts:
    22
    I did this to make hot key commands get ignored if edting in a text field....

    Code (CSharp):
    1.         if( EventSystem.current.currentSelectedGameObject != null &&
    2.           (EventSystem.current.currentSelectedGameObject.GetComponent<Text>() != null ||
    3.            EventSystem.current.currentSelectedGameObject.GetComponent<InputField>() != null) )
    4.         {
    5.             keyMode = eKeyInputMode.EnteringText;
    6.         }
    7.         else
    8.         {
    9.             keyMode = eKeyInputMode.KeysAreCommands;
    10.         }
    11.  
    Then in code that tests keys I do this....
    Code (CSharp):
    1.  
    2. if(GodClass.keyMode == eKeyInputMode.KeysAreCommands && Input.GetKeyDown(KeyCode.Delete))
    3.  
     
    RenanRL likes this.
  15. TSRajesh

    TSRajesh

    Joined:
    Jun 19, 2013
    Posts:
    69
    Can someone kindly summarize which solution works in b20? IsPointerOverEventSystemObject or IsPointerOverGameObject or something else?
    Thanks a Lot
     
  16. tbg10101_

    tbg10101_

    Joined:
    Mar 13, 2011
    Posts:
    192
    IsPointerOverGameObject might not be what you are looking for since it will be true if you are over a non-GUI GameObject as well.

    I'm going to try to test IsPointerOverEventSystemObject now.


    EDIT 1: IsPointerOverEventSystemObject is no longer available through the vanilla system that Unity provides.

    EDIT2: Adding an EventTrigger to all my buttons to detect mouse enter is a potential option. Unfortunately that seems to break drag-scrolling in ScrollRect so you have to add the EventTrigger to the ScrollRect itself, not the items inside it.
     
    Last edited: Nov 26, 2014
  17. barjed

    barjed

    Joined:
    May 9, 2013
    Posts:
    70
    Has anyone figured out how to do this in b19+?
     
  18. makoto_snkw

    makoto_snkw

    Joined:
    Aug 14, 2013
    Posts:
    340
    Can anyone share some example project where we can touch those GUI elements?
    I'm not sure where to put those codes and when.
     
  19. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,347
    I want to figure out if any GUI-Object has been clicked/touched/changed and what object it is:
    EventSystem is unknown identifier (b15).
    Where is the scripting API for the "EventSystem"?
     
  20. tbg10101_

    tbg10101_

    Joined:
    Mar 13, 2011
    Posts:
    192
    Here is the EventSystem documentation: http://docs.unity3d.com/ScriptReference/EventSystems.EventSystem.html

    What I ended up doing is putting MouseEnter and MouseExit triggers on all my GUI elements that I wanted to track of. Then I keep a reference to what object the cursor is over. Unfortunate that it is not built into Unity but it is pretty powerful when you get a hang of it since you can build dependencies and layers with a custom system.

    So far it is working out well for me.
     
    almo likes this.
  21. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I solved this by handing my raycasting over to the physics raycaster component, and implementing the event system interfaces on everything.
     
  22. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
  23. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    There is also my video tutorial, if anyone is interested.

     
    kdeger, jonno_hopkins, Zaelot and 2 others like this.
  24. Dreamlinker

    Dreamlinker

    Joined:
    Apr 18, 2015
    Posts:
    3
    I know this thread is a bit old and inactive but I thought I can ask here instead of opening a new thread.
    If I use IsPointerOverGameObject, it returns a bool. Now I also want to know which gameobject I'm over. For some reason (on mobile at least) I get a nullreference when I try to get the currentSelectedGameObject, so that's not really working for me.

    My problem is that I'm trying to capture and stop propagation of the event on some of the UI elements, but not all. I.e. buttons should capture and prevent propagation, but other UI elements can be used to interact with the main game.
     
  25. vutruc80

    vutruc80

    Joined:
    Jun 28, 2013
    Posts:
    57
    Just using IsPointerOverGameObject combines with nested CanvasGroup components. Add CanvasGroup in Root Canvas object with parameter:
    Blocking Raycast = false
    and also add it in every ui object handling ui event with parameters:
    Blocking Raycast = true
    Ignore Parent Groups = true
    Hope it helps :)
     
  26. DantaliaN

    DantaliaN

    Joined:
    Oct 7, 2012
    Posts:
    18
    If you have many different UI canvases like me, and you need to detect specific UI canvas, you can use something like this
    Code (CSharp):
    1.  
    2. if (EventSystem.current.IsPointerOverGameObject())
    3.         {
    4.             var pd = new PointerEventData(EventSystem) {position = Input.mousePosition};
    5.             var results = new List<RaycastResult>();
    6.             EventSystem.RaycastAll(pd, results);
    7.             foreach (var result in results)
    8.             {
    9.                 if (IsInLayerMask(result.gameObject, GuiLayer))
    10.                 {
    11.                    //Current canvas
    12.                 }
    13.             }
    14.         }
    15.  
     
    melkior and Major0 like this.
  27. feiting

    feiting

    Joined:
    Oct 26, 2012
    Posts:
    33
    If you select the Event System game object, you get a thing int the lower-right of the inspector during gameplay. Unfortunately all of the detailed information is below the screen, and you can't widen it to see it. Same as the versioning bug where the "This is under SVN" covers that area and you can't do anything to see it, same spot too. This post will save me a lot, thx
     
  28. jvhgamer

    jvhgamer

    Joined:
    Jun 27, 2017
    Posts:
    36
    Just about every single source of information related to this question supplies this line of code as the answer:

    EventSystem.current.IsPointerOverGameObject

    "Simply add this check. It will return true if over a UI element"

    Ok, this is true but, it returns true when over a GameObject as well. Meaning it returns true for UI element clicks and GameObject clicks. Effectively accomplishing the exact opposite of the request by allowing user clicks to propagate through the UI rather then the desired behavior of the UI blocking clicks from passing through it.

    I found success in combining the piece above with something like this:
    Code (CSharp):
    1.     if (UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
    2.     {
    3.         if (UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject != null)
    4.         {
    5.             if (UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject.GetComponent<CanvasRenderer>() != null)
    6.             {
    7.               //setting a boolean here, if it was true this means I clicked on a UI element
    8.               clickingGuiElement = true;
    9.             }
    10.             else
    11.             {
    12.               clickingGuiElement = false;
    13.             }
    14.         }
    15.         else
    16.         {
    17.           clickingGuiElement = false;
    18.         }
    19.     }
    20.     else
    21.     {
    22.       clickingGuiElement = false;
    23.     }
    Then modifying my input code:

    Code (CSharp):
    1.     if (Input.GetMouseButtonDown(0))
    2.     {
    3.         if (Physics.Raycast(ray, out hit))
    4.         {
    5.             if (clickingGuiElement == true)
    6.                 return;
    7.             else
    8.                 // interaction for GOs not on GUI here
    9.         }
    10.     }
     
    Last edited: Nov 21, 2017
    RenanRL likes this.
  29. pradip_spixel

    pradip_spixel

    Joined:
    Jul 11, 2018
    Posts:
    3
    not working on panel
     
  30. vfxjex

    vfxjex

    Joined:
    Jun 3, 2013
    Posts:
    93
    It seems EventSystem is lacking an Interface or Call Back method where if any button or UI events is triggered then the EventSystem is being Call Back.
    something like:

    Code (CSharp):
    1. public void OnEventSystemTrigger (T)
    2. {
    3. "Get Events"
    4. }
    5.  
     
    apostelzhuk likes this.
  31. pmelo

    pmelo

    Joined:
    Oct 30, 2013
    Posts:
    10
    Great thread.
    Here's my helper function, thanks to this post.
    Code (CSharp):
    1.     /// <summary>
    2.     /// Do a null check first, just in case.<code>EventSystem.current != null</code>
    3.     /// </summary>
    4.     private bool MouseOverUIElement
    5.     {
    6.         get
    7.         {
    8.             return EventSystem.current.currentSelectedGameObject != null &&
    9.           EventSystem.current.currentSelectedGameObject.layer == LayerMask.NameToLayer("UI");
    10.         }
    11.     }
     
    Inclusivetech likes this.
  32. Inclusivetech

    Inclusivetech

    Joined:
    Jan 13, 2022
    Posts:
    4
    This doesn't work with panels, probably because a panel is just a rect with an image and it's not a proper ui interactable object. For now I turned my added a button component on my panel. Hideous solution but it works.

    [EDIT]
    Apparently only UI Components that exist in the navigation flow count.
     
    Last edited: Feb 22, 2022