Skip to content

The Powerful World of Delegates

Delegates are one of those advanced features you can find in the Xojo programming language, and it’s a really powerful one! Once you discover and comprehend all the flexibility you can get from Delegtes, I’m pretty sure you’ll start to start using them!

But what is a Delegate? We can define it as a data type definition for a method (or function) signature. That is: when you define a new delegate type you need to provide it with a concrete method or function signature. And here is where everything begins.

Once you’ve defined the new Delegate type, you can use it in your code as you would with any other data type. So, for example, you can add a property to any object (Windows, WebPage, iOSView, Class, subclass…) and define its type as the just-created Delegate type.

That means that during your app’s code execution, you can change, for example, the Delegate property value so it stores ANY method or function matching the Delegate signature and then, you can invoke it! The main point here is that, through the use of Delegates, you can dynamically change the code to execute.

Let’s see how it works through a simple example, randomly drawing to a Graphic class instance using that code will work with any graphic instance you pass along as parameter.

Delegate Creation

Of course, the first step is defining our Delegate data type. In a new Desktop project, select Insert > Delegate, and use the Inspector Panel to change its values to:

  • Delegate Name: FigureDelegate
  • Parameters: g as Graphics

Voilà! We have created a new data type that can point to any method matching that signature.

Using the Delegate Type

As you do with any of the standard data types or your created classes, you can create new variables or properties whose data type is our delegate type. For example, add a new property to the Window1 item and change its definition in the Panel Inspector so it reads:

  • Name: Delegates()
  • Type: FigureDelegate

Our Delegate property will be an Array storing FigureDelegates values.

Creating Matching Methods

Now let’s add a few methods matching our Delegate signature, so we can add them as values to our Delegates() Array.

The first one will randomly draw a line in the received Graphics context, as parameter. So, add a new method to Window1 and use the Inspector panel to change its values to:

  • MethodName: DrawLine
  • Parameters: g as Graphics

And write the following code in the associated Code Editor:

g.ClearRectangle(0,0,g.Width,g.Height)

Var rd As New random
Var x, y, w, h As Double

g.PenSize = 2
g.DrawingColor = RGB(rd.InRange(0,255), rd.InRange(0,255), rd.InRange(0,255))

x = rd.InRange(0, g.Width)
y = rd.InRange(0, g.Height)
w = rd.InRange(0, g.Width)
h = rd.InRange(0, g.Height)

g.drawline(x,y,w,h)

Our second method will draw Ovals; so, add a new method to the Window1 item and change its values to read:

  • Method Name: DrawOval
  • Parameters: g as Graphics

And write the following code in the associated Code Editor:

g.ClearRectangle(0,0,g.Width,g.Height)

Var rd As New random
Var x, y, w, h As Double

g.PenSize = 2
g.DrawingColor = rgb(rd.InRange(0,255), rd.InRange(0,255), rd.InRange(0,255))

Var widthAvail As Integer
Var heightAvail As Integer

x = rd.InRange(0, g.Width)
y = rd.InRange(0, g.Height)
widthAvail = g.Width - x
heightAvail = g.Height - y
w = rd.InRange(0, widthAvail)
h = rd.InRange(0, heightAvail)
g.DrawOval(x,y,w,h)

Next, add a third method. This one will draw a string. Once added to the Window1 item, use the Inspector Panel to change its values to:

  • Method Name: DrawText
  • Parameters: g as Graphics

And put the following snippet of code in the associated Code Editor:

g.ClearRectangle(0,0,g.Width,g.Height)

Static t As Text = "Hello World!"
Var tc As Double = g.TextWidth(t)/2

g.DrawText(t, g.Width/2-tc, g.Height/2-g.TextHeight/2)

Adding Methods to the Delegates() type

We told that a Delegate data type points to a Method or Function; but, how can we get that value? Really simple! Xojo provides the AddressOf operator that gives us the memory address where the method “lives”.

Add the Open Event Handler to the Window1 item and add the following code to the associated Code Editor:

Image = New Picture(ImageWell1.Width, ImageWell1.Height, 32)
Delegates.AddRow(AddressOf DrawLine)
Delegates.AddRow(AddressOf DrawOval)
Delegates.AddRow(AddressOf DrawText)

Adding a Picture Instance

We will need a Graphic context to paint in. For that we will add a new Property to our Window1 item, using the Inspector Panel to change its values to:

  • Name: Image
  • Type: Picture

Layout the User Interface

Now let’s take care of the user interface, so we can see how everything works.

Select Window1 to bring in the Layout Editor for the default application window. Then, add an ImageWell and a PushButton control from the Library to the Layout Editor. Change their positions and the ImageWell size so they matche the following screenshot:

Finally, add the Action Event Handler to the just added PushButton and write the following snippet of code in the associated Code Editor:

Var rd As New Random
Var d As FigureDelegate

d = Delegates( rd.InRange(0, Delegates.LastRowIndex) )

d.Invoke( image.Graphics )

ImageWell1.Image = Image

As you can see, we defined a new FigureDelegate variable and assigned it a random value from our Delegates Array. Then, we only need to call the method (or function) pointed by a Delegate data type using the Invoke method on it. Run the example app and see how it behaves.

As you can see, using this technique you could use the same methods on, for example, any picture instance.