MapInfo Pro

 View Only

MapBasic Monday: Building a Simple Ribbon Interface

  • 1.  MapBasic Monday: Building a Simple Ribbon Interface

    Employee
    Posted 02-20-2023 06:36
      |   view attached

    Happy #mapinfomonday 

    In today's article, we will continue down the path of building our first MapBasic application. You can find the earlier articles on this topic here.

    Until now, we had to run our application for it to perform its task. We will now integrate it into the ribbon interface of MapInfo Pro so that we easily can use the functionality of the tool. This means that we need to restructure our code a bit again, I will show you have you easily can add buttons to the ribbon, and we will make our code a bit more clever so that it can detect if a map already exists. Finally, we will add another table that the tool can open doubling the capability of the tool.

    Are you ready? Let's get started!

    Restructuring the Code - again

    As I mentioned in an earlier article, you will often use the Main procedure to integrate your tool into the interface, and then let it wait for the user to request functionality to be executed by clicking on a button. That's what we will do now.

    We will move the current code from the Main procedure into a new procedure called OpenTableCustomers. We will also make a slight change to the code to make it easier to adapt to other tables we might want to open.

    The new procedure will look like this:

    '******************************************************************
    'Sub OpenTableCatchmentAreas: Open a specific table
    '******************************************************************
    Sub OpenTableCatchmentAreas
    
    Dim nMID As Integer,
    	sTabFile As String
    
    	sTabFile	= "C:\3. Demo\2. Maps\2023\Site Selection\Customers\Catchment Areas.TAB"
    	nMID		= OpenTableIntoMap(sTabFile)
    	Call ConfigureLayer(nMID, sTabFile)
    
    End Sub

    I added a new variable, sTabFile, to hold the name of the table to open. From the name of the variable, you can see that it is of type String and that it holds the name of a MapInfo Native tab file.

    By adding this variable and passing it to the function and the procedure, I only need to change the name of the tab file in one place.

    The Main procedure now holds no code but we will change that in the next chapter.

    Adding a PushButton to the Ribbon

    It's now time to add a button to the ribbon.

    When you want to add a button to the ribbon, you place it in a given tab (see (1) below), and in a given tab group (see (2) below).

    We want to add our button to the Home tab in the File group. When specifying these, you need to know their internal names. What you see on the ribbon is their caption. With MapBasic v2021, we have included a file containing all the names as constants. We can use these instead of the names, and this file also gives us access to finding the internal names.

    To use the defines, or the constants, we need to include this file in our source code file. We will also include another file that holds constants often used, MapBasic.def.

    You typically include these files at the top of your source code:

    Include "MapBasic.def"
    Include "RibbonControls.def"

    The two constants we need to determine the name of the tab and tab group are these:

    DEFINE TAB_HOME								"TabHome"
    DEFINE TAB_HOME_FILE_GRP					"HomeFile"

    Each line has three elements: 1) the Define keyword, 2) the name of the constant, and 3) the value that the constant refers to, here the name of the tab and tab group. To use such a constant, you simply insert the name of the constant. When you compile your source file, the compile will replace the constant name with the value that it refers to.

    The benefit of using a constant instead of the actual value is that the value might change over time, and for some values, it can be hard to see what it actually means. This is especially the case where a constant refers to a numerical value.

    You have several ways to add a button to the ribbon through MapBasic. For this simple example, we will use the Alter Buttonpad statement to add a PushButton. In a later article, we will use other ways when we need more control over the placement of the button or when we want to add more advanced controls such as SplitButtons.

    We use Alter Buttonpad as we want to add the buttons to an existing group. If you want to create a new group on an existing or a new tab, you can use Create Buttonpad to do so. This code needs to go into the Main procedure

    Alter ButtonPad TAB_HOME_FILE_GRP
    	Add PushButton
    		Calling OpenTableCustomers
    		Large Icon -1 File ApplicationDirectory$() & "Customers 64x64.png"
    		HelpMsg "Open Table Customers\nCustomers"
    	Tab TAB_HOME
    

    In the code above, you can see that I add a PushButton to the File group on the Home tab.

    When the user clicks on the button, the procedure OpenTableCustomers will get called and executed.

    I have configured the button to use a large button where the icon to show on the button is stored in a file in the same folder as my application. ApplicationDirectory$() returns the folder where the application file is located.

    I have created the icon by taking a screen dump of MapInfo Pro after opening the table into a map window. I then dragged the image towards the upper left until the top left of the map window was at the upper left of the image. I then changed the size of the image to 64 by 64 pixels. You can also save the image as a 32 by 32-pixel image as that is the standard size for large icons.
    The HelpMsg is divided into two parts by \n. The first part is the tooltip that will appear when you hold the cursor on top of the button. This is often a longer description of what the button does. The second part is the caption of the button shown under the button on the ribbon.
    This is how the button looks on the ribbon. The button is shown as the 6th button from the left.

    When I click on the button, the table will get opened into a new map window.

    Make the OpenTableIntoMap Code more Clever

    Until now, the OpenTableIntoMap procedure would open the table and create a new map window for this table. We now want to change this so that it will add the table to the currently active window if it's a map window. This is probably the behavior most users would expect.

    Here is the modified procedure

    '******************************************************************
    'Function OpenTableIntoMap: This function opens a table into a map window
    ' takes a name of a tab file to open
    ' returns the Window ID of the map now showing the table
    '******************************************************************
    Function OpenTableIntoMap( ByVal sTabFile As String) As Integer
    
    Dim nMID As Integer
    
    	Open Table sTabFile Interactive
    
    	nMID = FrontWindow()
    	If nMID <> 0 Then
    		If Not WindowInfo(nMID, WIN_INFO_TYPE) = WIN_MAPPER Then
    			nMID = 0
    		End If
    	End If
    
    	If nMID = 0 Then
    		Map From PathToTableName$(sTabFile)
    		nMID = FrontWindow()
    	Else
    		Add Map
    			Window nMID Auto
    			Layer PathToTableName$(sTabFile)
    	End If
    
    	OpenTableIntoMap = nMID
    
    End Function

    I use the function FrontWindow() to determine the ID of the active window. If the value is 0, I know there is no active window and so also no map window.

    If the value is not 0, I need to check the type of the active window. I use the WindowInfo() function to return the type of the map. The constant WIN_INFO_TYPE comes from the file MapBasic.def and refers to the numeric value 3. Using this constant instead of the numeric value makes it much easier to read the code later on. If the active window isn't a map window, I set the value of the nMID variable to 0. This value is later used to determine if the table should be added to an existing map window or to a new map window.

    Finally, I check the value of the variable nMID. If it's 0, I create a new map window. Otherwise, I use the statement Add Map to add the table to an existing map window. The keyword Auto tells MapInfo Pro to automatically determine at what position to place the layer based on the objects in the table and the objects in the other layers.

    I have used the If Then statement to handle the flow of the procedure. You can use the If Then statement to check if a condition is met before performing a certain action, and you can use the Else part of the statement to add an alternative way for your code to move if the condition isn't met. Note how I'm using indention to make it easier to follow the flow of the procedure based on the conditions.

    The function now returns the value stored in the variable nMID as this variable now holds the ID of the existing map window or the new map window.

    Compile your source code and run it. Push the button to see if it still works. remember that you need to test this with no windows open, an existing map window open, and a browser window open.

    Opening an Additional Table

    We have now built a structure in our tool that makes it possible to add additional tables with just minor changes to our code. To test this, I will add an additional table. Just like for the first table, I open the MapBasic window and then I open a configure the second table. I can now copy the Set Map statements that I need to be able to configure the layer as I want it to look after opening it.

    Set Map Window 3010  Layer 2 Display Global  Global Pen (5,6,16711680)   Global Brush (1,16777215,16777215)    
    Set Map Window 3010  Layer 2 Selectable Off

    Just like previously, I need to modify these slightly. I will get back to this as we also need to modify the structure of the ConfigureLayer procedure.

    Until now this procedure has just had to deal with one layer but now we add another. This means we need to determine what layer we are asked to configure. We can use the name of the table to do so. We just have to build a structure that can split the code based on the table name. We are looking at two tables now but that could grow when we start adding more so the best option is probably to use the Do Case statement to handle this.

    '******************************************************************
    'Sub ConfigureLayer: This procedure configures the layer
    ' takes the Window ID of the map with the layer
    ' takes the name of a tab file to confire
    '******************************************************************
    Sub ConfigureLayer( ByVal nMID As Integer, ByVal sTabFile As String)
    
    Dim	sTab As String
    
    	sTab = PathToTableName$(sTabFile)
    
    	Do Case sTab
    		Case "Customers"
    			Set Map Window nMID Layer sTab Display Global     Global Symbol (38,16754768,8,"MapInfo Symbols",256,0)  
    			Set Map Window nMID Layer sTab Label Auto On
    			Set Map Window nMID Layer sTab Label With Contract
    		Case "Catchment_Areas"
    			Set Map Window nMID Layer sTab Display Global  Global Pen (5,6,16711680)   Global Brush (1,16777215,16777215)    
    			Set Map Window nMID Layer sTab Selectable Off
    	End Case
    
    End Sub

    I create a new variable sTab to hold the name of the table once opened into MapInfo Pro. I need this when configuring the layer through the Set Map statement, and I now also need it to determine what table is being configured. You can also see the modified Set Map statements for the second table above.

    I use the Do Case statement to determine what settings to use. Do Case sTab tells MapInfo Pro to compare the value in the variable sTab against a number of possible values. Case "Customers" is the first of the options where "Customers" is the value to compare against. If the value in the variable matches this value, the code after will get executed. If not, MapInfo Pro will continue comparing against the next value. Notice that only the first match will be used. Once a match has been made, no more matches can be made. Similarly to Else for the If Then statement, I can also use Case Else to catch all the cases that didn't find a match. In our example, we don't need this.

    Finally, I need to add an additional button to the ribbon in the Main procedure. Notice how I just add another PushButton element to the Alter ButtonPad statement. The Add keyword should only be there once.

    Alter ButtonPad TAB_HOME_FILE_GRP
    	Add PushButton
    		Calling OpenTableCustomers
    		Large Icon -1 File ApplicationDirectory$() & "Customers 64x64.png"
    		HelpMsg "Open Table Customers\nCustomers"
    	PushButton
    		Calling OpenTableCatchmentAreas
    		Large Icon -1 File ApplicationDirectory$() & "Catchment Areas 64x64.png"
    		HelpMsg "Open Table Catchment Areas\nCatchment Areas"
    	Tab TAB_HOME
    

    And I need a dedicated procedure for this table too:

    '******************************************************************
    'Sub OpenTableCatchmentAreas: Open a specific table
    '******************************************************************
    Sub OpenTableCatchmentAreas
    
    Dim nMID As Integer,
    	sTabFile As String
    
    	sTabFile	= "C:\3. Demo\2. Maps\2023\Site Selection\Customers\Catchment Areas.TAB"
    	nMID		= OpenTableIntoMap(sTabFile)
    	Call ConfigureLayer(nMID, sTabFile)
    
    End Sub
    

    Remember to add the declaration for this new procedure so that you now have all these declarations for your functions and procedures:

    Declare Sub Main
    Declare Sub EndHandler
    Declare Sub OpenTableCustomers
    Declare Sub OpenTableCatchmentAreas
    
    Declare Function OpenTableIntoMap( ByVal sTabFile As String) As Integer
    Declare Sub ConfigureLayer( ByVal nMID As Integer, ByVal sTabFile As String)

    Compile and run your tool and check that you now have two buttons and that each button will open and configure the table.

    Are you still here? This got a bit longer than I had expected. Next time we will keep it a bit shorter and see how you can integrate your tool better into the Tools Window.

    Find the sample code attached below, including the icons I created.



    ------------------------------
    Peter Horsbøll Møller
    Principal Presales Consultant | Distinguished Engineer
    Precisely | Trust in Data
    ------------------------------

    Attachment(s)