Change rectangle size but aligned to the bottom not top

I have a window showing the current state of some LEDs. I already have it set up using simple rectangles and a method that either turns the box above the label on or off depending on the state of the LED, but it doesn’t currently show the intensity.

They’re all a fixed height of 40 pixels so I’m just multiplying the intensity (as a percentage) by 40 and arriving at a new height.

image

In this example, R1 is on at 50%. The others are on at 100% The problem is that when I change the height of the rectangle:

wStatusWindow.indicatorR1.Height = newbarheight

It works but is aligned to the top. Is it possible to make a row of rectangles align to the bottom, so that when I change the height it’s the top that moves, not the bottom?

The only way I can think of is to recalculate the top of the rectangle based on the new height, but this is a lot more code and it means if I ever reposition the rectangles within this group box, I’ll have to also modify the code to reflect that new position. I’m hoping there’s a simpler way to do this.

The only way I know is to recalculate the top position.

The following code should work without needing to be tweaked if you move the rectangle.

wStatusWindow.indicatorR1.Top = wStatusWindow.indicatorR1.Top - (newbarheight - wStatusWindow.indicatorR1.Height)
wStatusWindow.indicatorR1.Height = newbarheight

Another way to do this would be to use a function. With a little care something like this can be built to handle any number of rectangles for dynamic interfaces.

I built a sample project because it seemed like an interesting way to practice:
Rectangles.xojo_xml_project

2 Likes

Yeah that’s essentially what I’ve done and it seems to work. I guess it’s not that as messy as I thought but it would still be nice if you could simply reference the bottom of the rectangle. If I ever decide to change the UI or resize things this is definitely going to come back to bite me.

//Set the new height of the bar
var newbarheight as integer = 40 * intensity

//set the top of the indicator to the default (124) plus the difference between default and new height.
var bartop as integer = 124 + (40 - newbarheight)

select case led
case "R1"
  wStatusWindow.indicatorR1.Top = bartop
  wStatusWindow.indicatorR1.Height = newbarheight 
  wStatusWindow.indicatorR1.Visible = visibility

Silly idea?

if these rectangles were canvas objects, and set to align to the bottom of the window/container in the IDE, just changing the height should make the bottom stay put, while the top moves up and down.
Paint the color in the Paint event.

thanks. I’ll take a look at this.

Maybe use a RectControl extension method to simplify your main code.

Sub HeightBottomAligned(Extends pControl As RectControl, Assigns pHeight As Int32)
  pControl.Top = pControl.Top - (pHeight - pControl.Height)
  pControl.Height = pHeight
End Sub

You could then do this:
wStatusWindow.indicatorR1.HeightBottomAligned = 50

That would work once and then fail. as you are altering the height of pControl and also using it to calculate the amount of movement. You need the pure 100% size to calculate the top correctly.

If the goal is to always keep the bottom edge in the same position when the height changes then my code will do that.

Actually, I think you are correct. My bad. Appologies.

Instead of using constants you could use the height of the GroupBox that the controls are contained within and offset them.

Var fullHeight as Integer = GroupBox1.Height - somefactor // to allow for the difference between them
Var standardBartop  as Integer = GroupBox1.Top + someotherfactor // when it is in its original position calculate the difference of that top and the group box top.

var newbarheight as integer = fullHeight * intensity
var bartop as integer = standardBartop + (fullHeight - newbarheight)

That would mean that you can simply change the height of the group box and the code would simply work to that new height.

In the IDE click on the GroupBox and record the height. Click on your bar an get the height, subtract one from the other and you have your constant “somefactor”.

Again Click on the GroupBox and get the top, click on your bar and get the top. subtract one from the other and you have “someotherfactor”.

Indeed, you could automate this by creating a couple of properties on the window and calculating these in the Opening event, as all controls will have their IDE sizes at that point.


Simpler still: Create two properties on the Window

private InitialHeight as Integer
private InitialTop as Integer

In Window.Opening:

InitialHeight = Bar.Height
InitialTop = Bar.Top

When you need to change the height:

var newbarheight as integer = InitialHeight * intensity
var bartop as integer = InitialTop + (InitialHeight - newbarheight)

Do you know about control locking. If you lock the text at the bottom of the group box to the bottom (but not the top). And lock the top and bottom of the bar. Then then resizing the group box will automatically adjust the bars at design time.