컴퓨터/Python

python pyside6 QTableWidget excel to excel 다른 엑셀파일 시트 복사하기

풍경소리^^ 2022. 9. 23. 18:29

exceltoexcel.py--------------------

from msilib.schema import ListView
import re
from ssl import enum_certificates
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, \
                            QHeaderView, QHBoxLayout, QVBoxLayout, QPushButton, QMessageBox, \
                            QFileDialog,  QListWidget, QSizePolicy, QStyleFactory, \
                            QLineEdit, QLabel
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QBrush
import pandas as pd # pip install pandas
import win32com.client
import os

import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows

import warnings
warnings.simplefilter("ignore", UserWarning)
sys.coinit_flags = 2
# import pywinauto

import pygetwindow as gw
from PyQt5.QtGui import QTextCursor


class MyApp(QWidget):
# class MyApp(QMainWindow):
    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.setFixedSize(200, 30)
        # s_open_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        # s_open_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        
        self.s_listwidget = QListWidget(self)
        # self.s_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.s_listwidget.setMaximumWidth(300)

        layout_1.addWidget(s_open_btn)
        layout_1.addWidget(self.s_listwidget)

        t_open_btn = QPushButton('대상 엑셀 파일 선택', self)
        t_open_btn.clicked.connect(self.fn_t_clickOpenBtn)

        self.t_listwidget = QListWidget(self)
        # self.t_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.t_listwidget.setMaximumWidth(300)

        layout_1.addWidget(t_open_btn)
        self.label2 = QLabel()
        self.label2.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300; border-radius: 0px; ")
        layout_1.addWidget(self.label2)
        layout_1.addWidget(self.t_listwidget)

        layout_main.addLayout(layout_1)

        ##### layout_2 ######

        layout_2 = QVBoxLayout()
        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.fn_df_save(self.t_row)

    def fn_s_clickOpenBtn(self):
        self.table.clear()
        self.s_listwidget.clear()
        # file_filter = 'Data file (*.xls *.csv  *.dat);; Excel File (*.xls* *.xls)'
        file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        self.file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'G:\python\vscode\pay',
            directory=r'G:\회사\인사\급여\2022급여\202209',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.file_path:
            self.df_list = self.sheetData(self.file_path)
            for sheet in self.df_list:
                self.s_listwidget.addItem(sheet.name)
            self.loadData(0)
            # self.initTableWidget(0)

    def fn_t_clickOpenBtn(self):
        self.label2.clear()
        self.t_listwidget.clear()
        file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        self.t_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'E:\python\vscode\pay',
            directory=r'B:\python\vscode\excel',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.t_file_path:
            self.df_list_t = self.sheetData(self.t_file_path)
            for sheet in self.df_list_t:
                self.t_listwidget.addItem(sheet.name)
            # self.loadData(0)
            self.label2.setText(self.t_file_path)
    
    def sheetData(self, file_path):
        df_list = []
        with pd.ExcelFile(file_path) as wb:
            for indx, stn in enumerate(wb.sheet_names):
                try:
                    df = pd.read_excel(wb, sheet_name=stn)
                except Exception as e:
                    print('File read error:', e)
                else:
                    df = df.fillna("")
                    df.name = stn
                    df_list.append(df)
        return df_list

    
    def loadData(self, row):
        try:
            self.table.clear()
            xl_File = []
            # df = pd.read_excel(self.file_path)
            self.df = self.df_list[row]
            # print(self.df)
            if self.df.size == 0:
                return
            
            self.df.fillna('',inplace=True)
            self.table.setRowCount(self.df.shape[0])
            self.table.setColumnCount(self.df.shape[1])
            self.table.setHorizontalHeaderLabels(self.df.columns)

            for row in self.df.iterrows():
                values = row[1]
                for col_index, value in enumerate(values):
                    if isinstance(value, (float, int)):
                        value = '{0:0,.0f}'.format(value)
                    tableItem = QTableWidgetItem(str(value))
                    self.table.setItem(row[0], col_index, tableItem)

            # QMessageBox.about(self,'원본파일열기','원본파일을 열었습니다.')
        except:
            return

    def fn_df_save(self, t_row):
        try:
            # self.table.clear()
            xl_File = []
            # df = pd.read_excel(self.file_path)
            self.df_t = self.df_list_t[t_row]
            if self.df.size == 0:
                return
            
            self.df.fillna('',inplace=True)
            self.df.round({"추가수당":0,"급여계":0,"차감지급액":0})
            # print(self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}).loc[0])
            self.df = self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}) # 반올림
            # print(self.t_listwidget.item(row).text())

            # self.df.to_excel(self.t_file_path, sheet_name=self.t_listwidget.item(row).text(), index=False)
            # self.df.to_excel(self.t_file_path, sheet_name="4대급여", index=False) # pandas 버전

            # wb_s = openpyxl.load_workbook(self.file_path)

            df_row_s = dataframe_to_rows(self.df, index=False)  # 확인 버전
            # ws_s = wb_s[self.s_listwidget.item(self.s_row).text()]
            # print(list(df_row_s))

            wb_t = openpyxl.load_workbook(self.t_file_path)
            ws_t = wb_t[self.t_listwidget.item(t_row).text()]
            # print(ws.title)
            # print(self.t_listwidget.item(row).text())
            # ws = wb.get_sheet_by_name(self.t_listwidget.item(row).text())
            # ws = wb.get_named_ranges(self.t_listwidget.item(row).text())
            
            # # sheet['A1'].value = 'fixed'
            # #해당 시트의 마지막 열, 마지막 행 
            # source data의 
            # s_row_max = self.df.shape[0]
            # s_column_max = self.df.shape[1]
            # s_row_max = ws_s.max_row
            # s_column_max = ws_s.max_column

            # t_row_max = self.df_t.shape[0]
            # t_column_max = self.df_t.shape[1]
            # t_row_max = ws_t.max_row
            # t_column_max = ws_t.max_column
            # print("행수:",row_max,"열수:",column_max)
            # column_max = ws_s.max_column
            # row_max = ws_s.max_row
            # print(column_max,row_max)
            #출처: https://ybworld.tistory.com/112 [투손플레이스:티스토리]
            #열마다 행을 for loop문 진행
            ##################################################################
            # wb_t.delete_rows(1,t_row_max)
            # wb_t.delete_cols(1,t_column_max)
            # wb_t.create_sheet(ws_t)

            ws_t.delete_rows(1, ws_t.max_row)   # 확인 버전

            # for col_num in range(1, s_column_max+1):
            #     for row_num in range(1, s_row_max+1):
                    
            #         #tempstr : cell값이 문자열이 아닌 경우를 감안하여 str로 바꿔줌
            #         tempstr = str(ws_s.cell(row = row_num, column = col_num).value)
            #         #문자열 함수 replace 사용(,를 빈칸으로)
            #         data = tempstr.replace(",","")
            #         #빈 셀의 경우 None이라는 문자열 타입이므로 제외하고 데이터 입력
            #         if data != "None":
            #             ws_t.cell(row = row_num, column = col_num).value = data

            # for col_idx in range(1, ws_s.max_column):
            #     for row_idx in range(1, ws_s.max_row):
            #         ws_t.cell(column=col_idx, row=row_idx).value

            for r_num, row in enumerate(df_row_s, 1):   # 확인 버전
                for c_num, value in enumerate(row, 1):  # 확인 버전
                    ws_t.cell(row=r_num, column=c_num, value=value) # 확인 버전
                    # ws_t.cell(row=r_num, column=c_num, value=(df_row_s.cell(row = r_num, column = c_num).value))
            
            # for row in self.df.iterrows():
            #     values = row[1]
            #     for col_index, value in enumerate(values):
            #         if isinstance(value, (float, int)):
            #             value = '{0:0,.0f}'.format(value)

            wb_t.save(self.t_file_path) # 확인 버전
            # wb_t.save("a.xlsx")
            # print(self.t_file_path)
            ################################################################

            # self.table.setRowCount(df.shape[0])
            # self.table.setColumnCount(df.shape[1])
            # self.table.setHorizontalHeaderLabels(df.columns)

            # for row in df.iterrows():
            #     values = row[1]
            #     for col_index, value in enumerate(values):
            #         if isinstance(value, (float, int)):
            #             value = '{0:0,.0f}'.format(value)
            #         tableItem = QTableWidgetItem(str(value))
            #         self.table.setItem(row[0], col_index, tableItem)

            QMessageBox.about(self,'파일 저장','파일 저장을 완료하였습니다.')
        except:
            return
    
        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyleSheet('''
        QWidget {
            font-size: 17px;
        }
        QHeaderView::section::Horizontal {
            background-color: rgb(191, 255, 0);
        }
    ''')
        
    myApp = MyApp()
    myApp.show()

    try:
        sys.exit(app.exec())
    except SystemExit:
        print('Closing Window...')

