Python Excel操作模块XlsxWriter之插入按钮 worksheet.insert_button()

本文介绍如何在Excel工作表中使用worksheet.insert_button()方法插入VBA按钮,并将其与宏关联,实现自动化任务。该方法接受指定行列位置及可选参数如宏名、按钮文字等。

worksheet.insert_button()

insert_button(row, col[, options])

向工作表插入一个VBA按钮控件。

参数:

  • row(int) - 单元格所在的行(索引从0开始计数)。
  • col(int) - 单元格所在的列(索引从0开始计数)。
  • options(dict) - 可选的按钮位置,缩放参数。

insert_button()方法可以用于向工作表插入Excel表单按钮。

这个方法通常仅在与工作簿add_vab_project()方法一起使用时才有用,以便将该按钮与嵌入VBA项目中的宏关联起来:

# 添加二进制VBA项目。
workbook.add_vba_project('./vbaProject.bin')

# 在VBA项目中添加按钮并与宏关联起来。
worksheet.insert_button('B3',{'macro':   'say_hello',
                              'caption': 'Press Me'})


insert_button()方法接收字典形式的可选参数来定位和缩放按钮。可用的参数和它们的默认值有:

{
    'macro':    None,
    'caption':  'Button 1',
    'width':    64,
    'height':   20.
    'x_offset': 0,
    'y_offset': 0,
    'x_scale':  1,
    'y_scale':  1,
}

marco选项是用于设置当用户点击时调用的宏。宏应当通过上面演示的工作簿的add_vba_project()方法来添加。

caption用于设置按钮的说明。默认是值是Button nn代表按钮的数量。

默认的按钮width是64像素,height是20像素,也就是单元格的默认宽度和高度。

offsetscale选项和insert_chart()的一样。

