0
\$\begingroup\$

I've got a script that manages a scene browser within my application where I'm hoping to generate a new button instance for each scene found. I've put together a button that I've made into a prefab and everything works up until I try to attach click behavior to the button. So far I am unable to capture or attach anything to the "onClick()" piece of the button component no matter what I try.

Code is as follows:

MySceneBrowser.cs
   foreach(string sceneName in sceneList){
     GameObject sceneButton = Instantiate(SceneButton) as GameObject;
     // Attach the scene name to the nested text UI object of the button
     sceneButton.GetComponentInChildren<Text>().text = sceneName; 
  /* Where I hope to attach script and method with parameter, method is within 
   * this class and called LoadSelectedScene(string sceneName)
   */
     sceneButton.transform.SetParent(SceneListPanel, false);
     }

Where in the inspector SceneButton is assigned to the prefab I've created, SceneListPanel is set to a content panel, and the scene list is generated in another method.

Any attempt I make to get the button component and allow me to set the onclick() fails, it just doesn't seem to exist through the script editor.

Setting any of these items through the inspector works, but I can't assign my controller class to the prefab before RunTime. I tried attaching a script directly to the prefab, but in this case only MonoBehavior functions were present through the inspector and I was unable to find any other method.

Once I attach the script I also need to be able to add the sceneName as the parameter.

[Edit] DMGregory pointed out I didn't elaborate on what I've tried so far, at this time I've tried the following (likely very wrong, still new to Unity) attempts to attach the desired script method:

  • sceneButton.AddComponent< SceneBrowserController >().LoadSelectedScene(sceneName);
  • Button b = sceneButton.GetComponent< Button >(); b.OnClick()...<--- Script can't find onClick, doesn't exist, doesn't show it as an option in code completion, etc.
  • sceneButton.AddComponent< SceneBrowserController >.LoadSelectedScene(sceneName); <-- obviously doesn't add it to the onClick listener, just attaches the script
  • SceneButton.AddComponent< UIEventListener >()....
  • UIEventListener.Get(sceneButton).onClick().....

This is in general the attempts I've made so far, with some variation. I don't have all my old attempts saved unfortunately. I'm sure I'm making a newbie assumption/mistake somewhere.

While playing with the prefab through my script I went ahead and tried this out:

if(sceneButton.GetComponent< Button >()){
Debug.Log("This object is here");
}

and it returns false on the if, if I change the if to (!sceneButton.GetComponent()) it does show the log message. To my understanding this indicates the button game object is not found, yet it is a component on the top level of the prefab.

Also, can anyone explain why this doesn't work to attach the onclick listener?

sceneButton.GetComponentInChildren<Button>().OnClick.AddListener(() => LoadSelectedScene(scene));

Gives the following compiler error:

Assets/.../.../.../SceneBrowser.cs(347,68): error CS1061: Type `Button' does not contain a definition for `OnClick' and no extension method `OnClick' of type `Button' could be found (are you missing a using directive or an assembly reference?)

As close to showing my full code as possible:

using UnityEngine;
using UnityEngine.UI;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

public class MyFileBrowser : MonoBehaviour
{
 Public GameObject SceneButton; // This is assigned to the prefab in inspector, they render properly.
 [...]

 public void LoadSelectedScene(string sceneName){
  // This is the method I'm hoping to reference in the onClick listener, while passing it the scene name
 }

[...]

private void DisplaySceneList(string[] scenesOutput){

   foreach(string sceneName in sceneList){
     GameObject sceneButton = Instantiate(SceneButton) as GameObject;
     // Attach the scene name to the nested text UI object of the button
     sceneButton.GetComponentInChildren<Text>().text = sceneName; 
  /* Where I hope to attach script and method with parameter, method is within 
   * this class and called LoadSelectedScene(string sceneName)
   */
     // Current attempt:
     sceneButton.GetComponent<Button>().onClick.AddListener(() => LoadSelectedScene(sceneName));
    // The onClick.AddListener[...] is all red in MonoDevelop, hover message says "'Button' does not contain a definition for 'onClick'


     sceneButton.transform.SetParent(SceneListPanel, false);
     }

}

This is with a prefab with the following structure:

  • SceneBrowser_SceneSelectButton (Image Component, Button Component, Layout Element Component)
    • Scene Image (Image component w/ sprite)
    • Scene Label (Text component)

I can access the Scene label no trouble with "GetComponentInChildren< Text >.text [...]" but cannot get "GetComponent< Button > on the sceneButton object created from this prefab. Oddly, "GetComponent< Image > does capture the image component off the top level object just fine.

\$\endgroup\$
  • \$\begingroup\$ "Any attempt I make...fails" — can you be more explicit here and describe what you've tried and what error/failure occurred? There are a few obvious possibilities one could suggest, but someone wanting to answer doesn't know whether you've already tried those methods and found they don't work because of some details in your setup. \$\endgroup\$ – DMGregory Jul 22 '15 at 23:09
  • \$\begingroup\$ Good call, I've updated the question contents to include a few of the attempts I've made \$\endgroup\$ – Miguet Schwab Jul 23 '15 at 13:02
  • \$\begingroup\$ I presume you've elided the argument or type parameter on the Add/GetComponent calls? Or did you try them exactly as written? (Exact code is kind of important — we don't know what you've left out for brevity vs what you may actually have forgotten to include, causing the error) \$\endgroup\$ – DMGregory Jul 23 '15 at 13:09
  • \$\begingroup\$ I will fully admit to the possibility that I've left out some basic item in my code, I am new to C# and to Unity. \$\endgroup\$ – Miguet Schwab Jul 23 '15 at 13:14
  • \$\begingroup\$ Direct question here, why doesn't this call work , everything onClick and forward is in red. I've added a new button object as a child on the prefab so it should find that the way it did when I pulled up text (Shown in the original question) sceneButton.GetComponentInChildren<Button>().onClick.AddListener(() => LoadSelectedScene(dir)); \$\endgroup\$ – Miguet Schwab Jul 23 '15 at 13:40
0
\$\begingroup\$

we can't able to assign onclick() function on run time. so use event system to declare your function. This ll shows you how to use event listener for a button

Edit 1: Declare the header for scene management

using UnityEngine.SceneManagement;

initialise the scene

Scene m_Scene;

Remove this line

sceneButton.GetComponentInChildren<Text>().text = sceneName;

Replace as

m_Scene = SceneManager.GetActiveScene();

sceneButton.GetComponentInChildren<Text>().text = m_Scene.name;

Then remove this line

sceneButton.GetComponent<Button>().onClick.AddListener(() => LoadSelectedScene(sceneName));

Replace as

sceneButton.GetComponent<Button>().onClick.AddListener(() => LoadSelectedScene(m_Scene.name));
\$\endgroup\$
  • 2
    \$\begingroup\$ This answer would be better if it summarized the method described at the link inside the body of the answer itself. That way even if the Unity Answers link changes, becomes unavailable, or the content on that site gets vandalized, the information will remain accessible here. \$\endgroup\$ – DMGregory Jun 18 '18 at 17:10
  • \$\begingroup\$ Link says to use button.onClick.addEventListener which is in direct contradiction to your answer. And also you're wrong. \$\endgroup\$ – Draco18s Dec 7 '18 at 4:46

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.