exceltoexcel.py--------------------반올림버전

from msilib.schema import ListView
import re
from ssl import enum_certificates
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, \
                            QHeaderView, QHBoxLayout, QVBoxLayout, QPushButton, QMessageBox, \
                            QFileDialog,  QListWidget, QSizePolicy, QStyleFactory, \
                            QLineEdit, QLabel
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QBrush
import pandas as pd # pip install pandas
import win32com.client
import os

import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows

import warnings
warnings.simplefilter("ignore", UserWarning)
sys.coinit_flags = 2
# import pywinauto

import pygetwindow as gw
from PyQt5.QtGui import QTextCursor


class MyApp(QWidget):
# class MyApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.window_width, self.window_height = 700, 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.setFixedSize(200, 30)
        # s_open_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        # s_open_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        
        self.s_listwidget = QListWidget(self)
        # self.s_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)     

        layout_1.addWidget(s_open_btn)
        layout_1.addWidget(self.s_listwidget)

        t_open_btn = QPushButton('대상 엑셀 파일 선택', self)
        t_open_btn.clicked.connect(self.fn_t_clickOpenBtn)

        self.t_listwidget = QListWidget(self)
        # self.t_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)

        layout_1.addWidget(t_open_btn)
        self.label2 = QLabel()
        self.label2.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300; border-radius: 0px; ")
        layout_1.addWidget(self.label2)
        layout_1.addWidget(self.t_listwidget)

        layout_main.addLayout(layout_1)

        ##### layout_2 ######

        layout_2 = QVBoxLayout()
        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.fn_df_save(self.t_row)

    def fn_s_clickOpenBtn(self):
        self.table.clear()
        self.s_listwidget.clear()
        # file_filter = 'Data file (*.xls *.csv  *.dat);; Excel File (*.xls* *.xls)'
        file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        self.file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'G:\python\vscode\pay',
            directory=r'G:\회사\인사\급여\2022급여\202209',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.file_path:
            self.df_list = self.sheetData(self.file_path)
            for sheet in self.df_list:
                self.s_listwidget.addItem(sheet.name)
            self.loadData(0)
            # self.initTableWidget(0)

    def fn_t_clickOpenBtn(self):
        self.label2.clear()
        self.t_listwidget.clear()
        file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        self.t_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'E:\python\vscode\pay',
            directory=r'B:\python\vscode\excel',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.t_file_path:
            self.df_list_t = self.sheetData(self.t_file_path)
            for sheet in self.df_list_t:
                self.t_listwidget.addItem(sheet.name)
            # self.loadData(0)
            self.label2.setText(self.t_file_path)
    
    def sheetData(self, file_path):
        df_list = []
        with pd.ExcelFile(file_path) as wb:
            for indx, stn in enumerate(wb.sheet_names):
                try:
                    df = pd.read_excel(wb, sheet_name=stn)
                except Exception as e:
                    print('File read error:', e)
                else:
                    df = df.fillna("")
                    df.name = stn
                    df_list.append(df)
        return df_list

    
    def loadData(self, row):
        try:
            self.table.clear()
            xl_File = []
            # df = pd.read_excel(self.file_path)
            self.df = self.df_list[row]
            # print(self.df)
            if self.df.size == 0:
                return
            
            self.df.fillna('',inplace=True)
            self.table.setRowCount(self.df.shape[0])
            self.table.setColumnCount(self.df.shape[1])
            self.table.setHorizontalHeaderLabels(self.df.columns)

            for row in self.df.iterrows():
                values = row[1]
                for col_index, value in enumerate(values):
                    if isinstance(value, (float, int)):
                        value = '{0:0,.0f}'.format(value)
                    tableItem = QTableWidgetItem(str(value))
                    self.table.setItem(row[0], col_index, tableItem)

            # QMessageBox.about(self,'원본파일열기','원본파일을 열었습니다.')
        except:
            return

    def fn_df_save(self, t_row):
        try:
            # self.table.clear()
            xl_File = []
            # df = pd.read_excel(self.file_path)
            self.df_t = self.df_list_t[t_row]
            if self.df.size == 0:
                return
            
            self.df.fillna('',inplace=True)
            self.df.round({"추가수당":0,"급여계":0,"차감지급액":0})
            # print(self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}).loc[0])
            self.df = self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}) # 반올림
            # print(self.t_listwidget.item(row).text())

            # self.df.to_excel(self.t_file_path, sheet_name=self.t_listwidget.item(row).text(), index=False)

            # wb_s = openpyxl.load_workbook(self.file_path)

            df_row_s = dataframe_to_rows(self.df, index=False) #@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@여기수정요망
            # ws_s = wb_s[self.s_listwidget.item(self.s_row).text()]
            # print(list(df_row_s))

            wb_t = openpyxl.load_workbook(self.t_file_path)
            ws_t = wb_t[self.t_listwidget.item(t_row).text()]
            # print(ws.title)
            # print(self.t_listwidget.item(row).text())
            # ws = wb.get_sheet_by_name(self.t_listwidget.item(row).text())
            # ws = wb.get_named_ranges(self.t_listwidget.item(row).text())
            
            # # sheet['A1'].value = 'fixed'
            # #해당 시트의 마지막 열, 마지막 행 
            # source data의 
            # s_row_max = self.df.shape[0]
            # s_column_max = self.df.shape[1]
            # s_row_max = ws_s.max_row
            # s_column_max = ws_s.max_column

            # t_row_max = self.df_t.shape[0]
            # t_column_max = self.df_t.shape[1]
            # t_row_max = ws_t.max_row
            # t_column_max = ws_t.max_column
            # print("행수:",row_max,"열수:",column_max)
            # column_max = ws_s.max_column
            # row_max = ws_s.max_row
            # print(column_max,row_max)
            #출처: https://ybworld.tistory.com/112 [투손플레이스:티스토리]
            #열마다 행을 for loop문 진행
            ##################################################################
            # wb_t.delete_rows(1,t_row_max)
            # wb_t.delete_cols(1,t_column_max)
            # wb_t.create_sheet(ws_t)

            ws_t.delete_rows(1, ws_t.max_row)

            # for col_num in range(1, s_column_max+1):
            #     for row_num in range(1, s_row_max+1):
                    
            #         #tempstr : cell값이 문자열이 아닌 경우를 감안하여 str로 바꿔줌
            #         tempstr = str(ws_s.cell(row = row_num, column = col_num).value)
            #         #문자열 함수 replace 사용(,를 빈칸으로)
            #         data = tempstr.replace(",","")
            #         #빈 셀의 경우 None이라는 문자열 타입이므로 제외하고 데이터 입력
            #         if data != "None":
            #             ws_t.cell(row = row_num, column = col_num).value = data

            # for col_idx in range(1, ws_s.max_column):
            #     for row_idx in range(1, ws_s.max_row):
            #         ws_t.cell(column=col_idx, row=row_idx).value

            for r_num, row in enumerate(df_row_s, 1):
                for c_num, value in enumerate(row, 1):
                    # ws_t.cell(row=r_num, column=c_num, value=(df_row_s.cell(row = r_num, column = c_num).value))
                    ws_t.cell(row=r_num, column=c_num, value=value)
            
            # for row in self.df.iterrows():
            #     values = row[1]
            #     for col_index, value in enumerate(values):
            #         if isinstance(value, (float, int)):
            #             value = '{0:0,.0f}'.format(value)

            wb_t.save(self.t_file_path)
            # wb_t.save("a.xlsx")
            # print(self.t_file_path)
            ################################################################

            # self.table.setRowCount(df.shape[0])
            # self.table.setColumnCount(df.shape[1])
            # self.table.setHorizontalHeaderLabels(df.columns)

            # for row in df.iterrows():
            #     values = row[1]
            #     for col_index, value in enumerate(values):
            #         if isinstance(value, (float, int)):
            #             value = '{0:0,.0f}'.format(value)
            #         tableItem = QTableWidgetItem(str(value))
            #         self.table.setItem(row[0], col_index, tableItem)

            QMessageBox.about(self,'파일 저장','파일 저장을 완료하였습니다.')
        except:
            return
    
        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyleSheet('''
        QWidget {
            font-size: 17px;
        }
        QHeaderView::section::Horizontal {
            background-color: rgb(191, 255, 0);
        }
    ''')
        
    myApp = MyApp()
    myApp.show()

    try:
        sys.exit(app.exec())
    except SystemExit:
        print('Closing Window...')

