Speed tip with popupmenus

In a different forum a user reminded me of a speed tip that had cropped up once or twice over the years. It has to do with popupmenus.

Basically on older versions of macOS if you did


PopupMenu1.ListIndex = -1
For i As Integer = 0 To 1000
  PopupMenu1.AddRow Str(i)
Next

This behaved not so badly although there is a slightly faster variation

But on Mojave this is noticeably slow. This simple loop could take as much as a second on Mojave in dark mode.

To speed it up it was discovered that if you added an item in position(0), set the listindex to 0 then added all the items and removed that extraneous item at position 0 then the speed was hardly impacted at all.

PopupMenu2.AddRow ""
PopupMenu2.ListIndex = 0
For i As Integer = 0 To 1000
  PopupMenu2.AddRow Str(i)
Next
PopupMenu2.RemoveRow 0

My testing on 10.12.6 and 10.14.5, in light and dark modes, using 2019r1.1 with the following code shows the differences in the debugger

Sub Action()
  Dim startTime1 As Double 
  Dim endTime1 As Double
  
  Dim startTime2 As Double 
  Dim endTime2 As Double
  
  
  startTime1 = Microseconds
  PopupMenu1.ListIndex = -1
  For i As Integer = 0 To 1000
    PopupMenu1.AddRow Str(i)
  Next
  endTime1 = Microseconds
  
  
  startTime2 = Microseconds
  PopupMenu2.AddRow ""
  PopupMenu2.ListIndex = 0
  For i As Integer = 0 To 1000
    PopupMenu2.AddRow Str(i)
  Next
  PopupMenu2.RemoveRow 0
  endTime2 = Microseconds
  
  
  Dim total1 As Double = (endtime1 - startTime1) / 1000000
  Dim total2 As Double = (endtime2 - startTime2) / 1000000
  
  label1.text = str(total1, "###.00000")
  label2.text = str(total2, "###.00000")

End Sub

And the results are surprising and consistent between running in the debugger & a built application

Debug              Total1 (slow)       Total2 (fast)
 10.12.6            0.037 sec            0.012 sec
 10.14.5 (light)    1.152 sec            0.019 sec
 10.14.5 (dark)     1.158 sec            0.019 sec 
 Built x86_64       Total1 (slow)       Total2 (fast)
 10.12.6            0.036 sec            0.010 sec
 10.14.5 (light)    1.174 sec            0.017 sec
 10.14.5 (dark)     1.174 sec            0.028 sec

Whatever changed in Mojave Popupmenus got very slow.

Heads up.

Thanks to Jim McKay for reporting this

Fun things to do with Xcode

I know a lot of you don’t want to mess with Xcode BUT there are some really handy things it can help you with and you don’t have to write any Swift or Objective-C code.

Since you can drop a plist into Xojo to supplement or replace certain keys at some point you may need to create one. Xcode has an excellent editor for plists.

If you start Xcode and select File > New > File and scroll down there is a section that lists various kinds of files that you can edit. In this list is a Plist.

Select that template and edit and you have a plist ready to add to your Xojo project.

But thats only the beginning.

Perhaps the handiest things Xcode can do is examine the view hierarchy of ANY application. In Cocoa every control is a kind of “view” and your entire UI is composed of multiple views one on top of the other and composited together.

If you’re having issues getting things to appear correctly this can be very handy to know whats above or below what in the entire view hierarchy that macOS uses to create what you see on screen.

We’ll work thought a quick example.

Start Xcode. Start a new empty macOS project. Use the Cocoa App template. It doesn’t matter what you call it just that Xcode wont work for this without an open project. Save that project in a new folder on your desktop since we’re going to throw it away when done.

Start Activity Monitor so you can get the the PID of your running application. I’m going to select Xojo since everyone reading this should have a copy.

I happened to show the Memory usage but other views like CPU time also have a PID column. The number in that column is what you need.

Now back to Xcode.

Select Debug > Attach to Process by PID or Name. A small panel should appear and in here you can put the PID from Activity Monitor. Nothing else will appear to change.

However there are new options available.

Select Debug > View Debugging > Capture View Hierarchy. Once you do that you get what appears to be a 2-D wire frame drawing of the user interface views. However, this is NOT just a 2D view. You can slick and drag in the view area and Xcode will reveal the various layers used to composite the image you see on screen.

