x


How does GUI.Toggle work?

I have a level editor with a test button that I want to change into a toggle button - I want it to turn on when pressed and stay on until pressed again. Currently I have a setup like this

 //In variable declaration
 private bool testButtonToggle = false; //Off by default
 
 //In OnGUI()
 if (GUI.Toggle(testButtonRect, testButtonToggle, "", testToggleStyle)) {
      Debug.Log("Toggle code block ran: " + testCounter + " times!");
      if (testButtonToggle)
      {
             testButtonToggle = false;
             //Turn off test mode
      }
      else if (!testButtonToggle)
      {
             testButtonToggle = true;
             //Turn on test mode
      }
      testCounter++;
 }

With it coded that way, it stays toggled on when you first press it and while you hold down the mouse button, but as soon as the mouse goes up it toggles off instantly. That led me to think that when you give a Toggle a bool parameter it automatically toggles it when it is pressed, but that makes it function like a normal button and it will only run the 'else if (false)' block.

more ▼

asked Dec 07, 2012 at 08:24 PM

MibZ gravatar image

MibZ
415 36 35 44

(comments are locked)
10|3000 characters needed characters left

2 answers: sort voted first

Just in addition to Eric's answer:

A Toggle just switches between two states. It doesn't have something like "onMouseDown" or "onMouseUp" events. It just turns the variable on when you click it once (and it stays on) and when you click again it turns off again (and stays off)

 private bool testButtonToggle = false;
 
 void OnGUI()
 {
     testButtonToggle = GUI.Toggle(testButtonRect, testButtonToggle, "", testToggleStyle);
     if (testButtonToggle)
     {
         // Do something when it's toggled on, for example draw addtional GUI elements:
         if (GUI.Button(...))
         {
             //...
         }
     }
 }

I have to admit that the example on the Toggle page is terrible.

*edit*
Just read your comment above. Well The problem is OnGUI is ment for GUI element / event processing and might get called several times per frame. If you want to execute code every frame you should do it like this:

 private bool testButtonToggle = false;
 
 void OnGUI()
 {
     testButtonToggle = GUI.Toggle(testButtonRect, testButtonToggle, "", testToggleStyle);
 }
 
 void Update()
 {
     if (testButtonToggle)
     {
         // Do something when it's toggled on
     }
     else
     {
         // Do something else when it's toggled off.
     }
 }

*edit2*:

To detect a state change you just have to store value of your state variable from the last frame and compare it with the current. If it's different a change has occurred.

 private bool testButtonToggle = false;
 private bool oldTestButtonToggle = false;
 
 void OnGUI()
 {
     // Responsible for the state change
     testButtonToggle = GUI.Toggle(testButtonRect, testButtonToggle, "", testToggleStyle);
     // When the two variables are uneven a change has occurred. Either has been turned
     // on or off this frame
     if (testButtonToggle != oldTestButtonToggle) 
     {
         if (testButtonToggle)
         {
             // on event
         }
         else
         {
             // off event
         }
     }
 }

With a toggle you can simplify it like this:

 private bool testButtonToggle = false;
 
 void OnGUI()
 {
     if (GUI.Toggle(testButtonRect, testButtonToggle, "", testToggleStyle) != testButtonToggle)
     {
         testButtonToggle = !testButtonToggle; // toggle manually
         if (testButtonToggle)
         {
             // on event
         }
         else
         {
             // off event
         }
     }
 }

Now the toggle works just like a normal button. The only difference is that you have an active state which changes it's visual appearence.

more ▼

answered Dec 07, 2012 at 09:38 PM

Bunny83 gravatar image

Bunny83
77.8k 26 106 335

I know that it doesn't have mouse events, I described it that way because the way it is behaving the different ways I've tried it don't make sense.

And I don't want the code to run every frame, I placed it inside the if statement around the toggle call because I only want it to run when the state is changed, and all the buttons I've ever made worked that way just fine.

From my understanding the code inside the if block will only run when the GUI control inside the if statement is pressed, and from there it will run the true block or the false block alternatively. Like a light switch that is a push button instead of a lever.

Dec 07, 2012 at 09:49 PM MibZ

There's a huge difference between a Button and a toggle. A Button will execute an event when it's pressed. A Toggle changes a state. I will add another example how to detect a state change. This is actually irrelevant for GUI since it always works the same way.

I'll add another example specific for a GUI.Toggle.

Dec 07, 2012 at 10:09 PM Bunny83

Alright, so what I was trying was wrong. Thanks for your help gentlemen!

Dec 07, 2012 at 10:45 PM MibZ
(comments are locked)
10|3000 characters needed characters left

Please see the example in the docs; you assign the result of GUI.Toggle to a variable.

more ▼

answered Dec 07, 2012 at 08:58 PM

Eric5h5 gravatar image

Eric5h5
111k 55 185 669

How would I do that and still be able to place the GUI call in an if statement? Like so?

if (testButtonToggle = GUI.Toggle(testButtonRect, testButtonToggle, "", testToggleStyle))

Well I tried that and it runs the code inside the if block every tick. On top of that it seems wrong to me - to have an assignment in an if statement seems programatically illogical because it isn't a comparison.

After that I tried adding 'testButtonToggle = GUI.Toggle(identical parameters)' at the end of the if block, but it never assigns any value to the bool.

After that I tried adding it after the if block, but then it toggles to true and never toggles back to false even when pressed again.

Finally I tried adding "testButtonToggle = GUI.Toggle(...);" before the original code (if (testButtonToggle = GUI.Toggle(...)); and in that case it toggles to true from the first Toggle, runs the true block inside the if statement every tick, and never toggles back to false even when clicked.

Why so difficult >.>

Dec 07, 2012 at 09:25 PM MibZ

All I want is a button that toggles on/off (I have different textures for each) with an if statement around it to run code only when it is clicked, one block for true, one block for false.

Like my snippet, except...you know. Functional.

Can I do that?

Dec 07, 2012 at 09:27 PM MibZ

Just check to see if the variable changed. You can also potentially use GUI.changed, though that depends on the circumstances.

Dec 07, 2012 at 09:44 PM Eric5h5

I am checking if it changed, the problem is that I apparently don't get how it is supposed to work because none of the ways I have tried behave in ways that make sense.

Dec 07, 2012 at 09:50 PM MibZ
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x5873
x254
x5

asked: Dec 07, 2012 at 08:24 PM

Seen: 5515 times

Last Updated: Dec 07, 2012 at 10:45 PM