Issues with Buttons: Freezing Canvas and Clearing Data After Execution

Hi everyone,

I’ve been experiencing some issues with buttons in Grasshopper. Occasionally, pressing a button seems to freeze the canvas, making it impossible to interact with or click on anything until I force close and reopen the file. Because of this, I’ve resorted to using the standard Boolean Toggles instead, but they’re not ideal for my current workflow.

In this context, we’re using buttons for operations like:

  • Collecting geometry from Rhino (e.g., when geometry changes, the user needs to re-collect it).
  • Running custom components (using the button as a refresh trigger).

The main advantage of buttons is their temporary “True” state and the need to only click the mouse once, which would ideally act like a one-time refresh. However, once the component which is connected to a button finishes running, the button’s state goes back to “False,” and the data from the component gets wiped clean.

My questions are:

  1. Is there a way to address the glitch where buttons freeze the canvas and prevent interaction?
  2. Is there a method to make buttons retain data in the downstream components even after their state reverts to “False”?
  3. Are there any recommended alternative solutions or approaches that achieve a similar “refresh” functionality without the need for Boolean Toggles?

Any insights or workarounds would be greatly appreciated!

Thanks in advance.

It is a persistent bug from sometime now.

My workaround in C# script components is to control the execution on the data using a boolean declared outside RunScript.

The button toggles the boolean when true and the at end of your script you flip it back.

This also applies to preserving the data. You can pass the result to a variable also declared outside the RunScript method. In python you can also use Sticky data to save anything and make it available in other Script instances

1 Like

Thank you Felipe, I am keen to give this a go. Do you have an example script with this functionality that you would be able to share?

Thanks,
Milo

Hey Milo,

I’ve also experienced the same issue. For me the solution was to enable/disable the group.


  private void RunScript(bool disable)
  {

    Guid target = this.Component.InstanceGuid;

    if(mygroupid == System.Guid.Empty){
      mygroup = (Grasshopper.Kernel.Special.GH_Group) this.GrasshopperDocument.FindObject(mygroupid, true);
      if(mygroup == null || !mygroup.ObjectIDs.Contains(this.Component.InstanceGuid)){
        mygroup = FindFirstGroup(target);
      }
    }

    state = disable;
    GrasshopperDocument.ScheduleSolution(5, Callback);

  }

  // <Custom additional code> 
  public Guid mygroupid = System.Guid.Empty;
  public Grasshopper.Kernel.Special.GH_Group mygroup = null;
  public bool state;

  public Grasshopper.Kernel.Special.GH_Group FindFirstGroup(Guid id){
    List<Grasshopper.Kernel.Special.GH_Group> groups = GrasshopperDocument
      .Objects
      .OfType<Grasshopper.Kernel.Special.GH_Group>()
      .Where(gr => gr.ObjectIDs.Contains(id))
      .ToList<Grasshopper.Kernel.Special.GH_Group>();
    if(groups.Count > 0){return groups[0];}else{return null;}
  }

  private void Callback(GH_Document doc){
    foreach(Guid id in mygroup.ObjectIDs){
      if(!id.Equals(this.Component.InstanceGuid)){
        Grasshopper.Kernel.IGH_ActiveObject obj = (Grasshopper.Kernel.IGH_ActiveObject) this.GrasshopperDocument.FindObject(id, true);
        obj.Locked = state;
        obj.ExpireSolution(false);
      }
    }
  }

I have only used it for Rhino Commands / Resets, not for larger calculations. In case of larger calculations the group might be disabled again before it fulfilled the calculation.

Curious for @Felipe_Penagos 's solution, might be a better one.

1 Like

Here is all that is to it.
The boolean that triggers the action is declared outside. And the data is preserved also by declaring the variable outside RunScript

Not sure if infallible but it works for me

 private void RunScript(bool Activate, double Slider, ref object A)
  {
    if(Activate) Run = true;

    if (Run){
      dataToOutput = "I am available even if Activate is false\nThe slider value is " + Slider.ToString();
      Run = false;
    }

    A = dataToOutput;
  }

  // <Custom additional code> 
  bool Run = false;
  string dataToOutput = null;
  // </Custom additional code> 
}

The drawback is that you lose the output data if you update the code as it declares again the variable as null