Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resolved Instantiate a button with parameter?

Discussion in 'Scripting' started by bisewski, Dec 2, 2023.

  1. bisewski

    bisewski

    Joined:
    Jan 16, 2014
    Posts:
    274
    Hi!

    I have one button that I did as prefab.

    I access this prefab in my script as [SerialazeField]. I can instantiante and set the parent.

    But how I will set the parameters on Click? If I have this button in the hierarchy, I just drop my script in that field below the "Runtime Only" and set my the fcuntion and set the paramenter. I have one integer as parameter...

    I use this button to create a list with these buttons. This integer paramenter is used to load a model in a List<GameObject>


    EDIT 1: If I keep this prefab button in the hierarchy objects only set active as false and use it to instantiate, is the half o path...Now to know how change the parameter..

    Thank you
     
  2. bisewski

    bisewski

    Joined:
    Jan 16, 2014
    Posts:
    274
    No, much more easy...or much easier!?!

    myBtn.GetComponent<Button>().onClick.AddListener(delegate { changeModel(3); });
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,312
    The way above is an excellent simple way for one button.

    Sometimes you want to do more than one thing per item:

    - change name
    - change picture
    - connect listener to button?

    This maybe you do when you show a grid of pictures, or grid of choices.

    Enclosed is my approach: I make a custom script to control one item:

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. // @kurtdekker
    7.  
    8. public class OneSingleTile : MonoBehaviour
    9. {
    10.     [SerializeField]Button Button;
    11.     [SerializeField]Text Caption;
    12.     [SerializeField]Image Icon;
    13.  
    14.     public void SetCaptionText( string caption)
    15.     {
    16.         Caption.text = caption;
    17.     }
    18.  
    19.     public void SetIconSprite (Sprite sprite)
    20.     {
    21.         Icon.sprite = sprite;
    22.     }
    23.  
    24.     public void SetButtonDelegate( System.Action action)
    25.     {
    26.         Button.onClick.AddListener(
    27.             delegate {
    28.                 action();
    29.             }
    30.         );
    31.     }
    32. }
    then I put one item in scene, turned off, and us it to make as many as I need in a GridLayoutGroup:

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. // @kurtdekker
    6.  
    7. public class DynamicUIDemo : MonoBehaviour
    8. {
    9.     [Header("This example tile will be cloned.")]
    10.     public OneSingleTile ExemplarTile;
    11.  
    12.     OneSingleTile MakeFreshCopyOfExampleTile()
    13.     {
    14.         // create it and simultaneously parent it to the same place in the UI
    15.         var copy = Instantiate<OneSingleTile>( ExemplarTile, ExemplarTile.transform.parent);
    16.  
    17.         // make it visible
    18.         copy.gameObject.SetActive( true);
    19.  
    20.         return copy;
    21.     }
    22.  
    23.     void Start ()
    24.     {
    25.         // turn off the example first, so it doesn't interfere
    26.         ExemplarTile.gameObject.SetActive( false);
    27.  
    28.         // you choose how to create these, perhaps from a list
    29.         // of known levels, or a list of items, for instance.
    30.  
    31.         // This code searches Resources/DynamicUISprites and loads
    32.         // all the sprites it finds, sorts them by alphabetical
    33.         // name, and displays them in the grid.
    34.  
    35.         var sprites = Resources.LoadAll<Sprite>( "DynamicUISprites/");
    36.  
    37.         Debug.Log( System.String.Format( "I found {0} sprites.", sprites.Length));
    38.  
    39.         // alpha sort by name
    40.         System.Array.Sort( sprites, (a,b) => { return a.name.CompareTo( b.name); });
    41.  
    42.         // now make buttons (tiles) out of each one
    43.         foreach( var sprite in sprites)
    44.         {
    45.             var entry = MakeFreshCopyOfExampleTile();
    46.  
    47.             entry.SetIconSprite( sprite);
    48.  
    49.             entry.SetCaptionText( sprite.name);
    50.  
    51.             // set up what each button does when pressed
    52.             {
    53.                 string textToDisplay = "You clicked on:" + sprite.name;
    54.  
    55.                 entry.SetButtonDelegate(
    56.                     () =>
    57.                     {
    58.                         Debug.Log( textToDisplay);
    59.  
    60.                         // TODO you can call whatever other code you like here...
    61.                     }
    62.                 );
    63.             }
    64.         }
    65.     }
    66. }
    See enclosed for full setup.
     

    Attached Files:

    bisewski likes this.
  4. bisewski

    bisewski

    Joined:
    Jan 16, 2014
    Posts:
    274




    What? The Kurt did a book while I was taking coffee...

    Kurt, why my code doest work? The index i is the same for all buttons. And if I have 2 btns, so 0 and 1 woulb be the index but actually is 2...Is like the index i is updating for all buttons while looping...



    Code (CSharp):
    1. foreach (valuesModel c in SelectedModel.listOfModels[0].selectedModelC)
    2. {
    3.      GameObject n =  Instantiate(buttonCVersions, panelCVersions.transform);
    4.      print(i);
    5.      n.transform.GetChild(0).GetComponent<TMP_Text>().text = c.titleButton;
    6.      n.transform.GetComponent<Button>().onClick.AddListener(delegate { changeModel(i); });
    7.      i++;
    8.      print("ok1");
    9. }
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,312
    Galuner and bisewski like this.
  6. bisewski

    bisewski

    Joined:
    Jan 16, 2014
    Posts:
    274
    I implemented the same idea in your code and work fine!

    Code (CSharp):
    1. int index = 0;
    2. // now make buttons (tiles) out of each one
    3. foreach( var sprite in sprites)
    4. {
    5.     var entry = MakeFreshCopyOfExampleTile();
    6.  
    7.     entry.SetIconSprite( sprite);
    8.  
    9.     entry.SetCaptionText( sprite.name);
    10.  
    11.     // set up what each button does when pressed
    12.     {
    13.         string textToDisplay = "You clicked on:" + sprite.name + " " + index;
    14.  
    15.         entry.SetButtonDelegate(
    16.             () =>
    17.             {
    18.                 Debug.Log( textToDisplay);
    19.  
    20.                 // TODO you can call whatever other code you like here...
    21.             }
    22.         );
    23.     }
    24.     index++;
    25.  
    26. }
     
  7. bisewski

    bisewski

    Joined:
    Jan 16, 2014
    Posts:
    274


    holly mole...Perfect that stuff Kurt...Explain very well.

    Bunny sais: "So it does not read the "value" of the variable when you create the closure but actually accesses the variable itself."

    Kurt said: "C# does "variable capture" instead of value capture"...


    Thank you Sir.
     
    Kurt-Dekker likes this.