| 29 | |
| 30 | |
| 31 | class Addin: |
| 32 | |
| 33 | def __init__(self, xlam_file:str, visible:bool=False) -> None: |
| 34 | '''The Excel add-in object, including ribbon UI and VBA modules. |
| 35 | |
| 36 | Args: |
| 37 | xlam_file (str): Add-in file path. |
| 38 | visible (bool): Process the add-in with Excel application running in the background if False. |
| 39 | ''' |
| 40 | # work path |
| 41 | self.xlam_file = xlam_file |
| 42 | self.path = os.path.dirname(xlam_file) |
| 43 | |
| 44 | # Add-in VBA modules |
| 45 | self.excel_app = win32com.client.Dispatch('Excel.Application') # win32 COM object |
| 46 | self.excel_app.Visible = visible |
| 47 | self.excel_app.DisplayAlerts = False |
| 48 | |
| 49 | |
| 50 | def close(self): |
| 51 | '''Close add-in and exit Excel.''' |
| 52 | self.excel_app.Application.Quit() |
| 53 | |
| 54 | |
| 55 | def create(self, vba_only:bool=False): |
| 56 | '''Create addin file. |
| 57 | - customize ribbon tab and associated VBA callback according to ui file |
| 58 | - include VBA modules, e.g., general VBA subroutines for data transferring. |
| 59 | |
| 60 | Args: |
| 61 | vba_only (bool, optional): Whether simple VBA addin (without Python related modules). |
| 62 | Defaults to False. |
| 63 | ''' |
| 64 | N = 2 if vba_only else 3 |
| 65 | |
| 66 | # 1 create addin file |
| 67 | logging.info('(1/%d) Creating add-in structure...', N) |
| 68 | ui = UI(self.xlam_file) |
| 69 | template = os.path.join(RESOURCE_PATH, RESOURCE_ADDIN) |
| 70 | custom_ui = os.path.join(self.path, CUSTOM_UI) |
| 71 | ui.create(template, custom_ui) |
| 72 | |
| 73 | if not os.path.exists(self.xlam_file): |
| 74 | raise AddInException('Create add-in structures failed.') |
| 75 | |
| 76 | # 2 update VBA modules |
| 77 | vba = VBA(xlam_file=self.xlam_file, excel_app=self.excel_app) |
| 78 | |
| 79 | # 2.1 import ribbon module |
| 80 | logging.info('(2/%d) Creating menu callback subroutines...', N) |
| 81 | base_menu = os.path.join(RESOURCE_PATH, RESOURCE_VBA, f'{VBA_MENU}.bas') |
| 82 | user_menu = os.path.join(RESOURCE_PATH, RESOURCE_VBA, f'{VBA_USER_MENU}.bas') |
| 83 | vba.import_module(base_menu) |
| 84 | vba.import_module(user_menu) |
| 85 | |
| 86 | # extra steps for VBA-Python combined addin |
| 87 | if not vba_only: |
| 88 | logging.info('(3/%d) Creating Python-VBA interaction modules...', N) |