Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

New GUI dynamically created from script

Discussion in 'UGUI & TextMesh Pro' started by Briksins, Aug 24, 2014.

  1. Briksins

    Briksins

    Joined:
    Jul 15, 2012
    Posts:
    27
    Hello Everyone

    I decide to download new 4.6 Beta and try new GUI :)
    It looks amazing but...

    I should say it is extreme change into opposite direction. Before it was 100% depending on script, now it is fully drawable in Editor and I didn't find any examples of how to handle it from script.

    I found latest documentation in: <install_dir>/Editor/Data/Documentation and there is a lot of explanation of how to draw elements in Editor, what each option mean and so on, also there is "Legacy GUI Scripting Guide" which related to old GUI, but no any scripting explanation to the new GUI, just raw scripting references to the new GUI classes without any examples or anything...

    I'm trying to achieve some kind of dynamic version of GUI. It is not gonna work for me as static GUI designed in Editor.

    Here is the quickest example:
    I dont have any GUI on screen, if I hit "console button" I want new GUI created aka chat box, but without input field, just disabled text area where i can see some custom/internal application logs which i customly create.

    Obviously I Know how to detect key pres in "Update()" method, but what after?
    1)Where should GUI code goes? in "onGUI()" ? or it is related only to old/legacy GUI system?
    2)How do i create GUI elements from script? how to add button or text field from code?
    3) how to set their positions?
    I'm surprised that - this information completely missing and new GUI turned into completely in-Editor design thing...
    Am I misunderstanding some concept or something?
     
    ocimum likes this.
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    It took me a while to get my head around the concept. But in the new system every GUI element is a GameObject. Some implications of this:

    1. You can build GUIs as prefabs and use instantiate to create. Positioning is a little more painful, to position a RectTransform you have to specify four Vector2 (two for the anchor and two for the transform). The math is not overly intuitive, I had to do a fair bit of playing to figure it out. (Tested it works)

    2. You can create GUI elements form scratch by adding the right components to an empty GameObject. (Untested, but should work)

    3. You can create all of your GUI ahead of time graphically. Then use GameObject.SetActive() to choose which elements to show and hide. (Tested it works)
     
    Briksins likes this.
  3. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    556
    In no particular order:

    The Unity staff have mentioned the documentation isn't done yet, with many manual pages, code examples and explanations coming in the future!

    As for how to do it, I suggest taking a look at some of the threads here. There've been quite a few questions asked and answered already, with a decent amount of code samples posted as well.

    OnGUI() is all legacy! You don't even need to use Update to detect a keypress if you want. I suggest watching the official tutorials first; specifically the one(s) about events and triggers.

    Hope that answered at least some of your questions. =) It is all a bit make-shift for now, but hey, that's why it's a beta. ;)

    Cheers!
     
    Briksins likes this.
  4. Briksins

    Briksins

    Joined:
    Jul 15, 2012
    Posts:
    27
    Thank you guys for replay and info
    1) I did watch nearly all videos with tutorials for new GUI, especially was helpful "Buttons" and "Events" handling. got the idea of "onClick" usage.

    2) Creating GUI elements from scratch as GO is kind of overkill? too much stuff to code to add all the components and set some default values for each of them. You know now in Unity Editor upper menu you have options to add new GUI element?
    How can i see what functions does it call on menu click and what does it do in that function? I'm sure there must be already something pre-set in UnityEngine.UI library, however i didn't find any simplifications like "addButton()" or something similar

    3) Creating GUI components as separate elements and store them in prefabs or enable and disable is could be a solution for something simple, like my example with console output, but once it will go to more complex, like replacing buttons on the fly depending on what user clicked, its going to be more difficult.

    I think core library UnityEngine.UI have to include basic methods to create not only raw elements like "UnityEngine.UI.Canvas" or "UnityEngine.UI.Text" but also some basic pre-defined methods like "addButton(<some params>)" to cover whatever available in Editor menu (what is there? 7-8 elements?
    I will do it by my self no problem, but if everyone will have to do it, it will be overkill, i have to be included in librarie

    P.S. Senshi - any chance you could give few links in the forum with code example you mentioned? or at least what were the keywords to search it? I did try to search but there too much result and most of it related to GUI problems in Editor, not in script
     
  5. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,870
    The recommended approach is to create a prefab for various controls (like a prefab for a button) and then from scripting simply instantiate that prefab. We would do this in the GameObject > Create menu too except that there are some technical problems with using prefabs for build-in assets. (Note that when setting the parent of the control from API, you should probably use the Transform.SetParent method with the keepWorldSpace argument set to false.)

    Having built-in methods for creating entire controls (like a button with image and text included) is not something we want to do since it's not very useful in practice. There's a million ways a button can look and be setup. Only text, only image, or both (or even multiple images or text elements). Color tint or sprite or animation transitions. Etc. Using a prefab makes it simple to instantiate a button that is tailored to your needs. A built-in methods in the API wouldn't.
     
    tyoc213 likes this.
  6. Diablo404

    Diablo404

    Joined:
    Mar 15, 2013
    Posts:
    136
    I'm a very beginner in scripting and may not understanding every under aspects of the thing. But, regarding the "There's a million ways a button can look and be setup", I agree but when we click the UI > Create Button on the inspector, we get that little base which gives us a standard basic button. Maybe we could, at least, get this function to be public?
     
    Briksins likes this.
  7. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,870
    The Create > UI menu items are just to get you started. For real work we much recommend to instantiate prefabs instead. This way if you later want to change the look and feel of your UI you can just change the prefab and then it will be reflected in your UI, including dynamically created UI.

    If we provided a method to create the standard UI elements, then anyone using those would be locked in with that look and feel with little options to change it without major work. That's not an approach we wish to lead users down, since it's basically a dead end.
     
    Flickayy likes this.
  8. Briksins

    Briksins

    Joined:
    Jul 15, 2012
    Posts:
    27
    That is kind of weird...
    You have option in Inspector menu to create new UI element. It create basic element - which user can modify in Editor later and you don't see it as dead end, but call the same function from script instead of Inspector menu to create the same base gui object you find as dead end?

    Why this option is not available from script? and how do u see it as dead end if basic option still can be modified through Editor or script? More over there no need to create any functionality, its already created by you and called when UI menu in Inspector used

    I'm wondering if you could tell method names to call?
    Like UI.Text or UI.Button in Editor menu definitely hooked up to some event script which call some method which create basic template GUI object in Scene, I would like to call the same from the script, all other params of the object can be modified through script and u have Script references to the each single class
    It is just not explained how to create/instantiate those classes.
    I don't like idea of making statics prefabs, i need GUI be dynamic and generates on the fly from Code.
    I feel it is 100% possible as u do it in Editor menu on click event
     
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    1. Use the Create>UI>Button to create your button.
    2. Do any major customisation.
    3. Drag into assets folder to create script
    4. Instantiate via script
    5. Use scripting controls to fine tweak the appearance.
    This process is identical to creating any other custom element in Unity. If you really want to duplicate the functions in the editor menu then simply follow the process above without step 2.
     
  10. Briksins

    Briksins

    Joined:
    Jul 15, 2012
    Posts:
    27
    Hello everyone again, continue fight with dynamic GUI creation from script
    as it was suggested I create prefabs of GUI elements and instantiate them

    Here is a problem im facing:
    As i mention above im creating in-app console to be opened on '`' (console key) which should display various internal logs and events of application

    There are few types of logs which are listed in enum file.
    each type should have check box as filter, so if check Box for certain type ticked off, then console will hide all messages related to that type. some kind of simple filtering system.

    The problem is that i don't know how many types of logs there will be (items in enum) or lets imagine it is not enum, but dynamic list of values returned in JSON from server where I need to add check box per each value dynamically

    Here is a quick snippet of my code:
    Code (CSharp):
    1.     //****** omitted ******
    2.     Vector3 localPos = new Vector3(0, 0, 0); //offset for check box position
    3.     //ConsoleLogType - enum with items
    4.     foreach (var name in Enum.GetNames(typeof(ConsoleLogType)))
    5.     {
    6.         //dictionary with all checkboxes (checkbox name, state)
    7.         toggleStates.Add(name, true);
    8.         //instantiate checkbox from prefab
    9.         GameObject toggleBtn = Instantiate(toggleBtnPref) as GameObject;
    10.         //set name to checkbox label
    11.         toggleBtn.GetComponentInChildren<Text>().text = name;
    12.         //assign to parent
    13.         toggleBtn.transform.SetParent(console.transform, false);
    14.         //set position
    15.         toggleBtn.transform.position = console.transform.position + localPos;
    16.         //update offset for next loop cycle
    17.         localPos = toggleBtn.transform.position + new Vector3(100, 0, 0);
    18.         //set event listener
    19.         toggleBtn.GetComponent<Toggle>().onValueChanged.AddListener(this.onCheckBoxClick);
    20.     }
    21.  
    22. }
    23. public void onCheckBoxClick(bool value) //who trigger it????
    24. {
    25.     //not implemented yet
    26. }
    The problem is that on onValueChange event ill get value, but there are no actor mentioned.
    How do i get name of the actor who initiate the event?
     
    hyouuu likes this.
  11. Briksins

    Briksins

    Joined:
    Jul 15, 2012
    Posts:
    27
    Sorry for double post, got an idea to use delegate and it worked like a charmed :)

    here is a solution if that would help anyone:
    Code (CSharp):
    1.             toggleBtn.GetComponent<Toggle>().onValueChanged.AddListener(
    2.                 delegate {
    3.                     this.onCheckBoxClick(toggleBtn.GetComponentInChildren<Text>().text,
    4.                         toggleBtn.GetComponent<Toggle>().isOn);
    5.                 }); //set event listener
    6.         }
    7.  
    8.     }
    9.     public void onCheckBoxClick(string name, bool value)
    10.     {
    11.         Debug.Log("Button: " + name + " is set to: " + value);
    12.     }
     
    viknesh2020, hyouuu, shan_u and 4 others like this.
  12. Indiegangster

    Indiegangster

    Joined:
    Jan 27, 2013
    Posts:
    10
    Thank you guys! Big help
     
  13. Dylfin

    Dylfin

    Joined:
    Mar 7, 2014
    Posts:
    2
    Other solution:
    Code (CSharp):
    1. var newItem = GameObject.Instantiate(this.DefaultCell) as GameObject;
    2. var toggleScript = newItem.GetComponent<UnityEngine.UI.Toggle>();
    3. toggleScript.onValueChanged.AddListener(delegate(bool status) {
    4. this.OnCheckBoxClick(toggleScript, status);
    5. });
     
    hyouuu likes this.
  14. riffraffgames

    riffraffgames

    Joined:
    Apr 26, 2013
    Posts:
    4
    This was huge! Thank you