Happy #MapInfoMonday, and also a happy #MapBasicMonday,
Today, I will share some tips for buildings dialogs through MapBasic. I will share a tip that was sent to me by @Alan-Frank Vecchio Thanks for taking the time to share that idea, Frank. I appreciate the ideas, suggestions, and questions sent to me. If you want to share something you can either contact me through the community here, send me an e-mail, or use the #MapInfoMonday survey.
The Dialog and Control statements
You use the Dialog statement to initial the construction of your dialog.
Dialog
[ Title title ]
[ Width w ] [ Height h ] [ Position x, y ]
[ Calling handler ]
Control control_clause
[ Control control_clause... ]
You can give your dialog a Title
that will appear at the top of the dialog. If you omit the title, the dialog will not have a title and it will not have the close button (the small x) at the top either.
You can also provide the dialog with a Width
and Height
. If you omit these, MapInfo will automatically calculate a reasonable size for the dialog. This works quite fine and you rarely have to worry about providing these values unless you want to make the dialog either larger or smaller than the area covered by the controls on the dialog.
You can also use the Position
to control where on the screen your dialog will appear. The position is calculated from the upper-left corner of the MapInfo Pro work area.
The Calling Handler allows you to run a procedure to initiate the dialog. This procedure will get called when the dialog has been constructed. This allows you to set the state and values of the controls on the dialog.
Finally, you can start adding the Controls to the dialog. The controls are the elements that allow the user to select or enter values that you need to proceed. It could be a text that you want to search for, a list of tables the user needs to pick from, and much more.
In the image above you can get a good overview of most of the control types available for MapBasic dialog. A few are missing such as the Button Control
and the DocumentWindow Control
.
For most control types, you can also assign a Handler
which will get called if the user clicks or selects from the control. This allows you to make the dialog responsive to user input. As an example, you can use this to react to the user selecting a table from a list and then populate another control with all the column names from the selected table. You use the Alter Control
statement to change controls on the dialog from procedures called from the dialog.
One thing to keep in mind is that the OKButton
is the default button. That means if the user hits the Enter key on the keyboard, it will be like she clicked on the OKButton
. I will get back to this later in the tips below.
I will not go into depth with each of the control types. We will cover these in another #MapBasicMonday article.
Dismissing and Preserving the dialog
By design, the user can close the dialog in three ways.
She can click on the OKButton
or she can click on the CancelButton
.
She can click on the cross (x) in the dialog title. This will be equal to using the CancelButton
.
As the programmer of the dialog, you can however dismiss or preserve the dialog through code from other handlers too. To dismiss the dialog, use the Dialog Remove
statement. This statement can be used from any procedure called from the dialog.
It sets the flag that the dialog was canceled so you may have to handle this nicely if you check for this state after the Dialog
statement using the CommandInfo()
function. You can for example do this by setting a module-level variable.
The Dialog Remove
statement is often used so that the user doesn't have to click the OKButton
. Personally, I often use it if the user double-clicks on an element in a ListBox control
.
The Dialog Preserve
will keep the dialog on screen after the user has clicked on the OKButton
or CancelButton
. A typical use case for the Dialog Preserve
is to give the user a second chance before closing the dialog: "Are you really sure you want to dismiss the dialog?". If the user changes his mind, you can use the Dialog Preserve
statement, and the dialog will reappear on the screen in the state it was when the user clicked on the OKButton
or CancelButton
.
Hiding Controls outside of the Dialog Area
This tip came from @Alan-Frank Vecchio as I mentioned above.
I had been racking my brain trying to create a search box but if the user hits enter whilst the dialog is open regardless, the dialog submits. My simple workaround was to position the OKBUTTON outside the visible dialog form.
'Global or modular variable
Dim bDialogClosed As Logical
Sub showdialog()
DIALOG
Width 260 HEIGHT 190
TITLE sDialogTitle
Control OKBUTTON
Position 1000,1 ' hidden off the page but does capture enter key pressed !!!
Title "OK"
Calling preserveD
Control STATICTEXT
Position 30, 17
TITLE "Farm No:"
Control EDITTEXT ID TXT_FARMNO
Position 65, 15 Width 65
Control BUTTON ID BTN_SEARCH
Position 146, 13 Title "Search"
Calling farmSearch
' other dialog stuff here
Control button ID BTN_FAKEOK
Position 61, 165 Title "OK"
Calling DoPrint
If bDialogClosed Then
' process normal stuff that would occurred on normal ok button
End If
End Sub
============================
' work around to capture the enter button in the EditText box
Sub preserveD
Dim bByFarm As Logical,
sFarmNo As String,
f As Float
sFarmNo = ReadControlValue(TXT_FARMNO)
f = Val(sFarmNo)
Call farmSearch ' populates the dialog controls using ALTER CONTROL
Dialog Preserve
End Sub
============================
Sub DoPrint
bPrintDialogClosed = true
Dialog Remove
End Sub
Notice how Alan-Frank sets the width and Height for the dialog. In this way, MapInfo Pro will not calculate the size of the dialog but use his values and so he is able to place a control outside of the dialog area.
And in the handler procedure for the OKButton
control, he uses Dialog Preserve
to keep the dialog on the screen.
Activating Hidden Control using an Alt shortcut key
A similar idea lies behind a trick I used some years back. I wanted to give myself and other administrators some additional settings but these shouldn't be visible to normal users. This could also just be the ability to for example add more values to a Listbox control.
I used the same idea of positioning a button outside of the visible area of the dialog. But instead of using an OKButton Control
, I used a normal Button Control
. To be able to activate it, I gave it a title with the "&" character. That character makes the following etter accessible through the Alt keyboard shortcut.
Control Button
Position 500, 500
Calling AdvancedSettings
Title "&Advanced Settings"
For the example above, I can use Alt + A to activate the button and so call the handler of the button.
Using the OKButton to Perform an Action
Instead of hiding the OKButton
, you can also give it a different title and make it appear to do different things. In the example below, I changed the title of the OKButton
control from "OK" to "Search".
Dialog
Title "Wildcard Search"
Calling DLGFUWCHandler_OnLoad
Control StaticText
Position 5,5
Width (DLGFUWCGetResultListWidth() - 50)
Title "Search for - use % and _ as wildcards"
'Search Controls
Control StaticText ID CTRL_LBL_SEARCH_FOR + 1
Position 5,15
Width DLGFUWCGetSearchControlWidth(1)
Title DLGFUWCGetSearchControlTitle(1)
Control EditText ID CTRL_TXT_SEARCH_FOR + 1
Position 5,25
Width DLGFUWCGetSearchControlWidth(1)
Value IIf(DLGFUWCGetSearchValue(1)="", DLGFUWCGetSearchMethodAsString(1), DLGFUWCGetSearchValue(1))
Control OKButton
Position (DLGFUWCGetResultListWidth() - 40), 15
Width 45 Height 24
Title "Search"
Calling DLGFUWCHandler_OKClicked
Control Listbox ID CTRL_LST_RESULTS
Position 5,40
Width DLGFUWCGetResultListWidth() Height DLGFUWCGetResultListHeight()
Calling DLGFUWCHandler_ResultListClicked
Control Button ID CTRL_CMD_SHOW_ALL
Position (DLGFUWCGetResultListWidth() - 40), (DLGFUWCGetResultListHeight() + 45)
Width 45
Title "Show all"
Calling DLGFUWCHandler_ShowAllClicked
Control CancelButton
Position (DLGFUWCGetResultListWidth() - 40), (DLGFUWCGetResultListHeight() + 65)
Width 45
Title "Close"
When the user clicks the OKButton
control or hits the Enter key on the keyboard, the handler of the OKButton
control is called and performs a search using the values entered. The results get loaded into the dialog through the ListBox control.
Once loaded, the user can click on the individual elements in this list to activate the handler for the Listbox
control.
Sub DLGFUWCHandler_ResultListClicked
OnError GoTo ErrorOccured
If CommandInfo(CMD_INFO_DLG_DBL) Then
'*The user double clicked a record - let's close down the dialog
Dialog Remove
Else
Dialog Preserve
End If
'Other commands to show the item the user clicked on
End Sub
In the handler procedure, I check if the user double-clicked. If she did, the dialog will get removed when the handler procedure finishes. If not, the dialog will stay on the screen.
This dialog does all the work while being on screen. So it's not important to capture that the user clicks the CancelButton. This will just remove the dialog.
You can find the full source code for this dialog on GitHub. It's part of the mbMultiSearchTool. Look in the module DLGFindUsingWildcard.mb.
Thanks again for giving me some input for this post, @Alan-Frank Vecchio! It's really appreciated. If you have some tips you want to share with the wider MapInfo Pro community, feel free to post directly to the MapInfo Pro community here, or reach out to me and I can share it in an upcoming #MapInfoMonday post.
------------------------------
Peter Horsbøll Møller
Principal Presales Consultant | Distinguished Engineer
Precisely | Trust in Data
------------------------------