Block Shape Update issue

109 views
Skip to first unread message

Jason Farris

unread,
Jun 4, 2023, 5:00:39 PM6/4/23
to Blockly
The code provided below is SO close to working the way I want it to.  The behavior of the block works, however, the shape does not update unless I move the block on the workspace.

The block behavior should be:
In Toolbox:  checkbox is false and variableInput is hidden
Initial placement on workspace:  checkbox is false and variableInput is hidden
When on workspace:  when checkbox = true, variableInput is shown
when checkbox = false, variableInput is hidden

Here's the block definition and the Python generator (which i realize has no 'code' in it).  I'll work out the Python stuff after the block works the way it's supposed to.

Blockly.Blocks['custom_block'] = {
    init: function() {
      var block = this;
 
      this.appendDummyInput()
          .appendField("Wait ")
          .appendField(new Blockly.FieldNumber(0, 0, 23, 1), "hours")
          .appendField("H  ")
          .appendField(new Blockly.FieldNumber(0, 0, 59, 1), "minutes")
          .appendField("M  ")
          .appendField(new Blockly.FieldNumber(0, 0, 59, 1), "seconds")
          .appendField("S  ")
          .appendField(new Blockly.FieldNumber(0, 0, 999, 1), "milliseconds")
          .appendField("ms     ");
 
      this.appendDummyInput("showOnRunInput")
          .appendField("Show on Run Screen:")
          .appendField(new Blockly.FieldCheckbox("FALSE", function(value) {
            block.updateShape_(value === 'TRUE');
            block.setCollapsed(false); // Force an update to fix rendering issues
            block.render(); // Render the block to update its shape
          }), "checkbox");
 
      this.appendDummyInput("variableInput")
          .appendField("Select Timer Alias:")
          .appendField(new Blockly.FieldVariable("Timer Alias"), "TimerAlias")
          .setVisible(false);
 
      this.setPreviousStatement(true, null);
      this.setNextStatement(true, null);
      this.setColour(230);
      this.setTooltip("");
      this.setHelpUrl("");
 
      // Delay the rendering process until after the block is initialized
      setTimeout(function() {
        block.updateShape_(block.getFieldValue('checkbox') === 'TRUE');
      }, 0);
    },
 
    updateShape_: function(value) {
      var variableInput = this.getInput('variableInput');
 
      // Check if the block is in the toolbox and the checkbox is false
      var isInToolbox = this.isInFlyout || (this.workspace && this.workspace.isFlyout);
      variableInput.setVisible(!isInToolbox && value);
 
      // Rerender the block to update its shape
      if (this.rendered) {
        this.render();
      }
    }
  };
 
  Blockly.Python['custom_block'] = function(block) {
    // Generate Python code for the block.
    // You can customize this function to define the desired behavior.
    var code = '...';
    return code;
  };

Jason Farris

unread,
Jun 4, 2023, 5:35:32 PM6/4/23
to Blockly
I apologize.  I pasted the incorrect code in the original statement.

Below is the correct code where everything works as I want it to, except I have to move the block on the screen before it will update its shape.

Blockly.Blocks['custom_block'] = {
    init: function() {
      var block = this;
 
      this.appendDummyInput()
          .appendField("Wait ")
          .appendField(new Blockly.FieldNumber(0, 0, 23, 1), "hours")
          .appendField("H  ")
          .appendField(new Blockly.FieldNumber(0, 0, 59, 1), "minutes")
          .appendField("M  ")
          .appendField(new Blockly.FieldNumber(0, 0, 59, 1), "seconds")
          .appendField("S  ")
          .appendField(new Blockly.FieldNumber(0, 0, 999, 1), "milliseconds")
          .appendField("ms     ");
 
      this.appendDummyInput("showOnRunInput")
          .appendField("Show on Run Screen:")
          .appendField(new Blockly.FieldCheckbox("FALSE", function(value) {
            block.updateShape_(value === 'TRUE');
            block.setCollapsed(false); // Force an update to fix rendering issues
          }), "checkbox");
 
      this.appendDummyInput("variableInput")
          .appendField("Select Timer Alias:")
          .appendField(new Blockly.FieldVariable("Timer Alias"), "TimerAlias")
          .setVisible(false);
 
      this.setPreviousStatement(true, null);
      this.setNextStatement(true, null);
      this.setColour(230);
      this.setTooltip("");
      this.setHelpUrl("");
 
      // Delay the rendering process until after the block is initialized
      setTimeout(function() {
        block.updateShape_(block.getFieldValue('checkbox') === 'TRUE');
        block.render();
      }, 0);
    },
 
    updateShape_: function(value) {
      var variableInput = this.getInput('variableInput');
 
      // Check if the block is in the toolbox and the checkbox is false
      var isInToolbox = this.isInFlyout || (this.workspace && this.workspace.isFlyout);
      variableInput.setVisible(!isInToolbox && value);
    }
  };
 
  Blockly.Python['custom_block'] = function(block) {
    // Generate Python code for the block.
    // You can customize this function to define the desired behavior.
    var code = '...';
    return code;
  };