import sys import pandas as pd import pythoncom import win32com.client from PyQt5.QtWidgets import ( QApplication, QWidget, QLabel, QLineEdit, QPushButton, QFileDialog, QMessageBox, QVBoxLayout, QComboBox ) from PyQt5.QtCore import QTimer import numpy as np from 连接池模块 import POOL class ExcelImporter(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Excel 导入 MySQL 工具") self.resize(600, 350) self.file_path = "" self.excel_app = None self.timer = None self.type_combo = QComboBox() self.init_ui() def init_ui(self): layout = QVBoxLayout() # 文件路径选择 layout.addWidget(QLabel("选择 Excel 文件:")) self.file_path_edit = QLineEdit() self.browse_button = QPushButton("浏览") self.browse_button.clicked.connect(self.select_file) layout.addWidget(self.file_path_edit) layout.addWidget(self.browse_button) # 数据类型选择 layout.addWidget(QLabel("选择数据类型:")) self.type_combo.addItems(["临床诊断"]) layout.addWidget(self.type_combo) # 生成模板并打开 Excel 按钮 self.generate_button = QPushButton("生成模板并打开 Excel") self.generate_button.clicked.connect(self.open_excel_with_headers) layout.addWidget(self.generate_button) # 我已经编辑完成按钮 self.done_editing_button = QPushButton("我已经编辑完成") self.done_editing_button.clicked.connect(self.update_file_path) layout.addWidget(self.done_editing_button) # 表名输入框 layout.addWidget(QLabel("目标数据库表名:")) self.table_name_edit = QLineEdit() layout.addWidget(self.table_name_edit) # 导入按钮 self.import_button = QPushButton("导入数据库") self.import_button.clicked.connect(self.import_to_database) layout.addWidget(self.import_button) self.setLayout(layout) def select_file(self): file_path, _ = QFileDialog.getOpenFileName(self, "选择 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)") if file_path: self.file_path_edit.setText(file_path) self.file_path = file_path def open_excel_with_headers(self): selected_type = self.type_combo.currentText() headers_map = { "临床诊断": ["临床诊断", "首拼"], } headers = headers_map.get(selected_type) if not headers: QMessageBox.critical(self, "错误", "未定义该类型的数据结构") return if not self.file_path: QMessageBox.critical(self, "错误", "请先选择一个文件保存路径") return try: pythoncom.CoInitialize() self.excel_app = win32com.client.Dispatch("Excel.Application") self.excel_app.Visible = True workbook = self.excel_app.Workbooks.Add() worksheet = workbook.ActiveSheet # 写入表头 for col_num, data in enumerate(headers, 1): worksheet.Cells(1, col_num).Value = data # 保存文件 workbook.SaveAs(self.file_path) workbook.Close() # 释放资源 self.excel_app = None # 启动定时器检测 Excel 是否关闭 self.timer = QTimer() self.timer.timeout.connect(self.check_excel_closed) self.timer.start(3000) except Exception as e: QMessageBox.critical(self, "错误", f"启动 Excel 失败: {str(e)}") def check_excel_closed(self): try: # 检查 Excel 是否仍在运行 excel = win32com.client.GetActiveObject("Excel.Application") except Exception: self.timer.stop() QMessageBox.information(self, "提示", "Excel 已关闭,请继续导入数据") def update_file_path(self): if self.file_path: self.file_path_edit.setText(self.file_path) QMessageBox.information(self, "提示", "文件路径已更新") else: QMessageBox.critical(self, "错误", "没有可用的文件路径") def import_to_database(self): file_path = self.file_path_edit.text() table_name = self.table_name_edit.text() if not file_path: QMessageBox.critical(self, "错误", "请选择一个 Excel 文件") return if not table_name: QMessageBox.critical(self, "错误", "请输入目标数据库表名") return try: with POOL.connection() as conn: with conn.cursor() as cursor: df = pd.read_excel(file_path) if df.empty: QMessageBox.critical(self, "错误", "Excel 文件为空") return # 替换所有 NaN、inf、-inf 为 None df.replace([np.nan, np.inf, -np.inf], None, inplace=True) # 构建插入语句 if not table_name.isidentifier(): raise ValueError("表名包含非法字符") columns = ', '.join(df.columns.tolist()) placeholders = ', '.join(['%s'] * len(df.columns)) insert_sql = f"INSERT INTO `{table_name}` ({columns}) VALUES ({placeholders})" # 转换为元组列表 data = [tuple(row) for _, row in df.iterrows()] # 批量插入 cursor.executemany(insert_sql, data) conn.commit() QMessageBox.information(self, "成功", f"{cursor.rowcount} 条记录已成功导入到表 '{table_name}'") except Exception as e: try: conn.rollback() except: pass QMessageBox.critical(self, "错误", f"导入失败: {str(e)}") if __name__ == "__main__": app = QApplication(sys.argv) window = ExcelImporter() window.show() sys.exit(app.exec_()) 再加一个按钮让我选择excel的保存路径
07-26
class ExcelImporter(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Excel 导入 MySQL 工具") self.resize(600, 400) # 增加窗口高度以容纳新控件 self.last_created_excel = None # 记录最后创建Excel文件路径 self.templates = { "现病史": ["表现症状","问诊要点", "首拼"], "辩证治法": ["中医辩证","中医治法", "辩证首拼","代表方药"], "临床诊断": ["临床诊断", "首拼"], "验方": ["类型","病名", "证候","方名","方药","用法","功效"], "古方": ["来源", "方名", "方药", "用法", "功效", "注意"], "经方": ["类型", "方名","功效","组成","用法","价格"], "单方":["类型","功效","组成","用法"], "食疗方": ["类型", "方名", "功效", "组成", "用法"], "膳食方": ["类型", "方名", "功效", "组成", "用法"], "医嘱建议": ["医嘱建议"] } self.init_ui() def init_ui(self): layout = QVBoxLayout() # 模板选择区域 layout.addWidget(QLabel("选择模板:")) template_layout = QHBoxLayout() self.template_combo = QComboBox() self.template_combo.addItems(self.templates.keys()) template_layout.addWidget(self.template_combo) self.create_button = QPushButton("创建Excel") self.create_button.clicked.connect(self.create_excel_template) template_layout.addWidget(self.create_button) self.complete_button = QPushButton("我已编辑完成") self.complete_button.clicked.connect(self.on_complete_clicked) self.complete_button.setEnabled(False) # 初始禁用 template_layout.addWidget(self.complete_button) layout.addLayout(template_layout) # 文件路径输入框 layout.addWidget(QLabel("选择 Excel 文件:")) self.file_path_edit = QLineEdit() self.browse_button = QPushButton("浏览") self.browse_button.clicked.connect(self.select_file) file_layout = QHBoxLayout() file_layout.addWidget(self.file_path_edit) file_layout.addWidget(self.browse_button) layout.addLayout(file_layout) # 表名输入框 layout.addWidget(QLabel("目标数据库表名:")) self.table_name_edit = QLineEdit() layout.addWidget(self.table_name_edit) # 导入按钮 self.import_button = QPushButton("导入数据库") self.import_button.clicked.connect(self.import_to_database) layout.addWidget(self.import_button) self.setLayout(layout) def create_excel_template(self): """创建Excel模板并打开""" try: # 获取选中的模板名称 template_name = self.template_combo.currentText() # 创建临时Excel文件 with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as tmp: file_path = tmp.name self.last_created_excel = file_path # 创建DataFrame并写入列标题 headers = self.templates[template_name] df = pd.DataFrame(columns=headers) df.to_excel(self.last_created_excel, index=False) # 使用Excel 2013打开文件 excel = win32.gencache.EnsureDispatch('Excel.Application') excel.Visible = True workbook = excel.Workbooks.Open(os.path.abspath(self.last_created_excel)) worksheet = workbook.Sheets(1) # 获取第一个工作表 # 设置所有列宽为30 worksheet.Columns.ColumnWidth = 30 # 设置所有行高为25 worksheet.Rows.RowHeight = 25 # 设置自动换行 worksheet.Cells.WrapText = True # 获取标题行的列数 num_cols = len(headers) # 定义区域:从第一行到最后一行,列数为标题行的列数 start_cell = worksheet.Cells(1, 1) # 第一行第一列 end_cell = worksheet.Cells(worksheet.Rows.Count, num_cols) # 最后一行最后一列 table_range = worksheet.Range(start_cell, end_cell) # 设置边框样式 border_style = win32.constants.xlContinuous border_weight = win32.constants.xlThick # 加粗边框 black_color = 0x000000 # 黑色边框(Excel使用BGR格式) borders = table_range.Borders # 设置所有边框 for line in [ win32.constants.xlEdgeLeft, win32.constants.xlEdgeTop, win32.constants.xlEdgeBottom, win32.constants.xlEdgeRight, win32.constants.xlInsideVertical, win32.constants.xlInsideHorizontal, ]: border = borders.Item(line) border.LineStyle = border_style border.Color = black_color border.Weight = border_weight # 设置为加粗 # 启用"我已编辑完成"按钮 self.complete_button.setEnabled(True) QMessageBox.information(self, "成功", f"Excel模板已创建,请编辑后点击'我已编辑完成'") except Exception as e: QMessageBox.critical(self, "错误", f"创建Excel失败: {str(e)}") def generate_sp(self, s): """生成拼音首字母,全部小写""" if not isinstance(s, str) or not s.strip(): return "" # 处理中文字符串 if any('\u4e00' <= char <= '\u9fff' for char in s): # 获取拼音首字母,转为小写 initials = pypinyin.lazy_pinyin(s, style=pypinyin.Style.FIRST_LETTER) return ''.join(initials).lower() else: # 处理非中文(英文)名称 words = s.split() if not words: return "" # 取每个单词的首字母,转为小写 return ''.join(word[0].lower() for word in words if word) def on_complete_clicked(self): """处理编辑完成按钮点击事件,生成首拼列""" if not self.last_created_excel or not os.path.exists(self.last_created_excel): QMessageBox.warning(self, "警告", "未找到创建Excel文件") return try: # 读取Excel文件 df = pd.read_excel(self.last_created_excel) # 获取模板类型 template_name = self.template_combo.currentText() # 定义需要生成首拼的模板类型 templates_with_shoupin = ["现病史", "辩证治法", "临床诊断"] # 如果当前模板不需要生成首拼,跳过生成首拼的逻辑 if template_name in templates_with_shoupin: # 确定源列名 if template_name == "现病史": source_col = "表现症状" elif template_name == "辩证治法": source_col = "中医辩证" elif template_name == "临床诊断": source_col = "临床诊断" # 检查源列是否存在 if source_col not in df.columns: QMessageBox.critical(self, "错误", f"Excel文件中缺少'{source_col}'列") return # 处理空值 df[source_col] = df[source_col].fillna('') # 仅在对应的源列生成首拼 df['首拼'] = df[source_col].apply(self.generate_sp) # 保存回Excel文件 df.to_excel(self.last_created_excel, index=False) # 提示用户 QMessageBox.information(self, "成功", "首拼已自动生成并填充!") else: # 如果不需要生成首拼,可以在这添加其他逻辑(可选) pass # 当前不做任何处理 # 设置文件路径和表名(这部分无论是否生成首拼都执行) self.file_path_edit.setText(self.last_created_excel) self.table_name_edit.setText(template_name) self.complete_button.setEnabled(False) # 重置按钮状态 except Exception as e: QMessageBox.critical(self, "错误", f"操作失败: {str(e)}") def select_file(self): file_path, _ = QFileDialog.getOpenFileName(self, "选择 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)") if file_path: self.file_path_edit.setText(file_path) def import_to_database(self): file_path = self.file_path_edit.text() table_name = self.table_name_edit.text() if not file_path: QMessageBox.critical(self, "错误", "请选择一个 Excel 文件") return if not table_name: QMessageBox.critical(self, "错误", "请输入目标数据库表名") return try: with POOL.connection() as conn: with conn.cursor() as cursor: df = pd.read_excel(file_path) if df.empty: QMessageBox.critical(self, "错误", "Excel 文件为空") return # 替换所有 NaN、inf、-inf 为 None df.replace([np.nan, np.inf, -np.inf], None, inplace=True) # 构建插入语句 if not table_name.isidentifier(): raise ValueError("表名包含非法字符") columns = ', '.join(df.columns.tolist()) placeholders = ', '.join(['%s'] * len(df.columns)) insert_sql = f"INSERT INTO `{table_name}` ({columns}) VALUES ({placeholders})" # 转换为元组列表 data = [tuple(row) for _, row in df.iterrows()] # 批量插入 cursor.executemany(insert_sql, data) conn.commit() QMessageBox.information(self, "成功", f"{cursor.rowcount} 条记录已成功导入到表 '{table_name}'") except Exception as e: try: conn.rollback() except: pass QMessageBox.critical(self, "错误", f"导入失败: {str(e)}") 我想再加一个按钮,能够导入sql文件到mysql数据库,我已经在sql文件指定了要存的位置
08-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值