Help: How to override/shadow a property of subclassed control

Hello,

i have subclassed the ProgressBar control and named it “PBunlimited”. I added a private computed property “MaxFactor”.

After adding this control to Window1 and a “Run” the following should happen:

  1. The “Maximum” value of PBunlimited - inherited from the Super ProgressBar (=100) - should be checked if it was changed
    in the Xojo Inspector
  2. If the value was changed, the “Maximum” of PBunlimited should be calculated to a new value. Then this new value should
    be set as the new PBunlimited’s new Maximum and the “MaxFactor” should also be set (as Read Only thus the “Set” is not used" .

I tried to do this by adding a “public Computed Property” and naming it just as the Supers (ProgressBar) property “Maximum”. I tried to override/shadow the “Maximum” property, but that does not work.

Can anyone tell me how i can solve that problem in any way ?

General:
A subclass of a control should be checked (after instantiating or adding to a window and running the program) if

  1. a value of a property of the (subclass-)control was changed in Xojo inspector or in the code (changed = no more the default value)
  2. if the changed value exceeds a limit (set by a constant) the value should be calculated to a new one
  3. the new calculated value should be set as the new (subclass-)control property value
    3a) the calculation in 2) gives also a factor that should be set as value of a new property

Example:
ProgressBar1 -> subclass “PBunlimited1”
PBunlimited1 added to Windows1
In Inspector change of “Maximum” of PBunlimited1 from 100 to 10000000
Run
[now the followin should be done automatically]

-> check if Maximum was changed and greater than 65536 => then do

divide Maximum of PBUnlimited by 65536 and set private property mMaxFactor to the next rounded-up whole number of the division
[10000000 / 65536 = 152,587890625 -> rounded up to next whole numer = 153]

divide the Maximum by mMaxFactor value and set Maximum of PBunlimited1 to the next rounded-down whole number of this division
[10000000 / 153 = 65359,47712418301 -> rounded down to next whole numer = 65359]

[PBunlimited.MaxFactor should be set to 153, PBunlimited.Maximum should be set to 65359]

-Ralf

About the only way to do this is to start a Timer in the control’s constructor and put your initialization code in it. The reason is that the values set in the IDE are loaded after the constructor finishes, so your constructor won’t see the new value.

@Tim Hare

Thank you, but i got no idea how to do what you suggest. On my Padlet wall you can download a “Test” project file. There you can see how i tried to solve the problem but the maximum is either reset to 0 or an exception is thrown.

-Ralf

First, shadowing a property like this is a bad idea. However, if you want to make it work, you need to change your Maximum.Set code to

  if value > 65536 then
    mMaxFactor = Ceil(value / 65536)
    Progressbar(me).Maximum = floor(value / mMaxFactor )
  else
     Progressbar(me).Maximum = value
  end if

(By “bad idea”, I mean that shadowing a property makes your code fragile. It is still possible to manipulate Maximum directly without going through your computed property.)

@Tim Hare

Thank you very much. Now i could finish my Subclassed ProgressBar example.

But can you maybe explain to me why i must use “Progressbar(me).Maximum” instead of “Me.Maximum” or “Progressbar.Maximum” or “PBunlimited.Maximum” ?? (Any link where i read about that ?)

-Ralf

Be aware that you can not do the following (assuming that your window contains ProgressBar and PBunlimited instances):

For i As Integer = 0 To Window1.ControlCount - 1 If Window1.Control(i) IsA ProgressBar Then // a ProgressBar or a PBunlimited ProgressBar(Window1(i)).Maximum = ... // This will use the code of the Maximum property of ProgressBar, // even if it is an instance of PBunlimited End Next
You will have to first handle the subclass:

For i As Integer = 0 To Window1.ControlCount - 1 If Window1.Control(i) IsA PBunlimited Then // a PBunlimited PBunlimited(Window1(i)).Maximum = ... // This will use the code of the Maximum property of PBunlimited ElseIf Window1.Control(i) IsA ProgressBar Then // a ProgressBar, which is not a PBunlimited ProgressBar(Window1(i)).Maximum = ... // This will use the code of the Maximum property of ProgressBar End Next
That’s one of the nasty things of not being able to override properties like in VB. NET and most of the other OOP languages.

@Eli Ott

Thanks for that hint. I’m new to programming and i haven’t to loop through controls for now but when it comes to my learning experience i will remember it.

That is the very heart of the problem with shadowing a property. The type of variable you use matters. This isn’t a problem with overriding methods, but is a big problem with shadowing properties. Methods are virtual - they are resolved at runtime and will find the correct method to call based on the type of object, regardless of the type of variable. Properties are not - they are resolved at compile time based on the type of variable, regardless of the type of object the variable holds. This can lead to very subtle, hard to find bugs. You have to be very careful when shadowing a property.