exceltoexcelpandas.py--------------------원본 데이터를 잃지 않고 쓰고 싶을 때

from msilib.schema import ListView
import re
from ssl import enum_certificates
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, \
                            QHeaderView, QHBoxLayout, QVBoxLayout, QPushButton, QMessageBox, \
                            QFileDialog,  QListWidget, QSizePolicy, QStyleFactory, \
                            QLineEdit, QLabel
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QBrush
import pandas as pd # pip install pandas
import win32com.client
import os

import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows

import warnings
warnings.simplefilter("ignore", UserWarning)
sys.coinit_flags = 2
# import pywinauto

import pygetwindow as gw
from PyQt5.QtGui import QTextCursor


class MyApp(QWidget):
# class MyApp(QMainWindow):
    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.setFixedSize(200, 30)
        # s_open_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        # s_open_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        
        self.s_listwidget = QListWidget(self)
        # self.s_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.s_listwidget.setMaximumWidth(300)

        layout_1.addWidget(s_open_btn)
        layout_1.addWidget(self.s_listwidget)

        t_open_btn = QPushButton('대상 엑셀 파일 선택', self)
        t_open_btn.clicked.connect(self.fn_t_clickOpenBtn)

        self.t_listwidget = QListWidget(self)
        # self.t_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.t_listwidget.setMaximumWidth(300)

        layout_1.addWidget(t_open_btn)
        self.label2 = QLabel()
        self.label2.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300; border-radius: 0px; ")
        layout_1.addWidget(self.label2)
        layout_1.addWidget(self.t_listwidget)

        layout_main.addLayout(layout_1)

        ##### layout_2 ######

        layout_2 = QVBoxLayout()
        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.fn_df_save(self.t_row)

    def fn_s_clickOpenBtn(self):
        self.table.clear()
        self.s_listwidget.clear()
        # file_filter = 'Data file (*.xls *.csv  *.dat);; Excel File (*.xls* *.xls)'
        file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        self.file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'G:\python\vscode\pay',
            directory=r'G:\회사\인사\급여\2022급여\202209',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.file_path:
            self.df_list = self.sheetData(self.file_path)
            for sheet in self.df_list:
                self.s_listwidget.addItem(sheet.name)
            self.loadData(0)
            # self.initTableWidget(0)

    def fn_t_clickOpenBtn(self):
        self.label2.clear()
        self.t_listwidget.clear()
        file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        self.t_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'E:\python\vscode\pay',
            directory=r'B:\python\vscode\excel',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.t_file_path:
            self.df_list_t = self.sheetData(self.t_file_path)
            for sheet in self.df_list_t:
                self.t_listwidget.addItem(sheet.name)
            # self.loadData(0)
            self.label2.setText(self.t_file_path)
    
    def sheetData(self, file_path):
        df_list = []
        with pd.ExcelFile(file_path) as wb:
            for indx, stn in enumerate(wb.sheet_names):
                try:
                    df = pd.read_excel(wb, sheet_name=stn)
                except Exception as e:
                    print('File read error:', e)
                else:
                    df = df.fillna("")
                    df.name = stn
                    df_list.append(df)
        return df_list

    
    def loadData(self, row):
        try:
            self.table.clear()
            xl_File = []
            # df = pd.read_excel(self.file_path)
            self.df = self.df_list[row]
            # print(self.df)
            if self.df.size == 0:
                return
            
            self.df.fillna('',inplace=True)
            self.table.setRowCount(self.df.shape[0])
            self.table.setColumnCount(self.df.shape[1])
            self.table.setHorizontalHeaderLabels(self.df.columns)

            for row in self.df.iterrows():
                values = row[1]
                for col_index, value in enumerate(values):
                    if isinstance(value, (float, int)):
                        value = '{0:0,.0f}'.format(value)
                    tableItem = QTableWidgetItem(str(value))
                    self.table.setItem(row[0], col_index, tableItem)

            # QMessageBox.about(self,'원본파일열기','원본파일을 열었습니다.')
        except:
            return

    def fn_df_save(self, t_row):
        try:
            xl_File = []
            self.df_t = self.df_list_t[t_row]
            if self.df.size == 0:
                return
            
            # 원본
            self.df.fillna('',inplace=True)
            self.df = self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}) # 반올림

            wb_t = openpyxl.load_workbook(self.t_file_path)
            ws_t = wb_t[self.t_listwidget.item(t_row).text()]
            wb_t.remove(wb_t[self.t_listwidget.item(t_row).text()]) # 타겟 시트 삭제
            wb_t.save(filename=self.t_file_path)
            
            book = openpyxl.load_workbook(self.t_file_path)
            writer = pd.ExcelWriter(self.t_file_path, engine = 'openpyxl')
            writer.book = book
            
            # for row in self.df.iterrows():
            #     values = row[1]
            #     for col_index, value in enumerate(values):
            #         if isinstance(value, (float, int)):
            #             value = '{0:0,.0f}'.format(value)
            self.df.to_excel(writer, sheet_name=self.t_listwidget.item(t_row).text(),index=False)
            writer.save()

            QMessageBox.about(self,'파일 저장','파일 저장을 완료하였습니다.')
        except:
            return
    
        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyleSheet('''
        QWidget {
            font-size: 17px;
        }
        QHeaderView::section::Horizontal {
            background-color: rgb(191, 255, 0);
        }
    ''')
        
    myApp = MyApp()
    myApp.show()

    try:
        sys.exit(app.exec())
    except SystemExit:
        print('Closing Window...')

