엑셀 파일 qtablewidget 이용해서
원본파일의 시트를 더블클릭해서 선택
대상파일의 시트를 더블클릭해서 선택
저장버튼을 누르면
원본파일의 시트내용을 대상파일의 시트 마직막 행 다음에 이어 붙여넣기해서 저장
pyside6_exceltoexcelmodifysamefilesamesheet.py
import os
import pandas as pd
from PySide6.QtWidgets import (
QApplication, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QListWidget, QLabel,
QTableWidget, QTableWidgetItem, QFileDialog, QMessageBox
)
import openpyxl
import datetime
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.window_width, self.window_height = 1000, 500
self.resize(self.window_width, self.window_height)
##### layout_main ######
layout_main = QHBoxLayout()
self.setLayout(layout_main)
##### layout_1 (좌측 레이아웃) ######
layout_1 = QVBoxLayout()
# 원본 엑셀 파일 열기 버튼
s_open_btn = QPushButton('원본 엑셀 파일 열기', self)
s_open_btn.setMaximumWidth(300)
self.s_listwidget = QListWidget(self)
self.s_listwidget.setMaximumWidth(300)
# 원본 파일 경로를 표시할 라벨 추가
self.label_s = QLabel()
self.label_s.setMaximumWidth(300)
self.label_s.setText("원본파일 경로")
self.label_s.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: green;")
layout_1.addWidget(s_open_btn)
layout_1.addWidget(self.label_s) # 원본 파일 경로 라벨 추가
layout_1.addWidget(self.s_listwidget)
# 대상 엑셀 파일 선택 버튼
t_open_btn = QPushButton('대상 엑셀 파일 선택', self)
t_open_btn.setMaximumWidth(300)
t_open_btn.clicked.connect(self.fn_t_clickOpenBtn)
self.t_listwidget = QListWidget(self)
self.t_listwidget.setMaximumWidth(300)
self.label_t = QLabel()
self.label_t.setMaximumWidth(300)
self.label_t.setText("대상파일 경로")
self.label_t.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: red;")
layout_1.addWidget(t_open_btn)
layout_1.addWidget(self.label_t)
layout_1.addWidget(self.t_listwidget)
# 저장 버튼 추가
save_btn = QPushButton('저장', self)
save_btn.clicked.connect(self.fn_df_save)
layout_1.addWidget(save_btn) # layout_1에 저장 버튼 추가
layout_main.addLayout(layout_1)
##### layout_2 (우측 레이아웃) ######
layout_2 = QVBoxLayout()
# 원본/대상 구분 라벨 추가
self.label_table_type = QLabel("원본", self)
self.label_table_type.setStyleSheet("background-color: green; color: white; font-size: 16px; font-weight: bold;")
layout_2.addWidget(self.label_table_type)
self.table = QTableWidget()
layout_2.addWidget(self.table)
layout_main.addLayout(layout_2)
s_open_btn.clicked.connect(self.fn_s_clickOpenBtn)
self.s_listwidget.itemDoubleClicked.connect(self.getItem_s)
self.t_listwidget.itemDoubleClicked.connect(self.getItem_t)
def getItem_s(self):
self.s_row = self.s_listwidget.currentRow()
self.loadData(self.s_row, "원본")
def getItem_t(self):
self.t_row = self.t_listwidget.currentRow()
self.loadData(self.t_row, "대상")
def fn_s_clickOpenBtn(self):
self.table.clear()
self.s_listwidget.clear()
file_filter = 'Excel File (*.xlsx *.xlsm)'
self.s_file_path, _ = QFileDialog.getOpenFileName(
parent=self,
caption='파일 열기',
filter=file_filter
)
if self.s_file_path:
# 시트 목록을 가져와서 리스트에 추가
self.list_sheet_s = self.fn_listsheetData(self.s_file_path)
for sheet in self.list_sheet_s:
self.s_listwidget.addItem(sheet)
# 첫 번째 시트를 자동 선택하고 배경을 노란색으로 변경
if self.list_sheet_s:
self.s_listwidget.setCurrentRow(0) # 첫 번째 시트 선택
self.loadData(0, "원본") # 첫 번째 시트 로드
# 선택된 원본 파일 경로 표시
self.label_s.setText(self.s_file_path)
def fn_t_clickOpenBtn(self):
self.label_t.clear()
self.t_listwidget.clear()
file_filter = 'Excel File (*.xlsx *.xlsm)'
self.t_file_path, _ = QFileDialog.getOpenFileName(
parent=self,
caption='파일 열기',
filter=file_filter
)
if self.t_file_path:
# 시트 목록을 가져와서 리스트에 추가
self.df_list_t = self.fn_listsheetData(self.t_file_path)
for sheet in self.df_list_t:
self.t_listwidget.addItem(sheet)
# 첫 번째 시트를 자동 선택
if self.df_list_t:
self.t_listwidget.setCurrentRow(0) # 첫 번째 시트 선택
self.label_t.setText(self.t_file_path)
self.loadData(0, "대상") # 첫 번째 시트 로드
def fn_listsheetData(self, file_path):
self.wb_s = openpyxl.load_workbook(file_path)
list_sheet_s = []
with pd.ExcelFile(file_path) as wb:
for sh in wb.sheet_names:
list_sheet_s.append(sh)
return list_sheet_s
def loadData(self, row, table_type):
try:
self.table.clear()
if table_type == "원본":
select_sheet_name = self.list_sheet_s[row]
self.df_s = pd.read_excel(self.s_file_path, sheet_name=select_sheet_name)
# NaN 값을 빈 문자열로 변경하기 전에 문자열로 변환하여 dtype 문제를 해결
self.df_s = self.df_s.astype(str).replace('nan', '')
self.label_table_type.setText("원본") # 원본 표시
self.label_table_type.setStyleSheet("background-color: green; color: white; font-size: 16px; font-weight: bold;") # 녹색 배경
else:
select_sheet_name = self.df_list_t[row]
self.df_s = pd.read_excel(self.t_file_path, sheet_name=select_sheet_name)
# NaN 값을 빈 문자열로 변경하기 전에 문자열로 변환하여 dtype 문제를 해결
self.df_s = self.df_s.astype(str).replace('nan', '')
self.label_table_type.setText("대상") # 대상 표시
self.label_table_type.setStyleSheet("background-color: red; color: white; font-size: 16px; font-weight: bold;") # 빨간색 배경
self.table.setRowCount(self.df_s.shape[0])
self.table.setColumnCount(self.df_s.shape[1])
self.table.setHorizontalHeaderLabels(self.df_s.columns)
for row_index, row_data in self.df_s.iterrows():
for col_index, value in enumerate(row_data):
tableItem = QTableWidgetItem(str(value))
self.table.setItem(row_index, col_index, tableItem)
except Exception as e:
print(e)
return
def fn_df_save(self):
try:
# 원본 파일 경로가 없을 때 경고 메시지
if not self.label_s.text() or self.label_s.text() == "원본파일 경로":
QMessageBox.warning(self, "경고", "원본 파일을 선택하세요.")
return
# 대상 파일 경로가 없을 때 경고 메시지
if not self.label_t.text() or self.label_t.text() == "대상파일 경로":
QMessageBox.warning(self, "경고", "대상 파일을 선택하세요.")
return
t_row = self.t_listwidget.currentRow() # 현재 선택된 대상 시트 행
if t_row == -1:
QMessageBox.warning(self, "경고", "대상 시트를 선택하세요.")
return
# 원본과 대상 파일, 시트 정보 가져오기
self.list_sheet_t = self.fn_listsheetData(self.t_file_path)
# 선택된 원본 시트 이름과 대상 시트 이름
selected_sheet_s = self.s_listwidget.item(self.s_listwidget.currentRow()).text()
selected_sheet_t = self.t_listwidget.item(t_row).text()
# 원본과 대상 시트가 동일한 경우 경고 메시지
if self.s_file_path == self.t_file_path and selected_sheet_s == selected_sheet_t:
QMessageBox.warning(self, "경고", "같은 파일의 같은 시트는 데이터를 보낼 수 없습니다.")
return
wb_s = openpyxl.load_workbook(self.s_file_path)
ws_s = wb_s[selected_sheet_s]
ext_t = os.path.splitext(self.t_file_path)[1]
if ext_t == ".xlsx":
wb_t = openpyxl.load_workbook(self.t_file_path)
else:
wb_t = openpyxl.load_workbook(self.t_file_path, read_only=False, keep_vba=True)
ws_t = wb_t[selected_sheet_t]
# 원본 엑셀 파일의 제목 줄을 제외한 데이터 복사
mr = ws_s.max_row
mc = ws_s.max_column
# ws_t의 다음 빈 행 찾기
next_row = ws_t.max_row + 1
for i in range(2, mr + 1): # 제목 줄을 제외하기 위해 2부터 시작
for j in range(1, mc + 1):
c = ws_s.cell(row=i, column=j)
if isinstance(c.value, (datetime.date, datetime.datetime)):
# 날짜 형식만 유지해서 저장
ws_t.cell(row=next_row, column=j).value = c.value.strftime('%Y-%m-%d')
else:
ws_t.cell(row=next_row, column=j).value = c.value
next_row += 1
# 대상 파일 저장
wb_t.save(self.t_file_path)
wb_t.close()
wb_s.close()
# 대상 파일의 선택된 시트를 다시 로드하여 테이블 갱신
self.loadData(t_row, "대상")
QMessageBox.information(self, "성공", "저장이 완료되었습니다.")
except Exception as e:
print(e)
return
if __name__ == '__main__':
app = QApplication([])
window = MyApp()
window.show()
app.exec()
'컴퓨터 > Python' 카테고리의 다른 글
python xlsm파일 grok 가공 vba 포함하기 (0) | 2025.03.12 |
---|---|
python pandas 간이세액표 merge_asof (0) | 2025.01.14 |
python 구구단 dataframe 저장 (0) | 2025.01.02 |
python 셀레니움 headless 실행 중 다른 동영상 보여주는 코드 (0) | 2024.12.26 |
python pandas 폴더 내 엑셀파일 합치기 (0) | 2024.12.24 |