π GitHub Repo: https://github.com/rogers-cyber/CSVtoExcel
In this tutorial, youβll learn how to build a modern desktop app that:
Converts CSV β Excel (.xlsx)
Shows a preview of data
Saves history using SQLite
Supports batch processing
π§± Step 1 β Install Dependencies
First, install required packages:
pip install PySide6 xlsxwriter
π§ Step 2 β Project Structure
Create a simple structure:
csv_to_excel_app/
β
βββ main.py
βββ logo.ico (optional)
βοΈ Step 3 β Basic App Setup
Letβs create a minimal PySide6 app window.
import sys
from PySide6 import QtWidgets
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
window.setWindowTitle("CSVtoExcel")
window.resize(800, 500)
window.show()
sys.exit(app.exec())
π This gives you a blank desktop window.
π Step 4 β Create App Data Folder
We store history (SQLite DB) in a system-safe location.
from pathlib import Path
import os
import sys
def get_app_dir() -> Path:
if sys.platform.startswith("win"):
base = Path(os.getenv('LOCALAPPDATA') or Path.home())
elif sys.platform.startswith("darwin"):
base = Path.home() / 'Library/Application Support'
else:
base = Path.home() / '.local/share'
app_dir = base / "csv_to_excel_app"
app_dir.mkdir(parents=True, exist_ok=True)
return app_dir
π Step 5 β Setup SQLite Database
We store conversion history.
import sqlite3
DB_PATH = get_app_dir() / "history.db"
def init_db():
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS history(
id INTEGER PRIMARY KEY AUTOINCREMENT,
src_path TEXT,
dest_path TEXT,
timestamp TEXT,
rows INTEGER,
cols INTEGER
)
""")
conn.commit()
conn.close()
π Call this once when the app starts.
π₯ Step 6 β Load CSV File
Let users pick a CSV file.
from PySide6.QtWidgets import QFileDialog
def open_csv():
file, _ = QFileDialog.getOpenFileName(
None,
"Open CSV",
"",
"CSV Files (*.csv)"
)
return file
π Step 7 β Preview CSV Data
We read first 100 rows.
import csv
def preview_csv(path, limit=100):
rows = []
with open(path, encoding="utf-8", errors="replace") as f:
reader = csv.reader(f)
for i, row in enumerate(reader):
if i >= limit:
break
rows.append(row)
return rows
π This keeps the app fast even with large files.
π Step 8 β Convert CSV β Excel
Now the core feature π₯
import xlsxwriter
def convert_to_excel(csv_path, output_path):
with open(csv_path, encoding="utf-8", errors="replace") as f:
reader = csv.reader(f)
rows = list(reader)
workbook = xlsxwriter.Workbook(output_path, {'strings_to_urls': False})
sheet = workbook.add_worksheet()
for r, row in enumerate(rows):
for c, value in enumerate(row):
sheet.write(r, c, value)
workbook.close()
π§Ύ Step 9 β Save History
Every conversion is stored.
from datetime import datetime
def save_history(src, dest, rows, cols):
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
c.execute(
"INSERT INTO history (src_path, dest_path, timestamp, rows, cols) VALUES (?, ?, ?, ?, ?)",
(src, dest, datetime.utcnow().isoformat(), rows, cols)
)
conn.commit()
conn.close()
π§΅ Step 10 β Run Conversion in Background
We avoid freezing the UI using threads.
from PySide6.QtCore import QRunnable, QThreadPool
class Worker(QRunnable):
def __init__(self, csv_path, output):
super().__init__()
self.csv_path = csv_path
self.output = output
def run(self):
convert_to_excel(self.csv_path, self.output)
Run it:
pool = QThreadPool()
pool.start(Worker("input.csv", "output.xlsx"))
π₯ Step 11 β Build UI Layout
Add buttons + table preview.
layout = QtWidgets.QVBoxLayout()
btn_open = QtWidgets.QPushButton("Open CSV")
btn_convert = QtWidgets.QPushButton("Convert")
table = QtWidgets.QTableWidget()
layout.addWidget(btn_open)
layout.addWidget(btn_convert)
layout.addWidget(table)
π¨ Step 12 β Add Styling (QSS)
app.setStyleSheet("""
QPushButton {
background: #1976d2;
color: white;
padding: 6px;
border-radius: 6px;
}
QPushButton:hover {
background: #125aa0;
}
""")
π¦ Step 13 β Build EXE (Optional)
Use PyInstaller:
pip install pyinstaller
pyinstaller --onefile --windowed main.py
π Final Result
You now have a desktop app that:
β
Converts CSV to Excel
β
Handles large files
β
Saves history
β
Has a modern UI
π‘ Pro Tips
Add drag & drop support
Add batch folder conversion
Add encoding selector
Add preview table model (QTableView)
π Full Source Code

Top comments (0)