https://stackoverflow.com/questions/42370977/how-to-save-a-new-sheet-in-an-existing-excel-file-using-pandas

 

How to save a new sheet in an existing excel file, using Pandas?

I want to use excel files to store data elaborated with python. My problem is that I can't add sheets to an existing excel file. Here I suggest a sample code to work with in order to reach this iss...

stackoverflow.com

엄청 찾아 돌아다녔네요ㅠㅠ

xlsmtoxlsx.py--------------------

# importing openpyxl module
import openpyxl as xl;

# opening the source excel file
filename =r"E:\python\vscode\pay\급여s.xlsm"
wb1 = xl.load_workbook(filename)
# ws1 = wb1.worksheets[0]
ws1 = wb1["4대급여"]

# opening the destination excel file
filename1 =r"E:\python\vscode\pay\급여1.xlsx"	# 성공
# filename1 =r"E:\python\vscode\pay\급여1.xlsm"	# 실패
wb2 = xl.load_workbook(filename1)
# ws2 = wb2.active
ws2 = wb2["4대급여"]

# calculate total number of rows and
# columns in source excel file
mr = ws1.max_row
mc = ws1.max_column

# copying the cell values from source
# excel file to destination excel file
for i in range (1, mr + 1):
	for j in range (1, mc + 1):
		# reading cell value from source excel file
		c = ws1.cell(row = i, column = j)

		# writing the read value to destination excel file
		ws2.cell(row = i, column = j).value = c.value

