MapInfo Pro Developers User Group

 View Only

Another way to use Python to automate or customize Pro

  • 1.  Another way to use Python to automate or customize Pro

    Employee
    Posted 07-14-2020 15:58
      |   view attached
    Using Microsoft's COM or OLE technology, many customers have create full applications the embed maps and other pro windows into their own applications. Other have use COM to connect to Pro, either visible or in the background to customize the UI or to automate tasks from other applications. Typically these were done via C++, Visual Basic, VB script, or .NET.

    This approach was de-emphasized but not eliminated for a while during the transition to 64 bit versions of Pro. Recently starting with version 2019.2 the development team has been putting more effort restoring the ability to embed maps, browser and certain tool windows, largely to support customers migrating their applications to newer version of Pro.

    One benefit of this for Python developers is that there are several good Python libraries for interacting with COM technologies to open up using Pro in this manner via Python.

    I am attaching two sample python scripts that demonstrate this to make you aware of the possibilities. Note that these will not work completely correctly until 2019.3 is released later this year.

    The samples will also be added to the PythonQuickStart app available in the MapInfo Marketplace.

    -Bob

    Here is the code from one of the samples:
    ### Description: Shows how to use COM/OLE technology to start and customize Pro from a python application.
    ### To Run this navigate to Python37 folder under Pro installation, launch prompt.bat and run 'python "COM OLE Customize Pro.py"'
    ### Category: COM/OLE
    
    # uncomment next 2 lines to debug
    #from mi_py_debugger import *
    #pro = attach_debugger()
    import os
    os.environ['QT_USE_NATIVE_WINDOWS'] = "1"
    import win32com.client
    import win32com.server.util
    import sys
    from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QHBoxLayout, QVBoxLayout, QPushButton, QGridLayout
    from PyQt5 import QtGui
    
    # implement OLE callback class to pass to MapInfo Pro 
    class MIOLECallback:
       def __init__(self, pro):
           self._pro = pro
    
       _public_methods_ = ['WindowContentsChanged', 'SetStatusText' , 'MenuItemHandler', 'SayHello']
       def WindowContentsChanged(self, windowId: int):
          self._pro.Do('print "WindowContentsChanged {}"'.format(windowId))
    
       def SetStatusText(self, message: str):
          self._pro.Do('print "SetStatusText: {}"'.format(message))
    
       def MenuItemHandler(self, commandInfo: str):
          self._pro.Do('print "MenuItemHandler: {}"'.format(commandInfo))
    
       def SayHello(self, commandInfo: str):
          self._pro.Do('print "Hello  {}"'.format(commandInfo))
    
    
    # create a custom dialog using QT, could be a login dialog or a welcome screen for your app
    class CustomQTDialog(QDialog):
       def __init__(self, *args, **kwargs):
    
          super(CustomQTDialog, self).__init__(*args, **kwargs)
          
          # Get MapInfo Pro Dispatch ID
          self._pro = win32com.client.Dispatch("MapInfo.Application.x64")
          
          # Register callback object
          callback = win32com.server.util.wrap(MIOLECallback(self._pro))
          self._pro.RegisterCallback(callback)
    
          
          self.setWindowTitle("Python IntegratedMapping")
          self.resize(300, 300)
          vlayout = QVBoxLayout()
          self._cLayout = QVBoxLayout()
          vlayout.addLayout(self._cLayout)
          
          hlayout = QHBoxLayout()
          b2 = QPushButton()
          b2.setText("Show MapInfo Pro")
          b2.clicked.connect(self.button_action_pro_visible)
          hlayout.addWidget(b2)
          vlayout.addLayout(hlayout)
          
          self.setLayout(vlayout)
    
       
       def button_action_pro_visible(self):
          if self._pro:
             # Get MapInfo Pro HWND
             phwnd = int(self._pro.Eval("SystemInfo(SYS_INFO_MAPINFOWND)"))
             self._pro.Do("Set Application Window {}".format(phwnd))
             # add button to spatial tab
             self._pro.Do('Alter ButtonPad "SpatialCreateBar" Add PushButton Calling OLE "SayHello" Large HelpMsg "Hello\\nSay Hello" Tab "TabSpatial" ')
    
             ## add two mapper menu items
             self._pro.Do("Alter Menu \"MapperShortcut\" Add \"Custom Item\" ID 10000 calling OLE \"MenuItemHandler\"")
             self._pro.Do("Alter Menu \"MapperShortcut\" add \"Layer Control\" ID 8001 calling 801")
    
             # give user control
             self._pro.Visible = True
    
       def __del__(self):
          if self._pro:
             self._pro = None
    
    def application():
       app = QApplication(sys.argv)
       try:
          qtdlg = CustomQTDialog()
          qtdlg.exec_()
       finally:
          app.exit()
    
    if __name__ == '__main__':
       application()


    ------------------------------
    Bob Fortin
    Software Architect and Distinguished Engineer
    MapInfo Pro Development Team
    ------------------------------

    Attachment(s)

    zip
    PythonScripts.zip   2 KB 1 version