There are scrollers on the bottom left to adjust the separation of the layers so its easier to see them. You can, in this view, see what is in front of or behind something else and that can help you resolve weird drawing issues and may help reveal how other applications achieve specific affects like the translucency seen in the Finders left hand navigation panes.

As well in this view you can right click on any view and select the “Print description of” menu item. This wont always tell you something really useful in the lower panes. But it does tell you what Cocoa UI element an object is in case you need to use declares to manipulate it.

There are lots of other things you can do in Xcode once you have attached to a process to examine it. Observing the view hierarchy is just one really useful one.

Enjoy !

Keep your code off of my controls

Suppose you are creating a new container control to encapsulate some functionality onto this new control. You’re already thinking about “encapsulation” which is a good thing.

Why, when you create this new container, would you then make all the controls on it public so code outside the container can change it ? That seems like it would be a good way to ruin the encapsulation you’re trying to achieve.

And, if you do this, any changes to your nicely set up container then may require broader changes in your application if, or when, you make changes to your container.

Lets walk through a quick and simple example that illustrates the issue.

Start a new desktop project.

Add a container control to the project – it will cleverly be named ContainerControl1.

Add a Generic Button to this container. It will be called “PushButton1”.

Make sure its scope is “Public”

Now add an instance of this container to Window1.

Add the Open Event to Window1.

In there put

ContainerControl11.Pushbutton1.enabled = false

And when you run the pushbutton on the container will indeed show up as disabled.

Now imagine you add a lot of other functionality to your application and there are several places where your code enables or disables this button under various conditions. And perhaps you reuse this container on several other windows.

And then you decide to make some changes to the container. And one of those changes is to rename the button to something more meaningful.

In the project we’ve built so far this isnt so bad. If we rename PushButton1 to “ContainerButton” and try to run again we’ll get an error saying

Window1.Open, line 1
Type "ContainerControl1.ContainerControl1" has no member named "PushButton1"
ContainerControl11.PushButton1.Enabled = false

Now in a small application this is manageable. You simply hunt for and change the names and off you go.

But, you may have to do this many times depending on how many times you set the enabled state of the button. And you have to update them all.

And none of this was necessary.

If instead of letting code outside the container reach in and manipulate the control directly we provided an API to do this and hid the innards then we could be sure we have fewer places to fix and that no code outside the container isnt somehow changing the setup in some way that will cause other issues.

In the example lets do this.

In ContainerControl1 add a method

SetButtonEnabled(assigns isEnabled as boolean)
  ContainerButton.enabled = isEnabled
End Sub
  

Make the container buttons scope Private.

Now if you run you will get an error in the Window1.Open event saying

Window1.Open, line 1
Type "ContainerControl1.ContainerControl1" has no member named "Pushbutton1"
ContainerControl11.Pushbutton1.enabled = False

This is because the push button is now private and hidden to code outside the container control.

So we’ll fix this one line to

ContainerControl11.SetButtonEnabled = False

Now if you run the button is once more disabled. But now when we make changes to the ContainerControl we can focus on the container control and the methods it exposes to the rest of our code and not have to worry that we will have to fix a lot of other code elsewhere in our application.

Lets try this out.

Open the container and change the buttons name to “foobar”. And change our method we had for setting the enabled state to

foobar.enabled = isEnabled

And run the sample again.

We made two small changes and no other code had to change. If we had used this container many many times the time savings could have been significant. And the chance for odd bugs caused by code outside the container altering the containers contents significantly reduced.

Make your controls private and expose an API for them and save yourself a lot of grief.

Picking a good name

Not for your children (although that is important too since kids can be incredibly harsh and will pick on kids with names that they think sound different or odd)

This is to do with naming methods, properties, and just about everything else in your Xojo projects.

A good name indicates a number of things to anyone who reads the code. Purpose is the most obvious.

If all you had was a lot of methods named “foo” or “untitled” your application would be incredibly hard to figure out and maintain for very long.

So having a method named

SplitPropertyValuesIntoDictionary(jsonSource as JSonItem) as Dictionary

Gives you a decent idea what this method will do just by reading the full description and the names of the parameters.

