« MBS Xojo Plugins, ver… | Home | Using JavaScript with… »

Xojo Tips

Let us show you a few tips with the Xojo development, which we found to be helpful in the last weeks:

CType

The CType() function allows you to convert a value to a different type and we found it helpful to convert from boolean to integers. We use it here to shrink our code for counting how many boolean variables are set. Please read this snippet:

Sub Test() Dim FirstNameMatches As Boolean Dim LastNameMatches As Boolean Dim CompanyMatches As Boolean Dim EmailMatches As Boolean Dim PhoneMatches As Boolean Dim ProductMatches As Boolean // customer bought this before // evaluate here and set booleans Dim MatchPoints As Integer If FirstNameMatches Then MatchPoints = MatchPoints + 1 end if If LastNameMatches Then MatchPoints = MatchPoints + 1 End If If CompanyMatches Then MatchPoints = MatchPoints + 1 End If If EmailMatches Then MatchPoints = MatchPoints + 3 End If If PhoneMatches Then MatchPoints = MatchPoints + 1 End If If ProductMatches Then MatchPoints = MatchPoints + 1 End If If MatchPoints > MaxMatchPoints Then // best match so far MaxMatchPoints = MatchPoints End If End Sub

This is for matching a new order to existing customer database. The new order may have the same name, email, phone and we look for best match in existing table. For this we match the values and set these boolean variables. Then we count points on how many are set. For the email match we count three points as a special case. This usually finds us the right customer in a lot of cases, even if they changed name, email, company name or phone, but keep one or two values equal.

But now use CType() to directly convert boolean to integer and add the boolean. When converted to integer, a true value becomes 1 and false becomes 0. For email we add 3 if set and 0 if not set. And all can be nicely formatted using underscore character to continue the line:

Sub TestCType() Dim FirstNameMatches As Boolean Dim LastNameMatches As Boolean Dim CompanyMatches As Boolean Dim EmailMatches As Boolean Dim PhoneMatches As Boolean Dim ProductMatches As Boolean // customer bought this before // evaluate here and set booleans Dim MatchPoints As Integer = _ CType(FirstNameMatches, Integer) + _ CType(LastNameMatches, Integer) + _ CType(CompanyMatches, Integer) + _ CType(EmailMatches, Integer) * 3 + _ CType(PhoneMatches, Integer) + _ CType(ProductMatches, Integer) If MatchPoints > MaxMatchPoints Then // best match so far MaxMatchPoints = MatchPoints End If End Sub

The new code is shorter, hopefully easier to read and performs better. What do you think?

Local variable to cache

I have been using this technique a lot to speed up code here: We define a local variable with the same name as a global function, property or otherwise expensive thing to get. A few examples:

In a web application:

Dim session As session = session

In any project type:

Dim app As app = app

In a Desktop project with a ListBox control named List:

Dim List As ListBox = Self.List

Or in a Web project with a listbox:

Dim List As WebListBox = Self.List

For a window the same:

Dim MainWindow As MainWindow = MainWindow

Because in all cases you call a function, which is relative expensive compared to a local variable. App is a function, which looks up the current app object (via REALbasic._GetAppObject function). Session is a global function, which lookup the current thread and returns the associated session object (via _WebSupport.Session function). For a control on a webpage and window, you get a call to a function to lookup the control by name (via DesktopWindow._ControlByName function). Same for global window references (using REALbasic._GetImplicitDesktopWindow).

You find feature requests in the Xojo issues database for improving all this cases on the framework/compiler side.
e.g. #71958 Make App faster by making App a global property for all targets

To implement this feature, you may just go through your code and search for e.g. "List." When you see a method with a lot of positions found in the code, you enter the method and paste this line on the top of the method:

Dim List As ListBox = Self.List

This way you can quickly find spots where this is worth it.

Remember position in Listbox

For a lot of list boxes in the user interface, we would like to remember the current selection and scroll position. The easiest version would be to stay at about the same position. So before updating the listbox, you query ListIndex and ScrollPosition:

Sub testList() Dim i As Integer = list.ListIndex Dim s As Integer = list.ScrollPosition // update list List.DeleteAllRows QueryCustomers List // restore position list.ListIndex = i list.ScrollPosition = s End Sub

If you like to do better, not just remember the list index, but the current selected RowTag with the database row ID, so you can on restore select the same record, even if it moved.

Add CancelClose events for work windows

For a lot of automations we have a window, which shows progress and has some controls to start, stop, pause or continue a batch processing. For these window we recommend to add a CancelClose event like this:

EventHandler Function CancelClosing(appQuitting As Boolean) As Boolean #Pragma unused appQuitting If Finished = False Then Dim d As New MessageDialog // declare the MessageDialog object Dim b As MessageDialogButton // for handling the result d.Icon = MessageDialog.GraphicCaution // display warning icon d.ActionButton.Caption = "Close" d.CancelButton.Visible = True // show the Cancel button d.CancelButton.Cancel = False d.ActionButton.Cancel = True d.Message = "We are not yet finished." d.Explanation = "Close anyway?" b = d.ShowModal // display the dialog Select Case b // determine which button was pressed. Case d.ActionButton // user pressed Close Return False // let window/app close Case d.CancelButton // user pressed Cancel, keep open Return True End Select End If End EventHandler

This avoids accidentally closing the window before the job is done.

Scale text in PaintCellText for Listbox

We sometimes use bigger row sizes to show multi line text like addresses. These addressees may have text wider than the current column and higher than the current row. We have this handy code to scale down font size until it fits:

EventHandler Function PaintCellText(g as Graphics, row as Integer, column as Integer, x as Integer, y as Integer) As Boolean If column = kColumnAddress Then Dim s As String = Me.Cell(row, column) // start with 13 and go down until text fits or we have size 8 g.TextSize = 13 // measure text size with wrapping at curtent size Dim h As Integer = g.StringHeight(s, g.Width) While h > g.height And g.textsize > 8 // go down one point and measure again g.textsize = g.textsize - 1 h = g.StringHeight(s, g.Width-4) Wend // draw text here g.DrawString s, 2, g.textsize, g.Width-2 Return True End If End EventHandler

Of course we use that only for columns, that need the scaling and not for all column. And as you see we define constants in the window to keep track of which column number is for which value.

Thanks for reading and if you have more tips to share yourself, please post to the Xojo forum or on your own blog.

04 03 23 - 09:00