MapInfo Pro

 View Only

MapBasic Monday: Tips for building Dialogs I

  • 1.  MapBasic Monday: Tips for building Dialogs I

    Posted 08-21-2023 04:56
    Edited by Peter Møller 08-21-2023 07:11

    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.

    	[ 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()
            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".

    		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 Listboxcontrol.

    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
    		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