Events have similar naming issues. They should convey what is happening when they are raised. “Action” has never been a great name for the event that is raised by a pushbutton when it is clicked on. Its not entirely horrid but it could be better.

Pushed() 

might be better since that is what has occurred in a push button.

Some events happen DURING some other action. For instance when an expandable row in a listbox is clicked on you currently get a “ExpandRow” event – which might mislead you into thinking you have to write some code to actually DO the expansion like setting the rows expanded property to true as well as other code. Again the name isnt horrible but it could be better.

RowExpanding()

more closely reflects when the event is being raised; during the rows normal course of expanding. Again though this doesn’t convey much information about what is expected. Can you cancel the row from being expanded ? Without reading the documentation this name doesn’t tell you much.

AddRowsToRowExpanding()

might be even better as it tells you exactly what this event is for.

Now I know some will say “OMG thats so much typing” – yes – if you type every last thing out by hand. Learn to use Autocomplete and it will help you immensely and may even help you find other useful properties, methods etc that you may not know existed.

The better you pick names the more easily your code documents itself. I’m not advocating writing no comments in code but they should be about the general process being performed not the mechanics (unless the mechanics are really hairy)

see this excellent post about this subject

Who defined that ?

Sometimes its nice to be able to know what class defined a property or method. Introspection makes this mostly knowable.

The reason I say “mostly” is that something the introspection metadata does not tell you is if the property definition is local or inherited. So you cant tell for sure if a property in a subclass is one defined in the subclass or the inherited one from the superclass. It would be nice if this were knowable and introspection told you this but I’m not holding my breath that this will be altered as its been this way for a long time.

So lets see what introspection _can_ tell you as sometimes that is sufficient. And for when its not well you’ll have to sign on to a feature request to add metadata to introspection so you can tell.

One thing to know about introspection is that for a subclass you also get all of the supers information. So when you get the list of properties in a subclass all the supers properties will be included in that list as well.

We’ll make use of that tidbit.

For we need to get the TypeInfo for the class of interest. We’ll focus on doing this with something simple to start with – a Window. If you put this code in the open event of a Window you will get the TypeInfo for the window this is in.

// get a list of current class up through all its supers
dim current as Window = self
Dim t As Introspection.TypeInfo = Introspection.GetType ( current )

The TypeInfo is the metadata that tells you

  • the class’ name
  • if its an array, class enum, interface, or pointer,
  • if the item is a primitive type like an integer, color, or double
  • if its public or not
  • if the item is a value type or not (yes I wrote that article too)

This is all handy info. In addition to telling you all this the TypeInfo item is the one that allows you to access the properties, methods, attributes, and constructors of a class. There are several methods on the TypeInfo instance you can call that gets you a list of items you can then use.

To access the list of properties you call the GetProperties method of the TypeInfo instance

Dim props() As Introspection.PropertyInfo = t.GetProperties

Note you get back an array of PropertyInfo instances. Since any class might have more than one property this makes sense. An array is useful.

If you put a break point on the “Dim Props” line and ran this code you could manually see whats in the Props array. For a Windows you’ll have a length list and it will include things like Handle, Top, Left, Width and all the properties you might expect to see. And for each PropertyInfo object you see whether the item is private, public, protected, computed, readable and writable, shared and another object that tells you about the type of the property.

Introspection if full of objects that use other objects to tell you more information.

Again, this list doesn’t tell you anything about where the property originated – whether its defined IN this class or inherited from a super class.

So to keep track of where the property “originated” as best we can we’ll need to go through this list and mark every property as “from this class”. Then we’ll move up to the super class, get its list of properties, mark all of the ones we already knew about that match, by name, as being from the superclass. And then repeat this until we get all the way to the point where we are at the very base class that has no super.

For Window this is easy as Window has no super

We’ll create the code to do a window and then extend it to do a class that does have a deeper hierarchy of supers.

Start a new desktop project.

Add a listbox and pushbutton to the Window. Make sure the listbox has 2 columns.

Then create a new method on Window1 – GetSuperPropertyList( w as window)

In there lets put code similar to what was mentioned above.