# saving the destination excel file
wb2.save(str(filename1))

# https://python.engineering/python-how-to-copy-data-from-one-excel-sheet-to-another/

xlsmtoxlsm.py--------------------

# importing openpyxl module
import openpyxl as xl

# opening the source excel file
filename1 =r"B:\python\vscode\excel\excel_data\급여대장m.xlsm"
wb1 = xl.load_workbook(filename1)
# wb1 = xl.load_workbook(filename1, read_only=False, keep_vba=True)
# ws1 = wb1.worksheets[0]
ws1 = wb1["4대급여"]

# opening the destination excel file
# filename1 =r"B:\python\vscode\excel\excel_data\급여x1.xlsx"	# 성공
filename2 =r"B:\python\vscode\excel\excel_data\급여대장m1.xlsm"	# 성공
wb2 = xl.load_workbook(filename2, read_only=False, keep_vba=True)	# 성공
# ws2 = wb2.active
ws2 = wb2["4대급여"]

# calculate total number of rows and
# columns in source excel file
mr = ws1.max_row
mc = ws1.max_column

# copying the cell values from source
# excel file to destination excel file
for i in range (1, mr + 1):
	for j in range (1, mc + 1):
		# reading cell value from source excel file
		c = ws1.cell(row = i, column = j)

		# writing the read value to destination excel file
		ws2.cell(row = i, column = j).value = c.value

# saving the destination excel file
wb2.save(str(filename2))

# https://python.engineering/python-how-to-copy-data-from-one-excel-sheet-to-another/

https://stackoverflow.com/questions/17675780/how-to-save-xlsm-file-with-macro-using-openpyxl

 

How to save XLSM file with Macro, using openpyxl

I have .xlsm file with a Macro function. I'm loading it using openpyxl and write some data to the file and finally want to save as a different .xlsm file. To save the file as XLSM file I have used...

stackoverflow.com

xlsmtoxls.py--------------------

# importing openpyxl module
import openpyxl as xl
import xlrd
import xlwt

# opening the source excel file
filename1 =r"B:\python\vscode\excel\excel_data\급여대장m.xlsm"
wb1 = xl.load_workbook(filename1)
# ws1 = wb1.worksheets[0]
ws1 = wb1["4대급여"]
# print(ws1.title)

filename2 =r"B:\python\vscode\excel\excel_data\급여s1.xls"	# 성공
wb2 = xlrd.open_workbook(filename2)
sh_name = "4대급여"
ws2 = wb2[sh_name]
# nrows = ws2.nrows
# ncols = ws2.ncols
nrows = ws1.max_row
ncols = ws1.max_column
# print(nrows)
# print(ws1.cell(row=1, column=1).value)
# mr = ws1.max_row
# mc = ws1.max_column
datadict = {}
for row_num in range(1,nrows+1):
    # if row_num<=5:
    #     print(row_num)
    #     break
    datadict[row_num] = {}
    for col in range(1,ncols+1):
        datadict[row_num][col] = ws1.cell(row=row_num, column=col).value
        # datadict[row_num][col] = ws2.cell_value(row_num, col)

wb2 = xlwt.Workbook(encoding='utf-8')  # utf-8 인코딩 방식의 workbook 생성
worksheetw = wb2.add_sheet(sh_name)  # 시트 생성
for row_num in range(1,nrows+1):
    for col in range(1,ncols+1):
        worksheetw.write(row_num-1, col-1, datadict[row_num][col])
wb2.save(filename2)
# for i in range (1, mr + 1):
# 	for j in range (1, mc + 1):
# 		# reading cell value from source excel file
# 		c = ws1.cell(row = i, column = j)

# 		# writing the read value to destination excel file
# 		ws2.cell(row = i, column = j).value = c.value

# # saving the destination excel file

# wb2.save(str(filename2))

# https://python.engineering/python-how-to-copy-data-from-one-excel-sheet-to-another/

문제점

xls 확장자 

다른시트 다 없어지고 vba 매크로 없어짐

xls 확장자 지원 포기===

 

xlsx, xlsm 지원 버전

xlsmtoxlsx_toxlsm.py--------------------

# from msilib.schema import ListView
# import re
# from ssl import enum_certificates
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, \
                            QHeaderView, QHBoxLayout, QVBoxLayout, QPushButton, QMessageBox, \
                            QFileDialog,  QListWidget, QSizePolicy, QStyleFactory, \
                            QLineEdit, QLabel
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QBrush
import pandas as pd # pip install pandas
# import win32com.client
import os

import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows

# import warnings
# warnings.simplefilter("ignore", UserWarning)
# sys.coinit_flags = 2
# import pywinauto

# import pygetwindow as gw
from PyQt5.QtGui import QTextCursor


