- Home /
How to execute MenuItem for multiple objects once.
How can I write custom editor MenuItem command so it will be called for all selected objects.
Now it is called for every selected object, but I want to handle all selected objects in one command (through Selection.gameObjects i think) and suppress call for every selected object.
I am getting the same problem. It seems that an issue was filed: https://issuetracker.unity3d.com/issues/customeditor-multiple-fuction-call-from-custom-menuitem-when-calling-from-hierarchy
The solution proposed by gungnir works though.
Answer by gungnir · Feb 05, 2016 at 02:41 AM
Use the parametered version of the method:
static public void MethodName(MenuCommand menuCommand)
{
//Prevent executing multiple times when right-clicking.
if (Selection.objects.Length > 1)
{
if (menuCommand.context != Selection.objects[0])
{
return;
}
}
}
Answer by electric_jesus · Jul 13, 2018 at 03:31 PM
Unfortunately the option above doesn't work if you want to manage selection inside your custom menu method. Here is my workaround:
private static float _lastMenuCallTimestamp = 0f;
[UnityEditor.MenuItem("GameObject/Menu Option", priority = 0)]
private static void YourMenuOption() {
if (Time.unscaledTime.Equals(_lastMenuCallTimestamp)) return;
// place your code here
_lastMenuCallTimestamp = Time.unscaledTime;
}
I've also tried using EditorApplication.timeSinceStartup and Time.timeSinceStartup but I couldn't get a persistent timestamp with those. It seems like timeSinceStartup values are synchronized with the system time and keep updating even when Unity freezes (e.g. when you're trying to apply your custom menu method to a large number of objects).
That is definitely a hack, there has to be a better way.
Well, the Unity $$anonymous$$m themselves acknowledge this 'bug' and have said not planning to do anything about it in fear of breaking code where users rely on the current functionality. And the provide no proper alternative, so I think for the time being this is a perfectly fine workaround.
This answer is (almost) good, but you just need to replace the Time.unscaledTime
with EditorApplication.timeSinceStartup
. Then it properly works in the editor.
I can't believe Unity don't plan on fixing this (or adding an option to ignore the rest of the selection). I'm glad this answer at least works. It is definitely a hacky workaround but I guess that's what you have to deal with when developing on an engine like Unity. Thank you electric_jesus!
(Also EditorApplication.timeSinceStartup didn't work for me either, Time.unscaledTime works fine)
Answer by johnnyjacques · Apr 17, 2020 at 01:19 AM
Another option is to simply deselect the menu items after the first call.
private static void YourMenuOption() {
if (Selection.objects.Length <= 0) return;
// place your code here
Selection.objects = null;
}
It's not the best solution for all use cases though, because if you have a large, painstakingly selected selection, losing that selection after using this tool can be totally not what you want.
Answer by fcnaud · Nov 13, 2020 at 10:12 AM
as @LW said, MenuCommand.context
could be null.
so try this code. Can work both right click and top bar menu.
[MenuItem("GameObject/YourMenuItem", false, 49)]
public static void YourMenuItem(MenuCommand menuCommand)
{
if (ShouldExecute(menuCommand))
{
Debug.Log($"{menuCommand.context} {Selection.activeObject}");
// ... do something
}
}
private static bool ShouldExecute(MenuCommand menuCommand)
{
if (menuCommand.context == null) return true;
if (menuCommand.context == Selection.activeObject) return true;
return false;
}
it could be just one line of code.
Please refer to following.
if ((!menuCommand.context?.Equals(Selection.activeObject)) ?? false) return;
Answer by LW · Jan 18, 2019 at 04:22 PM
Not an answer but crazily enough, if you call the menu item from the top menu bar (Unity 2018.2.19f1) it only calls it once aannndddd the MenuCommand.context
is null... which is probably a bug.