1
\$\begingroup\$

Can someone give me an example of programmatically (not using a prefab) creating a button in Unity 5 using C# that has the following features?

  • a text on the button (that I can change)
  • an OnClickListener
  • attached to a script that will store values for the button and contain the OnClick event handler
  • the create method for the button should return a reference to the button so I can modify it at a later point from another script

    My attempt was:

    main.cs

    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    
    public class main : MonoBehaviour {
    
        public Canvas c;
    
        // Use this for initialization
        void Start () {
            createButton ("minion",999);
        }
    
        // Update is called once per frame
        void Update () {
    
        }
    
        //this is giving a button prefab all the methods from the class btnController
        void createButton(string name,int val){
            GameObject go =new GameObject();
            go.AddComponent<btnController>();
            go.transform.SetParent (c.transform,false); //add the gameobject to the canvas
    
    
            go.AddComponent<Button> ();
            //Button btnChild = go.GetComponent<Button> ();
            //btnChild.GetComponent<Text>().text = "hello";//doesnt work
            //go.GetComponentInChildren<Text>().text = "hello!";
    
            btnController bc= go.GetComponent<btnController>(); //get reference to script for this button prefab
            bc.Setup(name,val);//set values in this script for the GameObject to hold
    
            GameObject inst =Instantiate (go);
        }
    
    }
    

    btnController.cs

    using UnityEngine;
    using System.Collections;
    
    public class btnController : MonoBehaviour {
        string name="test";
        int value=6;
    
        //this script is attached to the button prefab. the onClick of the button prefab points to this OnClick method
    
    
        public void Setup(string n, int v){
            this.name = n;
            this.value = v;
            //Debug.Log ("in button setup:"+name+" "+value.ToString());
        }
    
        //OnClick is public so I can set the On Click () function to this method (in the prefab button)
        public void OnClick(){
            Debug.Log("btn clicked: "+this.name+" "+this.value.ToString());
        }
    }
    
  • \$\endgroup\$
    1
    \$\begingroup\$

    You are on the right track with creating a GO and adding a component. Instead of adding a custom button and a base button component, you should just extend the UI.Button. This script will hold custom properties, and exposes the 'Button' component in the UI and for scripting.

    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.EventSystems;
    using UnityEngine.Events;
    using System;
    using System.Collections;
    
    public class ButtonTest : Button, IPointerClickHandler {
    
        private string _text = "Button Text";
        private int _value = 0;
        private Button baseButton;
    
        public Action Callback;
    
        //update button text and stored value
        public string text {
            get{ return _text; }
            set{ GetComponentInChildren<Text>().text = value; _text = value;}
        }
    
        public int value {
            get{ return _value; }
            set{ _value = value; }
        }
    
        void Start(){
            //you can expose onClick and assign a listener
            baseButton = GetComponent<Button>();
            if(onClick != null)
            baseButton.onClick = onClick;
    
            //update label
            baseButton.GetComponentInChildren<Text>().text = text;
        }
    
        //or you can implement click handler and use 'callback'
        override public void OnPointerClick(PointerEventData ped){
            Debug.Log("clicked button");
            Debug.Log("Label: "+this.text);
            Debug.Log("Value: "+this.value);
            if(Callback != null){
                Callback();
            }
        }
    }
    

    Then, when you want to use the button in another script:

    //unique listener
    public void DoStuff(){
        Debug.Log("Hello!");
    }
    
    //unique callback
    public void DoStuff2(){
        Debug.Log("Hello from 2!");
    }
    
    // create object and add component
    GameObject go = new GameObject();
    go.AddComponent<ButtonTest>();
    
    //once you have a reference, you can assign your custom props
    ButtonTest myButton = go.GetComponent<ButtonTest>();
    myButton.text = "Wow New Text";
    
    //using Listener
    myButton.onClick.AddListener( () => { DoStuff2(); } );
    
    //using a callback method
    myButton.Callback = DoStuff;
    

    You don't need to use the Callback if your using 'onClick' and vice versa. I am just demonstrating two way to get notified of button click that is holding custom properties.

    Also, if you want to use 'onClick' instead of a callback, you will need to trigger the base Button click event, with an EventTrigger component.

    Inspector component

    Then you should get both method calls, and your updated properties:

    console result

    Hope this helps some.

    \$\endgroup\$
    -1
    \$\begingroup\$

    Unity has a built-in function GUI.Button that is exactly what you are asking for. GUI elements are unique in unity though because all must be included in a function you create called OnGUI() like so:

    void OnGUI()
    {
        // do stuff
    }
    

    As stated by the unity documentation, GUI.Button at minimum takes in 2 arguments: position (a Rect) and text (a string). The position argument also is the size of the button. You can include other stuff but I'll let you read the documentation for that.

    Now, in order to tell if the button has been clicked, you need to put the GUI.Button as the condition of an if statement (weird, I know). So for example if I wanted to create a square button I would do the following:

    void OnGUI()
    {
        // Remember Rect parameters are x, y, width, height
        if (GUI.Button(new Rect(50, 50, 100, 100), "Click Me!")
        {
            Debug.Log("Oh yeah it feels so good to be clicked!!!!");
            // Do other stuff like increment a global variable
        }
    }
    

    Now, I don't believe you can return a reference to the button as it is a function and not a structure, however, you can just have global variables like buttonText and buttonRect that you use in the function (i.e. GUI.Button(buttonRect, buttonText)) and then just change those global variables in another function when you want the button information to change. Also these global variables can just be public if you want to modify them from another script or you could just do some simple encapsulation (that means having SetButtonText() and GetButtonText() functions).

    \$\endgroup\$
    • 2
      \$\begingroup\$ This is really only for Unity 3.5 or less. GUI is now legacy , use UnityEngine.UI instead. \$\endgroup\$ – dval Jan 24 '16 at 8:37

    Your Answer

    By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

    Not the answer you're looking for? Browse other questions tagged or ask your own question.