class MyApp(QWidget):
# class MyApp(QMainWindow):
    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)
        # s_open_btn.setFixedSize(200, 30)
        # s_open_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        # s_open_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        
        self.s_listwidget = QListWidget(self)
        # self.s_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.s_listwidget.setMaximumWidth(300)

        layout_1.addWidget(s_open_btn)
        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.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.t_listwidget.setMaximumWidth(300)

        layout_1.addWidget(t_open_btn)
        self.label2 = QLabel()
        self.label2.setMaximumWidth(300)
        self.label2.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300; border-radius: 0px; ")
        layout_1.addWidget(self.label2)
        layout_1.addWidget(self.t_listwidget)

        layout_main.addLayout(layout_1)

        ##### layout_2 ######

        layout_2 = QVBoxLayout()
        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.fn_df_save(self.t_row)

    def fn_s_clickOpenBtn(self):
        self.table.clear()
        self.s_listwidget.clear()
        # file_filter = 'Data file (*.xls *.csv  *.dat);; Excel File (*.xls* *.xls)'
        # file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        file_filter = 'Excel File (*.xls* *.xls)'
        self.s_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'G:\python\vscode\pay',
            directory=r'E:\python\vscode\pay\excel_data',
            filter=file_filter,
            # initialFilter='Excel File (*.xls *.xlsx)'
            initialFilter='Excel File (*.xls* *.xls)'
        )
        if self.s_file_path:
            # 파일의 시트리스트
            self.list_sheet_s = self.fn_listsheetData(self.s_file_path)
            for sheet in self.list_sheet_s:
                # print(sheet)
                self.s_listwidget.addItem(sheet)
            self.loadData(0)
            # self.initTableWidget(0)

    def fn_t_clickOpenBtn(self):
        self.label2.clear()
        self.t_listwidget.clear()
        # file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        file_filter = 'Excel File (*.xlsx *.xlsm)'
        self.t_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            directory=r'E:\python\vscode\pay\excel_data',
            # directory=r'B:\python\vscode\excel',
            filter=file_filter
            # initialFilter='Excel File (*.xls *.xlsx)'
            # initialFilter='Excel File (*.xls* *.xls)'
        )
        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.name)
                self.t_listwidget.addItem(sheet)
            # self.loadData(0)
            self.label2.setText(self.t_file_path)

    def fn_listsheetData(self, file_path):
        self.wb_s = openpyxl.load_workbook(file_path)
        # xlsm
        # self.ws_s = self.wb_s["4대급여"]
        self.ws_s = self.wb_s.worksheets[0]
        # print(self.ws_s.title)
        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
        # xlsx
        # df_list = []
        # with pd.ExcelFile(file_path) as wb:
        #     for indx, stn in enumerate(wb.sheet_names):
        #         try:
        #             df = pd.read_excel(wb, sheet_name=stn)
        #         except Exception as e:
        #             print('File read error:', e)
        #         else:
        #             df = df.fillna("")
        #             df.name = stn
        #             df_list.append(df)
        # return df_list

    def fn_listsheetData_t(self, file_path):
        # xlsm
        self.wb_t = openpyxl.load_workbook(file_path)
        list_sheet_t = []
        with pd.ExcelFile(file_path) as wb:
            for sh in wb.sheet_names:
                list_sheet_t.append(sh)
        return list_sheet_t

    
    def loadData(self, row):
        try:
            self.table.clear()
            xl_File = []
            self.ws_s = self.wb_s.worksheets[row] # xlsm
            select_sheet_name = self.list_sheet_s[row]
            # self.ws_s = self.wb_s.worksheets[0]
            # self.df_s = pd.read_excel(self.wb_s, sheet_name=select_sheet_name)
            self.df_s = pd.read_excel(self.s_file_path, sheet_name=select_sheet_name)
            # self.ws_s = self.wb_s["4대급여"]
            if self.df_s.size == 0:
                return
            
            self.df_s.fillna('',inplace=True)
            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 in self.df_s.iterrows():
                values = row[1]
                for col_index, value in enumerate(values):
                    if isinstance(value, (float, int)):
                        value = '{0:0,.0f}'.format(value)
                    tableItem = QTableWidgetItem(str(value))
                    self.table.setItem(row[0], col_index, tableItem)

            # QMessageBox.about(self,'원본파일열기','원본파일을 열었습니다.')
        except:
            return

    def fn_df_save(self, t_row):
        try:
            # 파일의 시트리스트
            self.list_sheet_t = self.fn_listsheetData_t(self.t_file_path)
            xl_File = []
            select_sheet_name_t = self.list_sheet_t[t_row]
            # print(select_sheet_name_t)
            # print(self.t_file_path)

            ext_t = os.path.splitext(self.t_file_path)[1]
            if ext_t == ".xlsx":
                # self.df_s = pd.read_excel(self.s_file_path, sheet_name=select_sheet_name_t)
                # self.df_t = self.df_list_t[t_row]
                if self.df_s.size == 0:
                    return
            
                # 원본
                self.df_s.fillna('',inplace=True)
                # self.df_s = self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}) # 반올림
            
                wb_t = openpyxl.load_workbook(self.t_file_path)
                ws_t = wb_t[self.t_listwidget.item(t_row).text()]
                wb_t.remove(wb_t[self.t_listwidget.item(t_row).text()]) # 타겟 시트 삭제
                wb_t.save(filename=self.t_file_path)
                
                book = openpyxl.load_workbook(self.t_file_path)
                writer = pd.ExcelWriter(self.t_file_path, engine = 'openpyxl')
                writer.book = book
                
                # for row in self.df.iterrows():
                #     values = row[1]
                #     for col_index, value in enumerate(values):
                #         if isinstance(value, (float, int)):
                #             value = '{0:0,.0f}'.format(value)
                self.df_s.to_excel(writer, sheet_name=self.t_listwidget.item(t_row).text(),index=False)
                writer.save()

            else: # ext_t == ".xlsm":
                # print(self.s_file_path)
                # print(self.t_listwidget.item(self.t_row).text())
                wb_s = openpyxl.load_workbook(self.s_file_path)
                ws_s = wb_s[self.t_listwidget.item(t_row).text()]

                wb_t = openpyxl.load_workbook(self.t_file_path, read_only=False, keep_vba=True)
                ws_t = wb_t[self.t_listwidget.item(t_row).text()]
                # print(self.t_listwidget.item(t_row).text())
                
                # calculate total number of rows and
                # columns in source excel file
                mr = ws_s.max_row
                mc = ws_s.max_column

                # copying the cell values from source
                # excel file to destination excel file
                for i in range (1, mr + 1):
                    for j in range (1, mc + 1):
                        # reading cell value from source excel file
                        c = ws_s.cell(row = i, column = j)
                        # print(c.value)
                        # writing the read value to destination excel file
                        ws_t.cell(row = i, column = j).value = c.value

                # saving the destination excel file
                wb_t.save(str(self.t_file_path))
            

            QMessageBox.about(self,'파일 저장','파일 저장을 완료하였습니다.')
        except:
            return
    
        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyleSheet('''
        QWidget {
            font-size: 17px;
        }
        QHeaderView::section::Horizontal {
            background-color: rgb(191, 255, 0);
        }
    ''')
        
    myApp = MyApp()
    myApp.show()

    try:
        sys.exit(app.exec())
    except SystemExit:
        print('Closing Window...')