Dummy PG

unread,
Jun 5, 2023, 4:46:57 PM6/5/23
to Blockly
Just as hint, you'll need a setOnChange() function which is called basically in all events (so be careful and filter your events) that will trigger a render change.
replace setTimeout with below and remove updateShape with:
setOnChange((changeEvent) {
if (changeEvent.id === this.id && !this.isInFlyout){
    const checked = this.getFieldValue('checkbox') === 'TRUE';
    this.getField('variableInput').setVisible(checked);

})

Just play around with that code, it should be 80% accurate. :)

Beka Westberg

unread,
Jun 9, 2023, 5:24:28 PM6/9/23
to blo...@googlegroups.com
Hello!

Sorry I'm a bit confused :/ Is the issue that the block isn't rendering correctly in the toolbox?

--Beka

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/164baf43-e69b-42ec-8a9f-9f53f7ac8e80n%40googlegroups.com.

Jason Farris

unread,
Jun 13, 2023, 12:10:19 PM6/13/23
to Blockly
Thank you all for the help.  I was able to "trick" the block into updating the way I wanted it to.  I'll post the code below.

"Dummy" - I tried using the "on change" event and couldn't quite get it to work, but thank you for the information.

Beka - The block was showing correctly in the toolbox and when I would drop it on the workspace.  The issue was that when I would put a check in the checkbox field, the block would not update its shape.

The way I was able to "trick" it was to call the setInputsInline function twice, back to back.  I wanted it set to "false" and setting it to "true" caused the block to update, so I added another one in right away to set it back to "false" and get the block to show correctly.  This happens SO fast that you can't even tell it's happening.

It's probably NOT the best way to do it, but it works and right now, that's what matters.

I hope someone else finds this helpful.

Blockly.Blocks['custom_block'] = {
    init: function() {
      var block = this;
     
      this.appendDummyInput()
          .appendField("Wait ")
          .appendField(new Blockly.FieldNumber(0, 0, 23, 1), "hours")
          .appendField("H  ")
          .appendField(new Blockly.FieldNumber(0, 0, 59, 1), "minutes")
          .appendField("M  ")
          .appendField(new Blockly.FieldNumber(0, 0, 59, 1), "seconds")
          .appendField("S  ")
          .appendField(new Blockly.FieldNumber(0, 0, 999, 1), "milliseconds")
          .appendField("ms");
   
      this.appendDummyInput("showOnRunInput")
          .appendField("Show on Run Screen:")
          .appendField(new Blockly.FieldCheckbox("FALSE", function(newValue) {
            if (newValue === 'TRUE') {
              block.getInput('variableInput').setVisible(true);
              block.setInputsInline(true);
              block.setInputsInline(false);
            } else {
              block.getInput('variableInput').setVisible(false);
              block.setInputsInline(true);
              block.setInputsInline(false);
            }
          }), "checkbox");
   
      this.appendDummyInput("variableInput")
          .appendField("Select Timer Alias:")
          .appendField(new Blockly.FieldVariable("Timer Alias"), "TimerAlias")
          .setVisible(false);
 
      this.setPreviousStatement(true, null);
      this.setNextStatement(true, null);
      this.setStyle('Timer_blocks');
      this.setTooltip("");
      this.setHelpUrl("");
    }
  };

Reply all
Reply to author
Forward
0 new messages