# =================================================================== # extraer_combos_sap.py # Función standalone para extraer combinaciones de SAP2000 # =================================================================== import os import tkinter as tk from tkinter.filedialog import asksaveasfilename from openpyxl import Workbook from openpyxl.styles import Font, PatternFill, Alignment, Border, Side from openpyxl.utils import get_column_letter # Colores exactos de SAP2000 AZUL_TITULO = "33CCCC" # Azul oscurito título AZUL_SAP = "CCFFFF" # Azul marino cabecera # Barra de progreso (la misma que usas en el script principal) def printProgressBar(iteration, total, prefix='', suffix='', decimals=1, length=50, fill='█'): percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) filledLength = int(length * iteration // total) bar = fill * filledLength + '-' * (length - filledLength) print(f'\r{prefix} |{bar}| {percent}% {suffix}', end="") if iteration == total: print() def extraer_combinaciones_a_excel(SapModel, ruta_excel_origen=None): """ Extrae todas las combinaciones de SAP2000 y las guarda en Excel con el formato EXACTO del reporte oficial de SAP2000. Parámetros: SapModel: objeto SAP2000 ya conectado ruta_excel_origen: (opcional) ruta del Excel original para sugerir nombre y carpeta """ # --- Ventana para guardar --- root = tk.Tk() root.withdraw() root.attributes('-topmost', True) # Sugerir nombre y carpeta inteligente if ruta_excel_origen and os.path.exists(ruta_excel_origen): carpeta = os.path.dirname(ruta_excel_origen) nombre_base = os.path.splitext(os.path.basename(ruta_excel_origen))[0] nombre_sugerido = f"{nombre_base}_COMBINACIONES_SAP2000.xlsx" initialfile = nombre_sugerido else: initialfile = "COMBINACIONES_SAP2000.xlsx" archivo_salida = asksaveasfilename( initialfile=initialfile, defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")], title="Guardar combinaciones (formato SAP2000)" ) root.destroy() if not archivo_salida: print("\nExportación cancelada por el usuario.") return # --- Extraer combinaciones --- ret = SapModel.RespCombo.GetNameList() num_combos = ret[0] combo_names = ret[1] datos = [] print(f"\nExtrayendo {num_combos} combinaciones con formato oficial SAP2000...") for i, combo_name in enumerate(combo_names): tipo = SapModel.RespCombo.GetTypeOAPI(combo_name)[0] tipo_texto = "Linear Add" if tipo == 0 else "Envelope" if tipo == 1 else "Other" casos = SapModel.RespCombo.GetCaseList(combo_name) nombres_casos = casos[2] factores = casos[3] if len(nombres_casos) == 0: datos.append([combo_name, tipo_texto, "", ""]) else: for j, caso in enumerate(nombres_casos): if j == 0: datos.append([combo_name, tipo_texto, caso, factores[j]]) else: datos.append(["", "", caso, factores[j]]) printProgressBar(i + 1, num_combos, prefix="Progreso:", suffix="Completado", length=50) # --- Crear Excel con formato idéntico a SAP2000 --- wb = Workbook() ws = wb.active ws.title = "Combinaciones" # 1. Título ws['A1'] = "TABLE: Combination Definitions" ws['A1'].font = Font(name="Arial Narrow", size=11, bold=True) ws['A1'].alignment = Alignment(horizontal="center") ws['A1'].fill = PatternFill(start_color=AZUL_TITULO, end_color=AZUL_TITULO, fill_type="solid") ws.merge_cells('A1:D1') # 2. Cabeceras (azul marino SAP2000) cabeceras = ["ComboName", "ComboType", "CaseName", "ScaleFactor"] for c, texto in enumerate(cabeceras, 1): cell = ws.cell(row=2, column=c, value=texto) cell.font = Font(name="Arial Narrow", bold=True, color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 3. Tipos de datos (amarillo SAP2000) tipos = ["Text", "Text", "Text", "Unitless"] for c, texto in enumerate(tipos, 1): cell = ws.cell(row=3, column=c, value=texto) cell.font = Font(name="Arial Narrow", color="000000", size=10) cell.fill = PatternFill(start_color=AZUL_SAP, end_color=AZUL_SAP, fill_type="solid") cell.alignment = Alignment(horizontal="center") # 4. Datos for r, fila in enumerate(datos, start=4): for c, valor in enumerate(fila, 1): cell = ws.cell(row=r, column=c, value=valor) cell.font = Font(name="Arial Narrow", size=10) # Aplicar borde fino a todas las celdas thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for row in ws.iter_rows(): for cell in row: cell.border = thin_border # Autoajustar columnas según el contenido (excluyendo la primera fila que está fusionada) column_widths = {1: 18, 2: 12, 3: 25, 4: 12} # Anchos por defecto for row in ws.iter_rows(min_row=2, max_row=ws.max_row): # Comienza desde fila 2 for col_idx, cell in enumerate(row, 1): if cell.value: cell_len = len(str(cell.value)) if col_idx in column_widths: column_widths[col_idx] = max(column_widths[col_idx], cell_len) for col_idx, width in column_widths.items(): ws.column_dimensions[get_column_letter(col_idx)].width = width # Guardar wb.save(archivo_salida) print(f"\nCOMBINACIONES EXTRAÍDAS CORRECTAMENTE") print(f"Archivo: {archivo_salida}")