exceltoexcel_xlsm02.py--------------------

# from msilib.schema import ListView
# import re
# from ssl import enum_certificates
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QTableWidget, QTableWidgetItem, \
                            QHeaderView, QHBoxLayout, QVBoxLayout, QPushButton, QMessageBox, \
                            QFileDialog,  QListWidget, QSizePolicy, QStyleFactory, \
                            QLineEdit, QLabel
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem, QColor, QBrush
import pandas as pd # pip install pandas
# import win32com.client
import os

import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows

# import warnings
# warnings.simplefilter("ignore", UserWarning)
# sys.coinit_flags = 2
# import pywinauto

# import pygetwindow as gw
from PyQt5.QtGui import QTextCursor


class MyApp(QWidget):
# class MyApp(QMainWindow):
    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)
        # s_open_btn.setFixedSize(200, 30)
        # s_open_btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
        # s_open_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        
        self.s_listwidget = QListWidget(self)
        # self.s_listwidget.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.s_listwidget.setMaximumWidth(300)

        layout_1.addWidget(s_open_btn)
        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.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding)
        self.t_listwidget.setMaximumWidth(300)

        layout_1.addWidget(t_open_btn)
        self.label2 = QLabel()
        self.label2.setMaximumWidth(300)
        self.label2.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300; border-radius: 0px; ")
        layout_1.addWidget(self.label2)
        layout_1.addWidget(self.t_listwidget)

        layout_main.addLayout(layout_1)

        ##### layout_2 ######

        layout_2 = QVBoxLayout()
        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.fn_df_save(self.t_row)

    def fn_s_clickOpenBtn(self):
        self.table.clear()
        self.s_listwidget.clear()
        # file_filter = 'Data file (*.xls *.csv  *.dat);; Excel File (*.xls* *.xls)'
        # file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        # file_filter = 'Excel File (*.xls* *.xls)'
        file_filter = 'Excel File (*.xlsx *.xlsm)' # 실질적으로 표시되는 파일 형식
        self.s_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            # directory=r'G:\python\vscode\pay',
            directory=r'E:\python\vscode\pay\excel_data',
            filter=file_filter,
            # initialFilter='Excel File (*.xls* *.xls)' # 작동하는거랑 상관없음
        )
        if self.s_file_path:
            # 파일의 시트리스트
            self.list_sheet_s = self.fn_listsheetData(self.s_file_path)
            for sheet in self.list_sheet_s:
                # print(sheet)
                self.s_listwidget.addItem(sheet)
            self.loadData(0)
            # self.initTableWidget(0)

    def fn_t_clickOpenBtn(self):
        self.label2.clear()
        self.t_listwidget.clear()
        # file_filter = 'Excel File (*.xls* *.xls);;Data file (*.xls *.csv  *.dat)'
        file_filter = 'Excel File (*.xlsx *.xlsm)'
        self.t_file_path, ext = QFileDialog.getOpenFileName(
            parent=self,
            caption='파일 열기',
            # directory=os.getcwd(),
            directory=r'E:\python\vscode\pay\excel_data',
            # directory=r'B:\python\vscode\excel',
            filter=file_filter
            # initialFilter='Excel File (*.xls *.xlsx)'
            # initialFilter='Excel File (*.xls* *.xls)'
        )
        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.name)
                self.t_listwidget.addItem(sheet)
            # self.loadData(0)
            self.label2.setText(self.t_file_path)

    def fn_listsheetData(self, file_path):
        self.wb_s = openpyxl.load_workbook(file_path)
        # xlsm
        # self.ws_s = self.wb_s["4대급여"]
        self.ws_s = self.wb_s.worksheets[0]
        # print(self.ws_s.title)
        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
        # xlsx
        # df_list = []
        # with pd.ExcelFile(file_path) as wb:
        #     for indx, stn in enumerate(wb.sheet_names):
        #         try:
        #             df = pd.read_excel(wb, sheet_name=stn)
        #         except Exception as e:
        #             print('File read error:', e)
        #         else:
        #             df = df.fillna("")
        #             df.name = stn
        #             df_list.append(df)
        # return df_list

    def fn_listsheetData_t(self, file_path):
        # xlsm
        self.wb_t = openpyxl.load_workbook(file_path)
        list_sheet_t = []
        with pd.ExcelFile(file_path) as wb:
            for sh in wb.sheet_names:
                list_sheet_t.append(sh)
        return list_sheet_t

    
    def loadData(self, row):
        try:
            self.table.clear()
            xl_File = []
            self.ws_s = self.wb_s.worksheets[row] # xlsm
            select_sheet_name = self.list_sheet_s[row]
            # print(select_sheet_name)
            # self.ws_s = self.wb_s.worksheets[0]
            # self.df_s = pd.read_excel(self.wb_s, sheet_name=select_sheet_name)
            self.df_s = pd.read_excel(self.s_file_path, sheet_name=select_sheet_name)
            # print(self.df_s)
            # self.ws_s = self.wb_s["4대급여"]
            if self.df_s.size == 0:
                return
            
            self.df_s.fillna('',inplace=True)
            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 in self.df_s.iterrows():
                values = row[1]
                for col_index, value in enumerate(values):
                    if isinstance(value, (float, int)):
                        value = '{0:0,.0f}'.format(value)
                    tableItem = QTableWidgetItem(str(value))
                    self.table.setItem(row[0], col_index, tableItem)

            # QMessageBox.about(self,'원본파일열기','원본파일을 열었습니다.')
        except:
            return

    def fn_df_save(self, t_row):
        try:
            # 파일의 시트리스트
            self.list_sheet_t = self.fn_listsheetData_t(self.t_file_path)
            xl_File = []
            select_sheet_name_t = self.list_sheet_t[t_row]
            # print(select_sheet_name_t)
            # print(self.t_file_path)

            ext_t = os.path.splitext(self.t_file_path)[1]
            # if ext_t==".xlsx": #  dataframe으로 처리하면 기존 양식 날아가서 작동안하게 함
            #     # self.df_s = pd.read_excel(self.s_file_path, sheet_name=select_sheet_name_t)
            #     # self.df_t = self.df_list_t[t_row]
            #     if self.df_s.size == 0:
            #         return
            
            #     # 원본
            #     self.df_s.fillna('',inplace=True)
            #     # self.df_s = self.df.round({"추가수당":0,"급여계":0,"차감지급액":0}) # 반올림
            
            #     wb_t = openpyxl.load_workbook(self.t_file_path)
            #     ws_t = wb_t[self.t_listwidget.item(t_row).text()]
            #     wb_t.remove(wb_t[self.t_listwidget.item(t_row).text()]) # 타겟 시트 삭제
            #     wb_t.save(filename=self.t_file_path)
                
            #     book = openpyxl.load_workbook(self.t_file_path)
            #     writer = pd.ExcelWriter(self.t_file_path, engine = 'openpyxl')
            #     writer.book = book
                
            #     # for row in self.df.iterrows():
            #     #     values = row[1]
            #     #     for col_index, value in enumerate(values):
            #     #         if isinstance(value, (float, int)):
            #     #             value = '{0:0,.0f}'.format(value)
            #     self.df_s.to_excel(writer, sheet_name=self.t_listwidget.item(t_row).text(),index=False)
            #     writer.save()

            # print(self.s_file_path)
            # print(self.t_listwidget.item(self.t_row).text())
            wb_s = openpyxl.load_workbook(self.s_file_path)
            ws_s = wb_s[self.t_listwidget.item(t_row).text()]

            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[self.t_listwidget.item(t_row).text()]
            # print(self.t_listwidget.item(t_row).text())
            
            # calculate total number of rows and
            # columns in source excel file
            mr = ws_s.max_row
            mc = ws_s.max_column

            # copying the cell values from source
            # excel file to destination excel file
            for i in range (1, mr + 1):
                for j in range (1, mc + 1):
                    # reading cell value from source excel file
                    c = ws_s.cell(row = i, column = j)
                    # print(c.value)
                    # writing the read value to destination excel file
                    ws_t.cell(row = i, column = j).value = c.value

            # saving the destination excel file
            wb_t.save(str(self.t_file_path))

            # else: # ext_t == ".xlsm":
            #     # print(self.s_file_path)
            #     # print(self.t_listwidget.item(self.t_row).text())
            #     wb_s = openpyxl.load_workbook(self.s_file_path)
            #     ws_s = wb_s[self.t_listwidget.item(t_row).text()]

            #     wb_t = openpyxl.load_workbook(self.t_file_path, read_only=False, keep_vba=True)
            #     ws_t = wb_t[self.t_listwidget.item(t_row).text()]
            #     # print(self.t_listwidget.item(t_row).text())
                
            #     # calculate total number of rows and
            #     # columns in source excel file
            #     mr = ws_s.max_row
            #     mc = ws_s.max_column

            #     # copying the cell values from source
            #     # excel file to destination excel file
            #     for i in range (1, mr + 1):
            #         for j in range (1, mc + 1):
            #             # reading cell value from source excel file
            #             c = ws_s.cell(row = i, column = j)
            #             # print(c.value)
            #             # writing the read value to destination excel file
            #             ws_t.cell(row = i, column = j).value = c.value

            #     # saving the destination excel file
            #     wb_t.save(str(self.t_file_path))
            

            QMessageBox.about(self,'파일 저장','파일 저장을 완료하였습니다.')
        except:
            return
    
        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyleSheet('''
        QWidget {
            font-size: 17px;
        }
        QHeaderView::section::Horizontal {
            background-color: rgb(191, 255, 0);
        }
    ''')
        
    myApp = MyApp()
    myApp.show()

    try:
        sys.exit(app.exec())
    except SystemExit:
        print('Closing Window...')

