Sujan Adhikari
Sujan Adhikari

Reputation: 19

How to know which button was clicked ? (Unity/Hololens2/MRTK)

I have about 10 buttons with each button a unique value added through script. I want to know which button was clicked when interacting with the buttons using MRTK hands.

I have tried adding an updateField method to the button which gets the currently selected object using default EventSystem. However, when i debug the value is null.

public void UpdateField()
{
      int dayNumb = EventSystem.current.currentSelectedGameObject.GetComponent<DayButton>().CurrentNumber();
}

NullReferenceException: Object reference not set to an instance of an object UpdateInputField.UpdateField () (at Assets/Scripts/UpdateInputField.cs:35) UnityEngine.Events.InvokableCall.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:166) UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:58) Microsoft.MixedReality.Toolkit.UI.InteractableOnPressReceiver.OnUpdate (Microsoft.MixedReality.Toolkit.UI.InteractableStates state, Microsoft.MixedReality.Toolkit.UI.Interactable source) (at Assets/MixedRealityToolkit.SDK/Features/UX/Interactable/Scripts/Events/InteractableOnPressReceiver.cs:71) Microsoft.MixedReality.Toolkit.UI.Interactable.InternalUpdate () (at Assets/MixedRealityToolkit.SDK/Features/UX/Interactable/Scripts/Interactable.cs:525) Microsoft.MixedReality.Toolkit.UI.Interactable.Update () (at Assets/MixedRealityToolkit.SDK/Features/UX/Interactable/Scripts/Interactable.cs:506)

Upvotes: 0

Views: 3113

Answers (3)

Sujan Adhikari
Sujan Adhikari

Reputation: 19

Solved it!! I added a listener on each button in the start method. Then called the function to get the components of those objects.

Here is how i did it............

using UnityEngine.UI;
using UnityEngine.EventSystems;
using UnityEditor;
using Microsoft.MixedReality.Toolkit.UI;

public class UpdateInputField : MonoBehaviour {
    public InputField mainInputField;
    private Calendar calendar;
    private GameObject dateCanvas;
    public int dayNumb;

    void Start(){
        var allInteractables = GameObject.FindObjectsOfType<Interactable>();
        foreach (var i in allInteractables)
        {
            i.OnClick.AddListener(() => UpdateField(i));
        }
    }

    public void UpdateField(Microsoft.MixedReality.Toolkit.UI.Interactable index)
    {
        dayNumb = GameObject.Find(index.gameObject.name).GetComponent<DayButton>().CurrentNumber();
        calendar = GameObject.FindObjectOfType<Calendar>();
        mainInputField.text = calendar.ReturnDate(dayNumb);     
    }
}

Upvotes: 1

derHugo
derHugo

Reputation: 90580

Regarding the exception

EventSystem.current.currentSelectedGameObject.GetComponent<DayButton>().CurrentNumber();

offers a lot of possibilities. Basically the reference before each . can possibly by null. Most likely it is either currentSelectedGameObject when simply no object is selected currently or GetComponent<DayButton>() when the selected object simply has no such component.


I know nothing about your classes and very little about MRTK but maybe you could use an event system pattern like e.g.

public class DayButton : WhateverType
{
    // public static event everyone can add listeners to 
    // in order to wait for any DayButton click
    public static event Action<DayButton> OnButtonClicked;

    // Just assuming for now this is the method called on click
    public void OnClick()
    {
        // Fire the static event and inform every listener
        // that this button was clicked by passing yourself in as parameter
        OnButtonClicked?.Invoke(this);
    }
}

Then you could have one (or different) listener classes waiting for the event and checking which button was pressed like

public class SomeListener : MonoBehaviour
{
    privtae void Awake()
    {
        // Add a listener to the global event
        DayButton.OnButtonClicked += HandleOnButtonClicked;
    }

    private void OnDestroy()
    {
        // Make sure to always remove listeners once not needed anymore
        // otherwise you get NullReferenceExceptions!
        DayButton.OnButtonClicked -= HandleOnButtonClicked;
    }

    // By passing the according DayButton reference in you have access
    // to all its public fields and methods
    private void HandleOnButtonClicked(DayButton button)
    {
        Debug.Log("The Button with the name {button.name} and number {button.CurrentNumber} was clicked!", this);
    }
}

Upvotes: 2

Julia Schwarz
Julia Schwarz

Reputation: 2630

The following code will print the name of each button that was clicked in the scene. Note that instead of adding the event listeners on startup, you could just add these listeners when you create your buttons from code.

using Microsoft.MixedReality.Toolkit.UI;
using UnityEngine;

/// <summary>
/// On startup, adds event handlers for every Interactable aka button
/// in the scene that logs the name of the button pressed.
/// You can similarly add such a listener when adding the buttons dynamically
/// </summary>
public class PrintWhichButtonPressed : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        var allInteractables = GameObject.FindObjectsOfType<Interactable>();
        foreach (var i in allInteractables)
        {
            i.OnClick.AddListener(() => Debug.Log(Time.time + ": " + i.gameObject.name + " was clicked"));
        }
    }
}

Upvotes: 2

Related Questions