Best way to dynamically add horizontal space to custom component?

What I’m trying to do:
Recreate this hierarchical checkbox component, where each child has more and more leading whitespace to indicate its level within the tree. I know I can’t be the only person who has run into this problem.

What I’ve tried and what’s not working:
For each child, I’ve tried dynamically adding Spacer components, or just increasing the “width” property of the spacer component, with no visible difference. The documentation on the width of spacers is pretty lacking.

Code Sample:

  def __init__(self, **properties):
    self.column_panel_1.border = "1px solid"
    self.column_panel_1.add_component(Spacer(width = '2'))
    self.init_components(**properties)

To add more to the mystery, I can “control drag” space in the UI, for the Spacer component, but that doesn’t seem to change the “width” attribute at all., namely, when I try and print the width to the console. I have no idea what I’m missing here.

Clone link:
https://anvil.works/build#clone:7CH7XR6GAMNBMWP7=RXZ2I2BPSQQZJBOR45AQANTG

Here’s the clone, and as always, and suggestions are always appreciated.

Instead of using a spacer I use a label, set its role to text and add a number of spaces.

Setting its role to text prevents adjacent spaces from being squished into one space.

You can see the result here.

1 Like

Hi @nathanguyette,

Aha! Now I understand what you’re looking to do, what I’d recommend for this is to use a FlowPanel for each row. First add a Spacer with a controllable width= to create the indent, then add the rest of that line’s content (eg a Checkbox) with expand=True so it will fill up the rest of the space on that line. Voila - a programmatically controllable indent!

1 Like

Hey @meredydd, that worked beautifully, thank you so much! I added my own twist by encapsulating the rest of the controls that needed to be to the right of the spacer in a ColumnPanel and just set the Column panel expanded = True. :slight_smile:

I’m curious why the width property has to be set to blank in order to set it programmatically?

I tried setting the width to some static number before, and it wouldn’t work, just wondering the underlying mechanics for this.

I was actually about to use a similar solution using the RichText component before @meredydd came up with his solution.

Using the width argument is clean, but requires some code.

Using a label with a number of spaces can be done with databinding, without any code.

Here I am indenting with 5 spaces per level with ' ' * (5 * self.item['level']):

self.repeating_panel_1.items = [
    {'level': 0, 'text': 'Level one A'},
    {'level': 1, 'text': 'Level two B'},
    {'level': 2, 'text': 'Level three C'},
    {'level': 2, 'text': 'Level three D'},
    {'level': 1, 'text': 'Level two E'},
    {'level': 2, 'text': 'Level three F'},
    {'level': 0, 'text': 'Level one G'},
    {'level': 1, 'text': 'Level two H'},
]

image

2 Likes