pandas버전은 양식이 없어져서 주석처리로 비활성화하였습니다

xlsm→xlsx 시트 카피

xlsm→xlsm 시트 카피

exceltoexcel.py
0.01MB

 

import os
import pandas as pd
from PySide6.QtWidgets import (
    QApplication, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QListWidget, QLabel,
    QTableWidget, QTableWidgetItem, QFileDialog, QMessageBox
)
import openpyxl

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.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300;")

        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.label2 = QLabel()
        self.label2.setMaximumWidth(300)
        self.label2.setStyleSheet("color: #000000; border-style: solid; border-width: 2px; border-color: #FFC300;")

        layout_1.addWidget(t_open_btn)
        layout_1.addWidget(self.label2)
        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.label2.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.label2.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)
                self.df_s.fillna('', inplace=True)
                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)
                self.df_s.fillna('', inplace=True)
                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 in self.df_s.iterrows():
                values = row[1]
                for col_index, value in enumerate(values):
                    if isinstance(value, (float, int)):
                        value = '{0:0,.0f}'.format(value)
                    tableItem = QTableWidgetItem(str(value))
                    self.table.setItem(row[0], col_index, tableItem)
        except Exception as e:
            print(e)
            return

    def fn_df_save(self):
        try:
            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)
            select_sheet_name_t = self.list_sheet_t[t_row]
            wb_s = openpyxl.load_workbook(self.s_file_path)
            ws_s = wb_s[self.s_listwidget.item(self.s_listwidget.currentRow()).text()]

            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[self.t_listwidget.item(t_row).text()]

            # 원본 엑셀 파일의 제목 줄을 제외한 데이터 복사
            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)
                    ws_t.cell(row=next_row, column=j).value = c.value
                next_row += 1    

            wb_t.save(self.t_file_path)  # 대상 파일 저장

            # 대상 파일의 선택된 시트를 다시 로드하여 테이블 갱신
            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()

 

pyside6_exceltoexcelmodifysamefilesheet.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()