// get a list of properties on Window
Sub GetSuperPropertyList(current as Window) 
  Dim t As Introspection.TypeInfo = Introspection.GetType ( current )
  Dim allprops As New dictionary
  Dim props() As Introspection.PropertyInfo = t.GetProperties
  For j As Integer = 0 To props.ubound
     Dim oneProp As Introspection.PropertyInfo 
     oneProp = props(j)
     listbox1.addrow t.name, oneProp.Name
  Next
End Sub

We start by getting the TypeInfo for the Window passed in. And then from that we get the list of properties on a Window and put those in a listbox.

In the pushbuttons action event put

GetSuperPropertyListCount( self )

And run.

Press the pushbutton.

You should see in the listbox a list of about 30 or so items. In the first column everything will say “Window1” and the second column are the names of all the properties on a Window.

Quit the running application.

Lets adjust the code so it can handle more than just a Window.

Fortunately this change is quite simple. Every object type in Xojo inherits from “Object” and so we can pass ANY class instance to a methd that uses “Object” as the type of the parameter.

Change the declaration of GetSuperPropertyList from

Sub GetSuperPropertyList(current as Window) 

to

Sub GetSuperPropertyList(current as Object) 

And now in the pusbutton’s action event you can write

GetSuperPropertyList(self) 
GetSuperPropertyList(me)

Run and again press the button. This time you see a listing of the Window’s properties (self) and one from the pushbutton (me).

Now the only trick is to make the method list the properties of the immediate class and those of the supers. In order to do that we’ll need to :

  • go through the current class and make note of the class name and property name
  • get the super class
  • go through its properties making note of the class name and property name
  • lather rinse & repeat until we get to the point there is no super class any more
  • print out the list

Now as we go thought teach class and its super we want to note the property name and the class name, and then when we go through the super if the property exists we need to alter the name we recorded. A perfect place for a dictionary.

So lets alter the code to

// get a list of current class up through all its supers
Dim t As Introspection.TypeInfo 
// get the type info for the current item
t = Introspection.GetType ( current ) 
// a place to keep all the property info were about to gather up
Dim allprops As New dictionary

// as long as we have a class' typeinfo
While t <> Nil
  // get all the properties on the class
  Dim props() As Introspection.PropertyInfo = t.GetProperties
  // and save them in a dictionary
  // using the NAME of the property as the key
  // and the name of the class we founf it in as the value
  For j As Integer = 0 To props.ubound
    Dim oneProp As Introspection.PropertyInfo 
    oneProp = props(j)

    allprops.value( oneProp.Name ) = t.Name
  Next

  // get the immediate superclass of the class we're looking at now
  t = t.BaseType
Wend

// now we have a dict fill Of keys (propNames) 
// And values (the Class the define the prop)
// so list them all out
For i As Integer = 0 To allprops.Count - 1
  Dim key As String = allprops.Key(i)
  listbox1.addrow allprops.value(key).stringValue, key
Next

You can see that what we have added is code that does what we were doing before (getting the type info then the list of properties) and simply saves that list in a dictionary.

The thing that makes the code walk “up” the class hierarchy is the line

// get the immediate superclass of the class we're looking at now
t = t.BaseType

Every TypeInfo object knows which one is its superclass – this is the BaseType. And by using the BaseType each time in the while loop we move from the current type to its super type and so on until there is no super type.

In each iteration around the while loop we update any existing properties to say they cam from the super type (see note above about not being to actually tell if this is true or not). For most purposes this is adequate.

If you run this now & press the button you will see that instead of just Window & PushButton we see a bunch of properties from Control & RectControl. These are from the superclass of PushButton.

And there you go. A handy method to walk up the hierarchy and get which properties came from where.

Handy Method Editor tips

Did you know that you can write, in the declaration pane for the method editor, the entire declaration and the editor will rip it apart for you ?

So instead of having type the name, tab, parameters, tab, return type, tab, select a scope you can type

Private Foo(i as integer) as string

and press tab or return and it will all get split into the right spots.

Like this

Press Enter and get

EDIT : FWIW you can do this in a property as well that isn’t a computed property. But not in a constant (yeah you can probably blame me for that)

Friends

When you design classes you often make the properties they hold private or protected so outside code cant mess with the innards.

But what if you want to allow that – sometimes ?

