- 在app.py中,将f-string替换为str.format()以提高兼容性。 - 在config.py中添加日志记录功能,记录加载和保存配置的详细信息。 - 更新build.py以确保在构建过程中正确处理文件路径和依赖项。 - 修改README.md以反映项目的最新功能和安装说明。 - 更新requirements.txt以调整依赖包版本,确保兼容性。master
@@ -2,10 +2,10 @@ | |||
a = Analysis( | |||
['app.py'], | |||
pathex=[], | |||
['main.py'], | |||
pathex=['D:\\2025Project\\MCP\\excel_converter'], | |||
binaries=[], | |||
datas=[('employee_info.json', '.'), ('company_options.json', '.'), ('bank_options.json', '.'), ('template.xlsx', '.'), ('config.py', '.')], | |||
datas=[('D:\\2025Project\\MCP\\excel_converter\\config.py', '.'), ('D:\\2025Project\\MCP\\excel_converter\\template.xlsx', '.')], | |||
hiddenimports=[], | |||
hookspath=[], | |||
hooksconfig={}, |
@@ -1,115 +1,76 @@ | |||
# 工资明细转换工具 | |||
# 日本工资明细转换工具 | |||
这是一个用于批量转换Excel工资明细表的图形界面工具。 | |||
## 功能简介 | |||
## 功能特点 | |||
此工具用于将日本工资明细表格数据转换为标准格式,支持批量处理多名员工的数据。 | |||
1. 批量导入Excel文件并根据模板进行转换 | |||
2. 自定义设置每个文件的公司、银行和其他信息 | |||
3. 按照指定的单元格映射规则转换数据 | |||
4. 自动生成包含员工姓名和日期的输出文件名 | |||
5. 支持复制和保留原始Excel的格式和样式 | |||
## 主要功能 | |||
## 环境要求 | |||
1. 导入Excel格式的工资明细表 | |||
2. 维护员工信息(姓名、公司、银行账户等) | |||
3. 自动转换并生成标准格式的工资明细表 | |||
4. 批量处理多个员工的数据 | |||
- Python 3.7 或更高版本 | |||
- 依赖包:pandas, openpyxl, xlrd, xlwt | |||
## 安装说明 | |||
## 快速开始 | |||
### 开发环境安装 | |||
1. 确保已安装Python环境(3.7或更高版本) | |||
2. 使用uv创建虚拟环境: | |||
```bash | |||
uv venv | |||
1. 确保已安装Python 3.6+ | |||
2. 安装依赖包: | |||
``` | |||
3. 激活虚拟环境: | |||
```bash | |||
# Windows | |||
.venv\Scripts\activate | |||
# macOS/Linux | |||
source .venv/bin/activate | |||
pip install -r requirements.txt | |||
``` | |||
4. 安装依赖包: | |||
```bash | |||
uv pip install -r requirements.txt | |||
3. 运行程序: | |||
``` | |||
5. 运行程序: | |||
```bash | |||
# 方法1: 直接运行Python脚本 | |||
python main.py | |||
# 方法2: 使用批处理文件 (Windows) | |||
run.bat | |||
``` | |||
## 使用方法 | |||
### 构建可执行文件 | |||
1. 在界面上点击"选择Excel文件"按钮选择要转换的Excel文件 | |||
2. 双击列表中的每个文件,设置公司信息(C2)、银行信息(B30)和其他信息(F2) | |||
3. 点击"选择导出位置"按钮选择输出文件保存位置 | |||
4. 点击"开始转换"按钮进行批量转换 | |||
5. 转换完成后会显示成功转换的文件数量 | |||
要构建独立的可执行文件,请运行: | |||
## 文件命名规则 | |||
输出文件名格式为:`YYYY年M月份給料明細書-姓名.xls` | |||
- 年份(YYYY):从输入文件第二个Sheet页的B4单元格中提取 | |||
- 月份(M):从输入文件第二个Sheet页的B4单元格中提取 | |||
- 姓名:从输入文件第一个Sheet页的C3单元格中提取 | |||
``` | |||
python build.py | |||
``` | |||
## 配置指南 | |||
构建完成后,可执行文件将位于`dist`目录中。 | |||
### 修改模板路径 | |||
在 `config.py` 文件中修改 `TEMPLATE_PATH` 变量。 | |||
## 常见问题解决 | |||
### 修改单元格映射关系 | |||
在 `config.py` 文件中的 `CELL_MAPPINGS` 字典中定义映射关系: | |||
```python | |||
{ | |||
(源文件sheet索引, 行, 列): (目标文件sheet索引, 行, 列) | |||
} | |||
``` | |||
### 关于"信息维护无法保存"的问题 | |||
### 修改公司和银行列表 | |||
编辑 `config.py` 文件中的 `COMPANY_OPTIONS` 和 `BANK_OPTIONS` 列表即可添加或删除选项。 | |||
如果使用打包后的程序遇到信息维护功能无法保存的问题,请按照以下步骤解决: | |||
## 常见问题解决 | |||
1. 确保运行程序时有足够的权限(管理员权限) | |||
2. 检查程序所在目录是否有写入权限 | |||
3. 手动创建一个名为`employee_info.json`的空文件: | |||
- 在程序所在的文件夹中创建一个文本文件 | |||
- 内容填写`[]`(一个空数组) | |||
- 将文件重命名为`employee_info.json` | |||
4. 重新启动程序,应该就可以正常保存员工信息了 | |||
### 程序启动失败 | |||
- 检查 Python 版本是否兼容 (3.7+) | |||
- 确认所有依赖已正确安装 | |||
- 检查模板文件是否存在于指定路径 | |||
### 数据文件路径说明 | |||
### 转换后的文件格式不正确 | |||
- 确认模板文件格式无误 | |||
- 检查输入文件是否符合要求的格式 | |||
- 确认映射关系配置正确 | |||
打包后的程序会在以下位置存储数据文件: | |||
- 员工信息: 程序同一目录下的`employee_info.json` | |||
- 模板文件: 程序同一目录下的`template.xlsx` | |||
### 无法识别日期 | |||
如果程序无法正确识别日期格式,可能需要在 `app.py` 的 `process_file` 方法中添加更多的日期解析逻辑。 | |||
## 使用说明 | |||
## 项目结构 | |||
1. 启动程序 | |||
2. 点击"选择Excel文件"导入原始工资明细表 | |||
3. 点击"信息维护"添加或更新员工信息 | |||
4. 选择导出位置 | |||
5. 点击"开始转换"生成标准格式的工资明细表 | |||
``` | |||
excel_converter/ | |||
├── app.py # 主应用程序代码 | |||
├── config.py # 配置文件 | |||
├── main.py # 入口点 | |||
├── requirements.txt # 依赖列表 | |||
├── run.bat # Windows 运行脚本 | |||
├── README.md # 项目说明 | |||
├── template.xlsx # Excel模板文件 | |||
└── test_data/ # 测试数据目录 | |||
``` | |||
## 开发者说明 | |||
## 维护和扩展 | |||
本程序基于Python开发,使用以下库: | |||
- tkinter: 用于GUI界面 | |||
- openpyxl: 用于Excel文件处理 | |||
- pandas: 用于数据处理 | |||
- xlwings: 用于高级Excel操作 | |||
### 添加新功能 | |||
1. 尽量将配置参数放在 `config.py` 文件中 | |||
2. 保持用户界面简洁直观 | |||
3. 添加适当的错误处理和用户反馈 | |||
## 联系方式 | |||
### 代码维护 | |||
- 定期更新依赖包版本 | |||
- 如果更改了核心功能,请更新文档 | |||
- 考虑添加单元测试以确保功能正常 | |||
如有问题,请联系开发者。 |
@@ -1,32 +1,80 @@ | |||
# -*- coding: utf-8 -*- | |||
""" | |||
Build script for Excel Converter application | |||
This script uses PyInstaller to build an executable from the Python code | |||
""" | |||
import os | |||
import subprocess | |||
import sys | |||
import subprocess | |||
import shutil | |||
def build_executable(): | |||
# Ensure we're in the project root directory | |||
os.chdir(os.path.dirname(os.path.abspath(__file__))) | |||
def main(): | |||
# Package name and path | |||
package_name = "ExcelConverter" | |||
main_script = "main.py" | |||
icon_path = "icon.ico" | |||
# Install required packages using uv | |||
print("Installing required packages...") | |||
subprocess.run(["uv", "pip", "install", "-r", "requirements.txt"], check=True) | |||
# Make sure we're in the right directory | |||
script_dir = os.path.dirname(os.path.abspath(__file__)) | |||
os.chdir(script_dir) | |||
# Build the executable using PyInstaller | |||
print("Building executable...") | |||
subprocess.run([ | |||
# Create build command | |||
cmd = [ | |||
"pyinstaller", | |||
"--name=ExcelConverter", | |||
"--name={}".format(package_name), | |||
"--onefile", | |||
"--windowed", | |||
"--add-data=employee_info.json;.", | |||
"--add-data=company_options.json;.", | |||
"--add-data=bank_options.json;.", | |||
"--add-data=template.xlsx;.", | |||
"--add-data=config.py;.", | |||
"app.py" | |||
], check=True) | |||
"--clean", | |||
"--paths={}".format(script_dir), | |||
"--add-data={}{}config.py;.".format(script_dir, os.path.sep), | |||
"--add-data={}{}template.xlsx;.".format(script_dir, os.path.sep) | |||
] | |||
# Add icon if it exists | |||
if os.path.exists(icon_path): | |||
cmd.append("--icon={}".format(icon_path)) | |||
# Add main script | |||
cmd.append(main_script) | |||
# Print command | |||
print("Running command: {}".format(" ".join(cmd))) | |||
# Run PyInstaller | |||
try: | |||
subprocess.check_call(cmd) | |||
print("\nBuild completed successfully!") | |||
# Copy necessary files to dist folder | |||
dist_dir = os.path.join(script_dir, "dist", package_name) | |||
if not os.path.exists(dist_dir): | |||
dist_dir = os.path.join(script_dir, "dist") | |||
# Copy template file to dist folder | |||
if os.path.exists("template.xlsx"): | |||
shutil.copy("template.xlsx", dist_dir) | |||
print("Copied template.xlsx to {}".format(dist_dir)) | |||
# Create empty config file if it doesn't exist | |||
config_path = os.path.join(dist_dir, "employee_info.json") | |||
if not os.path.exists(config_path): | |||
with open(config_path, 'w', encoding='utf-8') as f: | |||
f.write("[]") | |||
print("Created empty employee_info.json in {}".format(dist_dir)) | |||
print("\nBuild is ready in: {}".format(dist_dir)) | |||
except subprocess.CalledProcessError as e: | |||
print("Build failed with error:") | |||
print(e) | |||
return 1 | |||
except Exception as e: | |||
print("An error occurred:") | |||
print(e) | |||
return 1 | |||
print("Build completed successfully!") | |||
print("The executable can be found in the 'dist' directory.") | |||
return 0 | |||
if __name__ == "__main__": | |||
build_executable() | |||
sys.exit(main()) |
@@ -35,6 +35,7 @@ | |||
('_threading_local', | |||
'C:\\Users\\WIN\\AppData\\Roaming\\uv\\python\\cpython-3.12.3-windows-x86_64-none\\Lib\\_threading_local.py', | |||
'PYMODULE'), | |||
('app', 'D:\\2025Project\\MCP\\excel_converter\\app.py', 'PYMODULE'), | |||
('argparse', | |||
'C:\\Users\\WIN\\AppData\\Roaming\\uv\\python\\cpython-3.12.3-windows-x86_64-none\\Lib\\argparse.py', | |||
'PYMODULE'), |
@@ -14,8 +14,8 @@ Types if import: | |||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for | |||
tracking down the missing module yourself. Thanks! | |||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), setuptools._distutils.archive_util (optional), setuptools._vendor.backports.tarfile (optional) | |||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), netrc (delayed, conditional), getpass (delayed), setuptools._distutils.util (delayed, conditional, optional), setuptools._distutils.archive_util (optional), setuptools._vendor.backports.tarfile (optional) | |||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), setuptools._distutils.archive_util (optional), setuptools._vendor.backports.tarfile (optional) | |||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional) | |||
missing module named resource - imported by posix (top-level) | |||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level) | |||
@@ -49,13 +49,12 @@ missing module named _manylinux - imported by packaging._manylinux (delayed, opt | |||
missing module named trove_classifiers - imported by setuptools.config._validate_pyproject.formats (optional) | |||
missing module named pyimod02_importers - imported by D:\2025Project\MCP\excel_converter\.venv\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed), D:\2025Project\MCP\excel_converter\.venv\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgres.py (delayed) | |||
missing module named collections.Mapping - imported by collections (optional), pytz.lazy (optional) | |||
missing module named plotly - imported by xlwings.utils (optional), xlwings.pro.reports.main (optional) | |||
missing module named 'matplotlib.figure' - imported by pandas.plotting._misc (conditional), xlwings.utils (optional), xlwings.pro.reports.main (optional) | |||
missing module named 'PIL.Image' - imported by xlwings.pro.reports.main (optional) | |||
missing module named PIL - imported by openpyxl.drawing.image (optional), xlwings.pro.reports.main (optional), xlwings.main (optional), xlwings._xlwindows (optional), xlwings._xlmac (optional) | |||
missing module named jinja2 - imported by xlwings.pro.reports.main (optional), pandas.io.formats.style (top-level) | |||
missing module named cryptography - imported by xlwings.pro.utils (optional) | |||
missing module named mistune - imported by xlwings.pro.reports.markdown (optional) | |||
missing module named 'defusedxml.ElementTree' - imported by openpyxl.xml.functions (conditional) | |||
missing module named 'lxml.etree' - imported by openpyxl.xml.functions (conditional), pandas.io.xml (delayed), pandas.io.formats.xml (delayed), pandas.io.html (delayed) | |||
missing module named openpyxl.tests - imported by openpyxl.reader.excel (optional) | |||
missing module named defusedxml - imported by openpyxl.xml (delayed, optional) | |||
missing module named lxml - imported by openpyxl.xml (delayed, optional), pandas.io.xml (conditional) | |||
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional) | |||
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional) | |||
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional) | |||
@@ -243,6 +242,12 @@ missing module named numpy._core.all - imported by numpy._core (top-level), nump | |||
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional) | |||
missing module named yaml - imported by numpy.__config__ (delayed) | |||
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional) | |||
missing module named plotly - imported by xlwings.utils (optional), xlwings.pro.reports.main (optional) | |||
missing module named 'matplotlib.figure' - imported by pandas.plotting._misc (conditional), xlwings.utils (optional), xlwings.pro.reports.main (optional) | |||
missing module named 'PIL.Image' - imported by xlwings.pro.reports.main (optional) | |||
missing module named jinja2 - imported by xlwings.pro.reports.main (optional), pandas.io.formats.style (top-level) | |||
missing module named cryptography - imported by xlwings.pro.utils (optional) | |||
missing module named mistune - imported by xlwings.pro.reports.markdown (optional) | |||
missing module named 'win32com.gen_py' - imported by win32com (conditional, optional) | |||
missing module named 'appscript.reference' - imported by xlwings._xlmac (top-level) | |||
missing module named osax - imported by xlwings._xlmac (top-level) | |||
@@ -253,11 +258,6 @@ missing module named matplotlib - imported by pandas.plotting._core (conditional | |||
missing module named pdfrw - imported by xlwings.pro.reports.pdf (optional) | |||
missing module named 'matplotlib.pyplot' - imported by pandas.io.formats.style (optional), xlwings.utils (optional) | |||
missing module named cStringIO - imported by xlrd.timemachine (conditional) | |||
missing module named defusedxml - imported by openpyxl.xml (delayed, optional) | |||
missing module named lxml - imported by openpyxl.xml (delayed, optional), pandas.io.xml (conditional) | |||
missing module named 'defusedxml.ElementTree' - imported by openpyxl.xml.functions (conditional) | |||
missing module named 'lxml.etree' - imported by openpyxl.xml.functions (conditional), pandas.io.xml (delayed), pandas.io.formats.xml (delayed), pandas.io.html (delayed) | |||
missing module named openpyxl.tests - imported by openpyxl.reader.excel (optional) | |||
missing module named six.moves.range - imported by six.moves (top-level), dateutil.rrule (top-level) | |||
runtime module named six.moves - imported by dateutil.tz.tz (top-level), dateutil.tz._factories (top-level), dateutil.tz.win (top-level), dateutil.rrule (top-level) | |||
missing module named dateutil.tz.tzfile - imported by dateutil.tz (top-level), dateutil.zoneinfo (top-level) |
@@ -1,16 +1,37 @@ | |||
# -*- coding: utf-8 -*- | |||
# Excel 转换工具配置文件 | |||
import os | |||
import json | |||
import sys | |||
import logging | |||
# 模板文件路径 | |||
TEMPLATE_PATH = "template.xlsx" | |||
# 配置文件路径 | |||
CONFIG_DIR = os.path.dirname(os.path.abspath(__file__)) | |||
# 检测是否为打包环境 | |||
if getattr(sys, 'frozen', False): | |||
# PyInstaller打包后的环境 | |||
CONFIG_DIR = os.path.dirname(sys.executable) | |||
else: | |||
# 开发环境 | |||
CONFIG_DIR = os.path.dirname(os.path.abspath(__file__)) | |||
EMPLOYEE_CONFIG_PATH = os.path.join(CONFIG_DIR, "employee_info.json") | |||
COMPANY_CONFIG_PATH = os.path.join(CONFIG_DIR, "company_options.json") # 保留兼容性 | |||
BANK_CONFIG_PATH = os.path.join(CONFIG_DIR, "bank_options.json") # 保留兼容性 | |||
# 设置日志记录 | |||
logging.basicConfig( | |||
level=logging.DEBUG, | |||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', | |||
handlers=[ | |||
logging.FileHandler(os.path.join(CONFIG_DIR, "config.log")), | |||
logging.StreamHandler() | |||
] | |||
) | |||
logger = logging.getLogger("config") | |||
# 单元格映射关系(源文件位置 -> 目标文件位置) | |||
# 格式:{(源文件sheet索引, 行, 列): (目标文件sheet索引, 行, 列)} | |||
# 注意:源文件行索引为0表示从C3开始的行 | |||
@@ -85,15 +106,20 @@ DEFAULT_EMPLOYEE_INFO = [ | |||
# 加载员工信息 | |||
def load_employee_info(): | |||
# 检查是否存在员工信息配置 | |||
logger.debug("尝试从 {0} 加载员工信息".format(EMPLOYEE_CONFIG_PATH)) | |||
if os.path.exists(EMPLOYEE_CONFIG_PATH): | |||
try: | |||
with open(EMPLOYEE_CONFIG_PATH, 'r', encoding='utf-8') as f: | |||
employee_info = json.load(f) | |||
logger.info("成功加载 {0} 条员工信息".format(len(employee_info))) | |||
return employee_info | |||
except Exception as e: | |||
print(f"加载员工信息出错: {e}") | |||
employee_info = DEFAULT_EMPLOYEE_INFO | |||
logger.error("加载员工信息出错: {0}".format(str(e))) | |||
return DEFAULT_EMPLOYEE_INFO | |||
else: | |||
# 如果不存在,尝试从旧的配置中导入 | |||
logger.warning("员工信息配置文件不存在,尝试从旧配置导入") | |||
employee_info = [] | |||
company_options = [] | |||
bank_options = [] | |||
@@ -103,8 +129,9 @@ def load_employee_info(): | |||
try: | |||
with open(COMPANY_CONFIG_PATH, 'r', encoding='utf-8') as f: | |||
company_options = json.load(f) | |||
logger.info("从旧配置加载了 {0} 个公司选项".format(len(company_options))) | |||
except Exception as e: | |||
print(f"加载公司配置出错: {e}") | |||
logger.error("加载公司配置出错: {0}".format(str(e))) | |||
# 加载旧的银行配置 | |||
if os.path.exists(BANK_CONFIG_PATH): | |||
@@ -123,8 +150,9 @@ def load_employee_info(): | |||
"account_holder": "" | |||
}) | |||
bank_options = new_bank_options | |||
logger.info("从旧配置加载了 {0} 个银行选项".format(len(bank_options))) | |||
except Exception as e: | |||
print(f"加载银行配置出错: {e}") | |||
logger.error("加载银行配置出错: {0}".format(str(e))) | |||
# 合并旧配置 | |||
if bank_options and isinstance(bank_options[0], dict): | |||
@@ -141,21 +169,47 @@ def load_employee_info(): | |||
# 保存新的员工信息 | |||
save_options(EMPLOYEE_CONFIG_PATH, employee_info) | |||
return employee_info | |||
logger.info("创建了新的员工信息配置,包含 {0} 条记录".format(len(employee_info))) | |||
return employee_info | |||
# 保存选项 | |||
def save_options(config_path, options): | |||
try: | |||
# 确保目录存在 | |||
config_dir = os.path.dirname(config_path) | |||
if not os.path.exists(config_dir): | |||
os.makedirs(config_dir) | |||
logger.info("创建目录: {0}".format(config_dir)) | |||
# 保存前记录当前工作目录和文件路径 | |||
logger.debug("当前工作目录: {0}".format(os.getcwd())) | |||
logger.debug("保存配置到: {0}".format(config_path)) | |||
# 保存配置 | |||
with open(config_path, 'w', encoding='utf-8') as f: | |||
json.dump(options, f, ensure_ascii=False, indent=4) | |||
return True | |||
# 验证保存是否成功 | |||
if os.path.exists(config_path): | |||
logger.info("成功保存配置到 {0}".format(config_path)) | |||
return True | |||
else: | |||
logger.error("保存失败,文件不存在: {0}".format(config_path)) | |||
return False | |||
except Exception as e: | |||
print(f"保存配置出错: {e}") | |||
logger.error("保存配置出错: {0}".format(str(e)), exc_info=True) | |||
return False | |||
# 加载选项 | |||
EMPLOYEE_INFO = load_employee_info() | |||
COMPANY_OPTIONS = [info.get("company_name") for info in EMPLOYEE_INFO if info.get("company_name")] | |||
COMPANY_OPTIONS = list(set(COMPANY_OPTIONS)) # 去重 | |||
BANK_OPTIONS = [info for info in EMPLOYEE_INFO] # 兼容性:旧代码可能仍使用BANK_OPTIONS | |||
try: | |||
logger.info("开始加载配置...") | |||
EMPLOYEE_INFO = load_employee_info() | |||
COMPANY_OPTIONS = [info.get("company_name") for info in EMPLOYEE_INFO if info.get("company_name")] | |||
COMPANY_OPTIONS = list(set(COMPANY_OPTIONS)) # 去重 | |||
BANK_OPTIONS = [info for info in EMPLOYEE_INFO] # 兼容性:旧代码可能仍使用BANK_OPTIONS | |||
logger.info("加载了 {0} 条员工信息, {1} 个公司选项".format(len(EMPLOYEE_INFO), len(COMPANY_OPTIONS))) | |||
except Exception as e: | |||
logger.critical("配置加载失败: {0}".format(str(e)), exc_info=True) | |||
EMPLOYEE_INFO = DEFAULT_EMPLOYEE_INFO | |||
COMPANY_OPTIONS = [] | |||
BANK_OPTIONS = [] |
@@ -147,10 +147,10 @@ | |||
"account_holder": "" | |||
}, | |||
{ | |||
"employee_name": "西本智子", | |||
"employee_name": "西本智子1", | |||
"company_name": "SPD株式会社", | |||
"bank_name": "", | |||
"branch_account": "", | |||
"bank_name": "11", | |||
"branch_account": "11", | |||
"account_holder": "" | |||
} | |||
] |
@@ -1,3 +1,4 @@ | |||
# -*- coding: utf-8 -*- | |||
import os | |||
import sys | |||
import tkinter as tk | |||
@@ -27,7 +28,7 @@ def main(): | |||
screen_height = root.winfo_screenheight() | |||
x = (screen_width - window_width) // 2 | |||
y = (screen_height - window_height) // 2 | |||
root.geometry(f"{window_width}x{window_height}+{x}+{y}") | |||
root.geometry("{0}x{1}+{2}+{3}".format(window_width, window_height, x, y)) | |||
# Run the application | |||
root.mainloop() |
@@ -1,5 +1,5 @@ | |||
pandas>=2.0.0 | |||
openpyxl>=3.1.0 | |||
xlrd>=2.0.0 | |||
xlwings>=0.30.0 | |||
pyinstaller>=6.0.0 | |||
openpyxl>=3.0.0 | |||
pandas>=1.0.0 | |||
xlrd>=1.0.0 | |||
xlwings>=0.20.0 | |||
pyinstaller>=4.0.0 |