- Home /
EditorGUILayout.ColorField inside GUILayout.Window causes ExitGUIException
I'm coding an EditorWindow. My problem is, when I use a EditorGUILayout.ColorField inside a GUILayout.Window, an ExitGUIException occurs when I click onto the color field.
I was able to boil down the problem to the following script:
using UnityEngine;
using UnityEditor;
public class TestEditor : EditorWindow
{
Color mColor = Color.green;
[MenuItem ("Test/TestEditor")]
static void Init()
{
EditorWindow.GetWindow( typeof( TestEditor ) );
}
public void OnGUI ()
{
BeginWindows();
GUILayout.Window ( 7, new Rect( 100, 100, 300, 50), DoWindow, "Window" );
EndWindows();
}
void DoWindow( int id )
{
mColor = EditorGUILayout.ColorField("Click here -->", mColor);
}
}
When I open the test editor and click on the color field, the following error occurs:
ExitGUIException: Exception of type 'UnityEngine.ExitGUIException' was thrown. UnityEngine.GUIUtility.ExitGUI () (at C:/BuildAgent/work/812c4f5049264fad/Runtime/ExportGenerated/Editor/GUIUtility.cs:95) UnityEditor.EditorGUI.DoColorField (Rect position, Int32 id, Color value, Boolean showEyedropper, Boolean showAlpha) (at C:/BuildAgent/work/812c4f5049264fad/Editor/MonoGenerated/Editor/EditorGUI.cs:2222) UnityEditor.EditorGUI.ColorField (Rect position, UnityEngine.GUIContent label, Color value) (at C:/BuildAgent/work/812c4f5049264fad/Editor/MonoGenerated/Editor/EditorGUI.cs:2201) UnityEditor.EditorGUI.ColorField (Rect position, System.String label, Color value) (at C:/BuildAgent/work/812c4f5049264fad/Editor/MonoGenerated/Editor/EditorGUI.cs:2198) UnityEditor.EditorGUILayout.ColorField (System.String label, Color value, UnityEngine.GUILayoutOption[] options) (at C:/BuildAgent/work/812c4f5049264fad/Editor/MonoGenerated/Editor/EditorGUI.cs:3834) TestEditor.DoWindow (Int32 id) (at Assets/Editor/TestEditor.cs:23) UnityEngine.GUILayout+LayoutedWindow.DoWindow (Int32 windowID) (at C:/BuildAgent/work/812c4f5049264fad/Runtime/ExportGenerated/Editor/GUILayout.cs:317) UnityEngine.GUI.CallWindowDelegate (UnityEngine.WindowFunction func, Int32 id, UnityEngine.GUISkin _skin, Int32 forceRect, Single width, Single height, UnityEngine.GUIStyle style) (at C:/BuildAgent/work/812c4f5049264fad/Runtime/ExportGenerated/Editor/GUI.cs:1023) UnityEditor.EditorWindow:BeginWindows() TestEditor:OnGUI() (at Assets/Editor/TestEditor.cs:16) UnityEditor.DockArea:OnGUI()
The error does not occur if I write the EditorGUILayout.ColorField simply into OnGUI instead of a window. Also, other fields like EditorGUILayout.CurveField or EditorGUILayout.FloatField don't cause any problems.
What am I doing wrong?
I am having this same problem. However the curve is giving me issues as well. Have you found the answer?
Answer by guavaman · Aug 29, 2013 at 12:58 AM
The problem: ExitGUIException thrown when clicking the color picker on a color field or the "Select" area on any object field.
Edit: Updated based on important information from @Bunny83's comments.
Unity throws this ExitGUIException EVERY time one of these controls is clicked. This exception is used by Unity and needs to be propagated. If you have wrapped the control in a try/catch statement (including upstream), it will catch the exception. If you don't have any try/catch statements, you'll never even see this exception thrown.
Any Try/Catch blocks around or upstream of a ColorField or ObjectField must propagate the ExitGUIException to allow Unity to receive it.
try {
// code
} catch (UnityEngine.ExitGUIException) {
throw;
} catch (System.Exception e) {
// Handle the exception
}
This is super annoying and incredibly still unsolved. Try-catch is fundamental around big blocks of editor code imho, because that way you can have the fundamental parts still work in case an exception happens (so you can fix it via the visual editor itself and then work on the bug).
You can catch exceptions, but make sure the ExitGUIException will propergate through. The point of this exception is (as it's name suggests) to exit the current GUI code. This is required in some special cases. See my comment below Glurth answer.
In case of GUI,Window / GUILayout.Window i'm not sure if there's an actual workaround. You can try catching ExitGUIException right at the top of your window callback and swallow it. If it still throws an InvalidOperationException there's no workaround. The best thing you can do is let Unity catch the ExitGUIException and live with it. $$anonymous$$aybe they fix the issue some day ^^.
Though I'm sure that the priority of editor issues is lower than engine issues. Also the usage of GUI.Windows inside editor code is a very rare case. So depending on how complicated the fix might be i wouldn't bet it's fixed any time soon. ^^
If you think it's important that it get fixed, file a bug report yourself. $$anonymous$$ake sure you attach a sample project that reproduces the problem with some easy to follow instructions how to reproduce the problem. The more bug reports they get about a certain issue the more likely they will fix it :)
Thanks Bunny :) I found a workaround in the meantime, but it's still annoying. And by the way, it doesn't happen only with GUI.Windows, since I don't have any but I have the issue anyway. Still, not a biggie after all.
Answer by Glurth · Jul 12, 2016 at 07:03 PM
I unexpectedly ran into this error the other day, and found this post. But since the issue had NOTHING to do with try/catch blocks, I figured I'd share what it was, though probably a rare issue.
My problem seemed to have something to do with HOW my editor GUI function was invoked. In particular, I was using reflection to find a particular function that I wanted. The result was stored in a System.Reflection.MethodInfo variable.
If I called Invoke() on that variable, the exception was generated.
method.Invoke(null, null);
However, if I converted the MethodInfo into a Delegate, and then called the delegate, the exception vanished.
public delegate void PreferencesGUI();
PreferencesGUI func = (PreferencesGUI)Delegate.CreateDelegate(typeof(PreferencesGUI), method);
func();
Honestly, I'm not quite sure what the internal difference between these two invocation methods is, nor why it should generate an exception. Update: answered in bunny's comment below
@Bunny83 : thought you might find this interesting/good to know. Update: thank you!
[1]: http://stackoverflow.com/questions/4117228/reflection-methodinfo-invoke-catch-exceptions-from-inside-the-method
The answer to this is pretty simple ^^. You usually shouldn't receive a ExitGUIException in normal setups.
First of all lets look at where that exception comes from. It's actually raised on purpose by the GUIUtility.ExitGUI()
method which literally just does this:
public static void ExitGUI()
{
throw new ExitGUIException();
}
So what's the point of this method / exception? The answer is simple. In some cases it's necessary to ter$$anonymous$$ate the current GUI execution to prevent either corruption or unpredictable results. This is usually necessary if you open a new window (actual standalone window, not a GUI.Window) from GUI code. It also might be necessary if the displayed content is changed during the execution and otherwise it might break the layout system. Since ColorField opens a seperate EditorWindow it uses ExitGUI when the field actually opens the window.
Usually Unity catches the exception itself silently. So in other words it's like OnGUI and OnInspectorGUI are implicitly wrapped in try-catch statements.
The reason why the exception isn't catched when using reflection is explained here on SO.
The reason in the original question seems to depend on the way how GUI.Windows are handled. The GUI.Window callbacks actually aren't called from the OnGUI method but later directly by Unity. It seems Unity somehow missed to catch the exception in this special case.
ExitGUI is usually ment to be only used internally by Unity since it's not documented. But since it's used implicitly inside documented methods you could rank this behaviour as bug.
Answer by jwyoo_stone · Apr 20, 2013 at 02:19 AM
I am having the same problem in custom inspector,when I use a reflector method to invoke a generic method to create a object type filed(e.g. colorField,CurveField,ObjectFiled...).
private static Color DoColorField(Rect position, int id, Color value, bool showEyedropper, bool showAlpha)
{
Event current = Event.current;
GUIStyle colorField = EditorStyles.colorField;
Color color = value;
value = !showMixedValue ? value : Color.white;
EventType typeForControl = current.GetTypeForControl(id);
switch (typeForControl)
{
case EventType.KeyDown:
if ((GUIUtility.keyboardControl == id) && (((current.keyCode == KeyCode.Space) || (current.keyCode == KeyCode.Return)) || (current.keyCode == KeyCode.KeypadEnter)))
{
Event.current.Use();
showMixedValue = false;
ColorPicker.Show(GUIView.current, value, showAlpha);
GUIUtility.ExitGUI();
}
return color;
case EventType.Repaint:
Rect rect;
if (!showEyedropper)
{
rect = position;
}
else
{
rect = colorField.padding.Remove(position);
}
if (showEyedropper && (s_ColorPickID == id))
{
Color pickedColor = EyeDropper.GetPickedColor();
pickedColor.a = value.a;
EditorGUIUtility.DrawColorSwatch(rect, pickedColor, showAlpha);
}
else
{
EditorGUIUtility.DrawColorSwatch(rect, value, showAlpha);
}
if (showEyedropper)
{
colorField.Draw(position, GUIContent.none, id);
return color;
}
EditorStyles.colorPickerBox.Draw(position, GUIContent.none, id);
return color;
}
if (typeForControl != EventType.MouseDown)
{
if ((typeForControl == EventType.ExecuteCommand) && (GUIUtility.keyboardControl == id))
{
int num;
string commandName = current.commandName;
if (commandName == null)
{
return color;
}
if (<>f__switch$map10 == null)
{
Dictionary<string, int> dictionary = new Dictionary<string, int>(4);
dictionary.Add("EyeDropperUpdate", 0);
dictionary.Add("EyeDropperClicked", 1);
dictionary.Add("EyeDropperCancelled", 2);
dictionary.Add("ColorPickerChanged", 3);
<>f__switch$map10 = dictionary;
}
if (!<>f__switch$map10.TryGetValue(commandName, out num))
{
return color;
}
switch (num)
{
case 0:
HandleUtility.Repaint();
return color;
case 1:
{
GUI.changed = true;
HandleUtility.Repaint();
Color lastPickedColor = EyeDropper.GetLastPickedColor();
lastPickedColor.a = value.a;
s_ColorPickID = 0;
return lastPickedColor;
}
case 2:
HandleUtility.Repaint();
s_ColorPickID = 0;
return color;
case 3:
GUI.changed = true;
HandleUtility.Repaint();
return ColorPicker.color;
}
}
return color;
}
if (showEyedropper)
{
position.width -= 20f;
}
if (position.Contains(current.mousePosition))
{
GUIUtility.keyboardControl = id;
showMixedValue = false;
ColorPicker.Show(GUIView.current, value, showAlpha);
GUIUtility.ExitGUI();
}
if (showEyedropper)
{
position.width += 20f;
if (position.Contains(current.mousePosition))
{
GUIUtility.keyboardControl = id;
EyeDropper.Start(GUIView.current);
s_ColorPickID = id;
GUIUtility.ExitGUI();
}
}
return color;
}
The source code of DoColorField There are there calls of "GUIUtility.ExitGUI()" can cause the exception I can't what can cause this.
Answer by Seneral · Aug 05, 2015 at 08:08 PM
This is still bugging me. If you can, change the catch block so you just catch UnityException's:
try
{
}
catch (Exception e)
{
Debug.LogException(e);
}
// Instead of
try
{
}
catch (UnityException e)
{
Debug.LogException(e);
}
Answer by buronix · Sep 27, 2016 at 10:39 AM
I needed to handle the exceptions, so my solution was:
try
{
//Your Code
}
catch (Exception e)
{
if(e.GetType() != typeof(ExitGUIException))
{
//The exception is real, handle here
Debug.LogException(e);
}
}
}
Your answer
Follow this Question
Related Questions
How to duplicate scene gizmo? 0 Answers
Setting up a key to cycle through editor modes 0 Answers
NullReferenceException help 1 Answer
manager not defined 1 Answer