This is the notion of a “friend”. Another class that you can literally say “yeah its ok I know them and it’s OK if they mess with my innards as they are my friend”. Xojo doesn’t have such a notion. So how do you make this possible ?

First off you really need to think hard about what it is you want to do and do you really need “friend”liness ? You may not. An interface or some other mechanism may be more suitable.

But if you do some to the conclusion you DO need a “friend” then you can make one using namespaces and private interfaces.

What you CAN do is

  1. take your class (call it AllowFriends) & put it in a module
  2. declare a PRIVATE class interface that class AllowFriends implements since you CAN implement an interface with private methods.
  3. Add classes to this module that you want to make friends of class AllowFriends
  4. on each class that wants to allow “friend” access implement the interface with PRIVATE methods.
  5. now anything in this module, classes or methods, that is a friend of class AllowFriends can cast it to the private interface & access whatever you exposed in that interface – this WILL only be methods but since you can make method pairs act like a getter/setter things should be fine.

And now you have classes in that module that can be “friends” but nothing outside the module can be since they cannot access the private methods on each class OR the private interface. The interface is restricted to only be used by classes & methods that exist in the module.

It’s not exactly “friend” from C++ but its about as close as you can get in Xojo.

Stupid IDE tricks

A question was asked the other day about “how can I list just all the Windows in my application” And that reminded me of something I added to the IDE some time back.

Advanced filters in the find field above the navigator. It has only a very short mention in the IDE user guide.

So if you want to find all the Windows in your application you can type something like this into the filter field

% type:Window

and press enter and you will see all windows and container controls listed (containers are window like objects hence why they are listed). You can use the type filter with just about any type you can imagine in your project; property, constant, enumeration, delegate, method and so on.

You can also put things in the type field that include wild cards. So if you want to see all properties, computed and regular, you can put

% type:%property

This will list any computedproperty or property, regardless of its name, in the navigator.

Combine this with a decent naming convention and you can make the filter work for you in a lot of ways I think a lot of people do not realize exists.

Making a constructor sometimes illegal to call

Suppose you write a control subclass that you want people to be able to add to a window layout OR be able to create on the fly. But you want to make sure that when an instance is constructed in code it MUST have a parameterized constructor. However, in order to put an instance on a layout by drag and drop it has to have a no parameter constructor. These two design goals seem very much at odds.

So how do you make this happen ?

Such a control might be like :

Class myControl
  Inherits Canvas

  Sub Constructor()
  End Sub

  Sub Constructor(name as string)
     self.mName = name
  End Sub

  Computed Property MyName as string
    Function Getter() as string
       return mName
    End Function
    Sub Getter(value as string)
       mName = value
    End Sub
   
  protected mName as string
end class

We’ll assume that MyName has been exposed as part of the Inspector Behaviour.

But the class definition above would definitely allow you to write code that called either constructor. How to make it so the no parameter constructor can only be used by instances on a layout that, as part of initializing the layout, basically does the following

dim c as new myControl
c.MyName = "whatever value the user set in the inspector"

But there is a trick you can use to know how you have been called. An exception exposes the call stack to you and you can examine that to know if there is a window being initialized that has resulted in your no parameter constructor being called. And so you can make it so a window being initialized can use the no parameter version. In fact to make it so your control can be placed on a layout in the IDE designer it MUST have a no parameter constructor if it has any constructors.

If we make that no parameter constructor read as follows we can make this raise an exception when used improperly outside of a window being constructed. Sorry can’t make the compiler reject it (THAT would be awesome)

Try
  Raise New NilObjectException
  
Catch noe As NilObjectException
  Dim stack() As String = noe.Stack
  
  // IF this is an instance created on a layout we should find a 
  // Window.__Init%%o<Window> in the stack above the call to this Constructor
  For i As Integer = 0 To stack.Ubound
    If stack(i) = "Window.__Init%%o<Window>" Then
      Return
    End If
  Next
  
  // and if we do not then raise an UnsupportedOperation error
  Raise New UnsupportedOperationException
End Try

A window, when being created, calls __Init and so we can tell if we were called by a window being created or not by walking up the call stack. If there is no Window.__Init in the stack then we definitely were not and so can raise an exception to let the coder know that this usage, without a parameter, is only for Layouts and nothing else.