Python Excel字符截取工具开发与实现
相关资源文件已经打包成EXE文件,可双击直接运行程序,且文章末尾已附上相关源码,以供大家学习交流,博主主页还有更多Python相关程序案例,秉着开源精神的想法,望大家喜欢,点个关注不迷路!!!
1. 简介:
这是一款使用PyQt5和Pandas开发的Excel字符截取工具。该工具通过图形化界面为用户提供了一个简便的方式来对Excel表格中的文本进行截取处理,支持按指定字符数从左侧或右侧截取,或者自定义截取范围。除了字符截取外,工具还提供了导出Excel、撤销操作等功能,并通过进度条和消息提示框为用户提供实时反馈。
2.功能及使用:
-
打开Excel文件:
- 用户可以通过点击“打开Excel文件”按钮选择本地的Excel文件,并将文件加载到表格中展示。
- 支持拖拽文件的功能,用户可以直接将Excel文件拖拽到应用窗口进行加载。
-
列选择:
- 用户可以通过复选框选择需要处理的列,选中的列会被高亮显示,未选择的列不参与处理。
- 确保至少选择一个列后,才可以点击“立即截取”按钮。
-
截取方式选择:
- 用户可以选择不同的截取方式,包括:
- 左截取:按指定字符数从左侧截取。
- 右截取:按指定字符数从右侧截取。
- 自定义截取范围:通过输入范围(如1-5)来指定截取的字符范围。
- 用户可以选择不同的截取方式,包括:
-
立即截取:
- 选择截取方式并输入相应参数后,点击“立即截取”按钮即可对选中的列进行字符截取操作。
- 截取进度通过进度条显示,并在完成后弹出提示框告知用户结果。
-
撤销操作:
- 用户可以通过“撤销操作”按钮恢复到上一步操作的状态,避免误操作。
-
导出Excel文件:
- 用户可以将处理后的数据导出为新的Excel文件,保存时可以选择文件路径和文件名。
-
进度条与提示框:
- 工具提供了进度条,用户可以实时看到操作的进度。
- 操作完成后,弹出成功提示框,告知用户结果。
-
界面美观与交互设计:
- 通过设置自定义样式、图标和字体,使得界面更加美观易用。
3. 运行效果:
主界面
处理前
处理后
撤销操作
表格数据导出
4. 总结:
这款基于PyQt5和Pandas开发的Excel字符截取工具,旨在为用户提供一个简单直观的界面来处理Excel表格中的数据。通过支持不同的截取方式、实时反馈、撤销操作等功能,工具能够高效地帮助用户完成字符截取任务。此外,进度条和提示框的设计为用户提供了友好的交互体验,使得整个操作过程更加流畅和易于理解。
5. 相关源码:
import sys
import pandas as pd
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLineEdit, QFileDialog, QTableWidget, QTableWidgetItem, QCheckBox, QLabel, QRadioButton, QProgressBar, QMessageBox
from PyQt5.QtGui import QColor, QFont, QDragEnterEvent, QDropEvent, QIcon
from PyQt5.QtCore import Qt
class ExcelProcessor(QWidget):
def __init__(self):
super().__init__()
self.setWindowIcon(QIcon("icon.ico")) # 设置窗口的图标,icon.ico是图标文件
self.setWindowTitle("Excel字符截取工具")
self.setGeometry(100, 100, 800, 500)
self.setStyleSheet("background-color: #f0f0f0;") # 设置背景颜色
self.layout = QVBoxLayout()
# 设置字体
font = QFont("Segoe UI", 20)
self.setFont(font)
# 文件选择按钮
self.file_button = QPushButton("打开Excel文件")
self.file_button.setStyleSheet("background-color: #4CAF50; color: white; padding: 5px 10px; border-radius: 5px;")
self.file_button.clicked.connect(self.open_file)
self.layout.addWidget(self.file_button)
# 表格展示区域
self.table_widget = QTableWidget()
self.table_widget.setStyleSheet("background-color: white; border: 1px solid #ccc;")
self.layout.addWidget(self.table_widget)
# 选择列标签
self.column_label = QLabel("请选择要处理的列:")
self.column_label.setStyleSheet("font-weight: bold; margin-top: 10px;")
self.layout.addWidget(self.column_label)
# 复选框水平布局
self.column_layout = QHBoxLayout()
self.layout.addLayout(self.column_layout)
# 截取方式标签
self.cut_option_label = QLabel("请选择截取方式:")
self.cut_option_label.setStyleSheet("font-weight: bold; margin-top: 10px;")
self.layout.addWidget(self.cut_option_label)
# 截取方式单选框
self.cut_option_layout = QHBoxLayout()
self.left_cut_radio = QRadioButton("左截取")
self.right_cut_radio = QRadioButton("右截取")
self.custom_range_radio = QRadioButton("自定义截取范围")
self.cut_option_layout.addWidget(self.left_cut_radio)
self.cut_option_layout.addWidget(self.right_cut_radio)
self.cut_option_layout.addWidget(self.custom_range_radio)
self.layout.addLayout(self.cut_option_layout)
# 左右截取输入框的水平布局
self.h_layout = QHBoxLayout()
self.left_input = QLineEdit(self)
self.left_input.setPlaceholderText("请输入左截取字符数")
self.right_input = QLineEdit(self)
self.right_input.setPlaceholderText("请输入右截取字符数")
self.h_layout.addWidget(self.left_input)
self.h_layout.addWidget(self.right_input)
self.layout.addLayout(self.h_layout)
# 自定义截取范围输入框
self.range_input = QLineEdit(self)
self.range_input.setPlaceholderText("请输入自定义截取范围,例如: 1-5")
self.layout.addWidget(self.range_input)
# 进度条
self.progress_bar = QProgressBar(self)
self.progress_bar.setStyleSheet("QProgressBar { border: 2px solid grey; border-radius: 5px; text-align: center; }")
self.layout.addWidget(self.progress_bar)
# 控件水平布局
self.top_layout = QHBoxLayout()
# 立即截取和导出Excel按钮
self.apply_button = QPushButton("立即截取")
self.apply_button.setEnabled(False)
self.apply_button.setStyleSheet("background-color: #2196F3; color: white; padding: 5px 10px; border-radius: 5px;")
self.apply_button.clicked.connect(self.apply_cut)
self.export_button = QPushButton("导出Excel")
self.export_button.setStyleSheet("background-color: #FF5722; color: white; padding: 5px 10px; border-radius: 5px;")
self.export_button.clicked.connect(self.export_to_excel)
self.top_layout.addWidget(self.apply_button)
self.top_layout.addWidget(self.export_button)
# 撤销操作和退出程序按钮
self.bottom_layout = QHBoxLayout()
self.undo_button = QPushButton("撤销操作")
self.undo_button.setStyleSheet("background-color: #FFC107; color: white; padding: 5px 10px; border-radius: 5px;")
self.undo_button.clicked.connect(self.undo_last_change)
self.exit_button = QPushButton("退出程序")
self.exit_button.setStyleSheet("background-color: #F44336; color: white; padding: 5px 10px; border-radius: 5px;")
self.exit_button.clicked.connect(self.close)
self.bottom_layout.addWidget(self.undo_button)
self.bottom_layout.addWidget(self.exit_button)
self.layout.addLayout(self.top_layout)
self.layout.addLayout(self.bottom_layout)
self.setLayout(self.layout)
self.df = None
self.history = [] # 用于保存历史记录,以便撤销
self.column_checkboxes = [] # 存储列的复选框
# 连接单选框,选择时启用/禁用相应的输入框
self.left_cut_radio.clicked.connect(self.toggle_input_state)
self.right_cut_radio.clicked.connect(self.toggle_input_state)
self.custom_range_radio.clicked.connect(self.toggle_input_state)
# 启用拖放功能
self.setAcceptDrops(True)
def open_file(self):
"""打开Excel文件并展示数据"""
options = QFileDialog.Options()
file_path, _ = QFileDialog.getOpenFileName(self, "打开Excel文件", "", "Excel 文件 (*.xlsx)", options=options)
if file_path:
self.df = self.read_excel(file_path)
if self.df is not None:
self.save_to_history() # 保存初始状态,支持撤销
self.update_table()
def dragEnterEvent(self, event: QDragEnterEvent):
"""处理拖拽事件,支持拖拽文件到窗口"""
if event.mimeData().hasUrls():
event.acceptProposedAction()
def dropEvent(self, event: QDropEvent):
"""处理拖拽放置事件,获取文件路径并打开Excel文件"""
file_urls = event.mimeData().urls()
if file_urls:
file_path = file_urls[0].toLocalFile()
if file_path.endswith(".xlsx"):
self.df = self.read_excel(file_path)
if self.df is not None:
self.save_to_history() # 保存初始状态,支持撤销
self.update_table()
def read_excel(self, file_path):
"""读取Excel文件并返回DataFrame"""
try:
return pd.read_excel(file_path, engine='openpyxl', header=None) # 不使用第一行作为列名
except Exception as e:
print(f"读取文件错误: {e}")
self.show_error_message(f"读取文件错误: {e}")
return None
def update_table(self):
"""更新QTableWidget,展示DataFrame中的数据"""
if self.df is not None:
self.table_widget.setRowCount(self.df.shape[0])
self.table_widget.setColumnCount(self.df.shape[1])
# 设置列名
self.table_widget.setHorizontalHeaderLabels([self.get_column_name(i) for i in range(self.df.shape[1])])
# 填充表格内容
for row in range(self.df.shape[0]):
for col in range(self.df.shape[1]):
value = self.df.iat[row, col]
if pd.isna(value):
value = ""
self.table_widget.setItem(row, col, QTableWidgetItem(str(value)))
# 更新列选择复选框
self.update_column_checkboxes()
def update_column_checkboxes(self):
"""更新列选择复选框"""
for checkbox in self.column_checkboxes:
checkbox.setParent(None)
self.column_checkboxes.clear()
for i in range(self.df.shape[1]):
checkbox = QCheckBox(self.get_column_name(i), self)
self.column_checkboxes.append(checkbox)
self.column_layout.addWidget(checkbox)
self.apply_button.setEnabled(False)
for checkbox in self.column_checkboxes:
checkbox.stateChanged.connect(self.check_column_selection)
def get_column_name(self, col_index):
"""生成Excel风格的列名 (A, B, C...)"""
col_name = ''
while col_index >= 0:
col_name = chr(col_index % 26 + 65) + col_name
col_index = col_index // 26 - 1
return col_name
def check_column_selection(self):
"""检查至少选中了一个列,并启用应用按钮,同时高亮显示选中的列"""
if any(checkbox.isChecked() for checkbox in self.column_checkboxes):
self.apply_button.setEnabled(True)
else:
self.apply_button.setEnabled(False)
# 重置进度条
self.progress_bar.setValue(0)
# 遍历所有的复选框,根据选中状态高亮显示相应列
for i, checkbox in enumerate(self.column_checkboxes):
if checkbox.isChecked():
self.highlight_column(i, QColor(255, 255, 0)) # 高亮显示,黄色
else:
self.reset_column(i)
def highlight_column(self, column_index, color):
"""高亮显示指定的列"""
for row in range(self.df.shape[0]):
item = self.table_widget.item(row, column_index)
if item:
item.setBackground(color)
def reset_column(self, column_index):
"""恢复列的默认背景色"""
for row in range(self.df.shape[0]):
item = self.table_widget.item(row, column_index)
if item:
item.setBackground(QColor(255, 255, 255)) # 白色背景
def toggle_input_state(self):
"""根据选择的截取方式,启用相应的输入框"""
self.left_input.setEnabled(False)
self.right_input.setEnabled(False)
self.range_input.setEnabled(False)
if self.left_cut_radio.isChecked():
self.left_input.setEnabled(True)
elif self.right_cut_radio.isChecked():
self.right_input.setEnabled(True)
elif self.custom_range_radio.isChecked():
self.range_input.setEnabled(True)
def apply_cut(self):
"""根据输入值立即应用截取操作"""
if self.df is not None:
try:
self.save_to_history()
left_chars = int(self.left_input.text()) if self.left_input.text().isdigit() else 0
right_chars = int(self.right_input.text()) if self.right_input.text().isdigit() else 0
range_input = self.range_input.text()
if range_input:
start, end = self.parse_range_input(range_input)
if start is not None and end is not None:
self.apply_custom_range_cut(start, end)
selected_columns = [i for i, checkbox in enumerate(self.column_checkboxes) if checkbox.isChecked()]
total_steps = len(selected_columns) # 每个列一个步骤
self.progress_bar.setMaximum(total_steps) # 设置进度条最大值为选中的列数
for step, selected_column in enumerate(selected_columns):
self.df[selected_column] = self.df[selected_column].astype(str)
if self.left_cut_radio.isChecked():
self.df[selected_column] = self.df[selected_column].str[:left_chars]
elif self.right_cut_radio.isChecked():
self.df[selected_column] = self.df[selected_column].str[-right_chars:]
# 更新进度条
self.progress_bar.setValue(step + 1)
self.update_table()
self.show_success_message("字符截取成功!")
except Exception as e:
self.show_error_message(f"应用截取时发生错误: {e}")
def parse_range_input(self, input_text):
"""解析自定义范围输入 (如 1-5)"""
try:
start, end = map(int, input_text.split('-'))
return start - 1, end # 转换为从零开始的索引
except ValueError:
return None, None
def apply_custom_range_cut(self, start, end):
"""应用自定义截取范围"""
for i in range(self.df.shape[1]):
self.df.iloc[:, i] = self.df.iloc[:, i].astype(str).apply(lambda x: x[start:end])
def show_error_message(self, message):
"""弹出错误提示框"""
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
msg.setWindowIcon(self.windowIcon()) # 设置与主窗口一致的图标
msg.setText(message)
msg.setWindowTitle("错误")
msg.exec_()
def show_success_message(self, message):
"""弹出成功提示框"""
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setWindowIcon(self.windowIcon()) # 设置与主窗口一致的图标
msg.setText(message)
msg.setWindowTitle("成功")
msg.exec_()
def save_to_history(self):
"""保存历史数据,以便撤销"""
self.history.append(self.df.copy())
def undo_last_change(self):
"""撤销上一步操作"""
if self.history:
self.df = self.history.pop()
self.update_table()
self.show_success_message("撤销操作成功!")
def export_to_excel(self):
"""导出当前数据为Excel"""
options = QFileDialog.Options()
file_path, _ = QFileDialog.getSaveFileName(self, "保存Excel文件", "", "Excel 文件 (*.xlsx)", options=options)
if file_path:
self.df.to_excel(file_path, index=False, header=False, engine='openpyxl')
self.show_success_message("表格数据导出成功!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = ExcelProcessor()
window.show()
sys.exit(app.exec_())