Initial commit

This commit is contained in:
Todd Sales
2025-06-23 21:01:55 -04:00
commit d42b70325a
2000 changed files with 183840 additions and 0 deletions

511
venv/app.py Normal file
View File

@ -0,0 +1,511 @@
import sqlite3
import os
import tkinter as tk
from tkinter import ttk
import openpyxl # You'd still need this if you're integrating directly
# Re-using the grouping function from the previous response for context
def group_rows_by_color(excel_file_path):
"""
Groups rows from an Excel file where each new group starts at a color-filled row.
(This is a simplified version; refer to the full previous code for details)
"""
try:
workbook = openpyxl.load_workbook(excel_file_path)
sheet = workbook.active
groups = []
current_group = []
for row_index, row in enumerate(sheet.iter_rows()):
first_cell = row[0]
is_color_filled_row = False
if first_cell.fill and first_cell.fill.patternType:
is_color_filled_row = True
row_values = [cell.value for cell in row]
if is_color_filled_row:
if current_group:
groups.append(current_group)
current_group = [row_values]
else:
current_group.append(row_values)
if current_group:
groups.append(current_group)
return groups
except FileNotFoundError:
print(f"Error: The file '{excel_file_path}' was not found.")
return []
except Exception as e:
print(f"An error occurred during grouping: {e}")
return []
def create_and_insert_data_to_db(grouped_data, db_name='my_grouped_data.db'):
"""
Creates a SQLite database table and inserts the grouped data.
Args:
grouped_data (list): A list of lists, where each inner list is a group
and contains rows (lists of cell values).
db_name (str): The name of the SQLite database file.
"""
conn = None
try:
conn = sqlite3.connect(db_name)
cursor = conn.cursor()
# --- 1. Create Table ---
# Define your table schema.
# You'll need to adapt 'Column1', 'Column2', etc., based on your actual data columns.
# For simplicity, let's assume a fixed number of columns for each row
# and add a 'group_id' to link rows to their respective groups.
# Example schema: (adjust based on your actual data structure)
# You might have a variable number of columns or specific names.
# This example assumes up to 10 columns per row, and adds a group_id.
# You should inspect your data to determine the actual number and type of columns.
# To make it flexible, let's assume the first row of your data (e.g., headers)
# defines the column count.
# Determine the maximum number of columns across all groups/rows to create a flexible table
max_cols = 0
for group in grouped_data:
for row in group:
if len(row) > max_cols:
max_cols = len(row)
# Create column definitions
columns_sql = [f"Column{i+1} TEXT" for i in range(max_cols)]
table_columns = "group_id INTEGER, row_in_group_id INTEGER, " + ", ".join(columns_sql)
cursor.execute(f'''
CREATE TABLE IF NOT EXISTS grouped_data (
{table_columns}
)
''')
conn.commit()
print(f"Table 'grouped_data' created or already exists in '{db_name}'.")
# --- 2. Insert Data ---
for group_id, group in enumerate(grouped_data):
for row_in_group_id, row_values in enumerate(group):
# Prepare data for insertion
# Fill missing columns with None to match the table's max_cols
padded_row_values = row_values + [None] * (max_cols - len(row_values))
# The values to insert will be group_id, row_in_group_id, then the row_values
values_to_insert = [group_id, row_in_group_id] + padded_row_values
# Create placeholders for the SQL query
placeholders = ', '.join(['?'] * len(values_to_insert))
cursor.execute(f'''
INSERT INTO grouped_data VALUES ({placeholders})
''', values_to_insert)
conn.commit()
print(f"Successfully inserted {len(grouped_data)} groups into '{db_name}'.")
except sqlite3.Error as e:
print(f"SQLite error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
if conn:
conn.close()
# --- How to use it ---
# 1. First, get your grouped data using the function from earlier:
excel_file_path = 'c:/Users/Todd.SFC/CascadeProjects/data_importer/Buff.xlsx' # Make sure this is the path to your actual .xlsx file
my_grouped_data = group_rows_by_color(excel_file_path)
def view_database_records(db_name='my_project_data.db', max_rows=50):
"""
View all records from the database in a more readable format.
Args:
db_name (str): Name of the SQLite database file
max_rows (int): Maximum number of rows to display per group
"""
try:
conn = sqlite3.connect(db_name)
conn.row_factory = sqlite3.Row # This allows column access by name
cursor = conn.cursor()
# Get all table names
cursor.execute("SELECT name FROM sqlite_master WHERE type='table';")
tables = cursor.fetchall()
for table in tables:
table_name = table[0]
print(f"\n{'='*80}")
print(f"TABLE: {table_name.upper()}")
print(f"{'='*80}")
# Get column info
cursor.execute(f"PRAGMA table_info({table_name})")
columns = [col[1] for col in cursor.fetchall()]
# Get all rows
cursor.execute(f"SELECT * FROM {table_name}")
rows = cursor.fetchall()
if not rows:
print("No records found.")
continue
# Group data by group_id if it exists
if 'group_id' in columns:
groups = {}
for row in rows:
group_id = row['group_id']
if group_id not in groups:
groups[group_id] = []
groups[group_id].append(dict(row))
# Display each group separately
for group_id, group_rows in groups.items():
print(f"\n{'*' * 30} Group {group_id} {'*' * 30}")
# Display column headers
header = " | ".join(f"{col:15}" for col in columns if col not in ['group_id', 'row_in_group_id'])
print(f"\n{' '*3}{header}")
print("-" * len(header) * 2)
# Display rows
for i, row in enumerate(group_rows[:max_rows]):
if i > 0 and i % 5 == 0 and i < len(group_rows) - 1:
print(f"{' '*3}... {len(group_rows) - i} more rows in group ...")
break
row_values = [str(row.get(col, ''))[:15].ljust(15) for col in columns
if col not in ['group_id', 'row_in_group_id']]
print(f"{row['row_in_group_id']:2} | {' | '.join(row_values)}")
if len(group_rows) > max_rows:
print(f"\nShowing first {max_rows} of {len(group_rows)} rows in group")
else:
# Display as a simple table if no group_id
print(f"\n{' | '.join(columns)}\n{'-' * 50}")
for i, row in enumerate(rows[:max_rows]):
if i > 0 and i % 10 == 0 and i < len(rows) - 1:
print(f"... {len(rows) - i} more rows ...")
break
print(" | ".join(str(value)[:30].ljust(30) for value in row))
if len(rows) > max_rows:
print(f"\nShowing first {max_rows} of {len(rows)} rows")
print(f"\nTotal rows in {table_name}: {len(rows)}")
except sqlite3.Error as e:
print(f"Database error: {e}")
except Exception as e:
print(f"An error occurred: {e}")
finally:
if conn:
conn.close()
# --- How to use the script ---
if __name__ == "__main__":
# First, process the Excel file and create the database
excel_file_path = 'c:/Users/Todd.SFC/CascadeProjects/data_importer/Buff.xlsx' # Update this to your Excel file path
my_grouped_data = group_rows_by_color(excel_file_path)
if my_grouped_data:
db_name = 'my_project_data.db'
create_and_insert_data_to_db(my_grouped_data, db_name)
# Then view the records
print("\nViewing database records:")
view_database_records(db_name)
else:
print("No data to process. Please check your Excel file path and contents.")
# print(row)
# conn.close()
import tkinter as tk
from tkinter import ttk
import sqlite3
def create_gui(db_name='my_project_data.db'):
"""
Creates a tkinter GUI to view SQLite database records with group selection.
Features:
- Dropdown to select a specific group
- Button to show all groups
- Treeview to display records
- Auto-refresh capability
Args:
db_name (str): Name of the SQLite database file
"""
def refresh_data():
"""Refresh the data from the database and update the UI"""
# Clear existing items in the tree
for item in tree.get_children():
tree.delete(item)
try:
# Check if database file exists
db_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', db_name)
if not os.path.exists(db_path):
error_msg = f"Database file not found: {db_path}"
print(error_msg)
status_label.config(text=error_msg, fg='red')
return
print(f"Connecting to database: {db_path}")
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Check if table exists
table_name = 'grouped_data'
print(f"Checking for table: {table_name}")
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
all_tables = cursor.fetchall()
print(f"All tables in database: {all_tables}")
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
if not cursor.fetchone():
error_msg = f"Table '{table_name}' not found in database. Available tables: {[t[0] for t in all_tables]}"
print(error_msg)
status_label.config(text=error_msg, fg='red')
conn.close()
return
print(f"Getting table info for: {table_name}")
cursor.execute(f"PRAGMA table_info({table_name})")
columns_info = cursor.fetchall()
print(f"Table columns: {columns_info}")
columns = [col[1] for col in columns_info]
print(f"Extracted column names: {columns}")
# Configure tree columns if not already set
if not tree['columns'] or set(tree['columns']) != set(columns):
# Clear existing columns
for col in tree['columns']:
tree.heading(col, text='')
tree.column(col, width=0, stretch=tk.NO)
# Set new columns
tree['columns'] = columns
tree.heading('#0', text='Group')
tree.column('#0', width=150, minwidth=100, stretch=tk.NO)
for col in columns:
tree.heading(col, text=col)
tree.column(col, width=100, minwidth=50, stretch=tk.YES)
# Get all rows
print("Fetching all rows from the table...")
cursor.execute(f"SELECT * FROM {table_name} ORDER BY group_id, row_in_group_id")
rows = cursor.fetchall()
print(f"Fetched {len(rows)} rows from the database")
if not rows:
print(f"No data found in table '{table_name}'.")
status_label.config(text=f"No data found in table '{table_name}'", fg='orange')
conn.close()
return
# Group rows by group_id
global all_groups
all_groups = {}
for row in rows:
row_dict = dict(row) # Convert to dict for easier access
group_id = row_dict.get('group_id')
if group_id is not None:
if group_id not in all_groups:
all_groups[group_id] = []
all_groups[group_id].append(row_dict)
print(f"Grouped data into {len(all_groups)} groups")
# Update dropdown with all group IDs
group_ids = sorted(all_groups.keys(), key=lambda x: int(x) if str(x).isdigit() else float('inf'))
current_selection = group_selector.get()
group_selector['values'] = group_ids
# Try to maintain the current selection if it still exists
if current_selection in group_ids:
group_selector.set(current_selection)
show_only_group(current_selection)
elif group_ids:
group_selector.set(str(group_ids[0]))
show_only_group(group_ids[0])
status_label.config(text=f"Loaded {len(rows)} records in {len(group_ids)} groups", fg='green')
conn.close()
except sqlite3.Error as e:
error_msg = f"Database error: {e}"
print(error_msg)
status_label.config(text=error_msg, fg='red')
except Exception as e:
error_msg = f"Unexpected error: {str(e)}"
print(error_msg)
status_label.config(text=error_msg, fg='red')
def on_group_selected(event):
"""Handler for group selection change"""
selected_group = group_selector.get()
if selected_group:
# Convert to int if it's a digit, otherwise keep as string
try:
group_id = int(selected_group) if selected_group.isdigit() else selected_group
show_only_group(group_id)
except Exception as e:
error_msg = f"Error selecting group: {str(e)}"
print(error_msg)
status_label.config(text=error_msg, fg='red')
def show_only_group(group_id):
"""Display only the records from the selected group"""
# Clear existing items in the tree
for item in tree.get_children():
tree.delete(item)
print(f"Attempting to show group: {group_id} (type: {type(group_id)})")
print(f"Available groups: {list(all_groups.keys())}")
# Try to find a matching group ID (handling both string and int types)
matching_group_id = None
for gid in all_groups.keys():
if str(gid) == str(group_id):
matching_group_id = gid
break
if matching_group_id is not None:
print(f"Found matching group: {matching_group_id} (type: {type(matching_group_id)})")
# Insert the selected group's data
group_node = tree.insert('', tk.END, text=f"Group {matching_group_id}", values=[''] * len(tree['columns']))
for row in all_groups[matching_group_id]:
# Get values in the correct order based on tree columns
values = [str(row.get(col, '')) for col in tree['columns']]
tree.insert(group_node, tk.END, values=values)
# Expand the group
tree.item(group_node, open=True)
status_label.config(text=f"Showing group: {matching_group_id}", fg='green')
else:
error_msg = f"Group {group_id} not found in available groups"
print(error_msg)
status_label.config(text=error_msg, fg='red')
def show_all_groups():
"""Display all groups in the treeview"""
# Clear existing items in the tree
for item in tree.get_children():
tree.delete(item)
if not all_groups:
status_label.config(text="No groups to display", fg='orange')
return
# Insert all groups
for group_id, group_rows in all_groups.items():
group_node = tree.insert('', tk.END, text=f"Group {group_id}", values=[''] * len(tree['columns']))
for row in group_rows:
# Get values in the correct order based on tree columns and ensure they're strings
values = [str(row.get(col, '')) for col in tree['columns']]
tree.insert(group_node, tk.END, values=values)
# Expand all groups
tree.item(group_node, open=True)
status_label.config(text=f"Showing all {len(all_groups)} groups", fg='green')
# Create main window
root = tk.Tk()
root.title("Database Group Viewer")
root.geometry("1200x800")
# Configure grid weights
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
# Create controls frame
controls_frame = tk.Frame(root, padx=5, pady=5)
controls_frame.grid(row=0, column=0, sticky='ew')
controls_frame.grid_columnconfigure(1, weight=1)
# Database file label
db_label = tk.Label(controls_frame, text=f"Database:")
db_label.grid(row=0, column=0, padx=5, pady=5, sticky='w')
db_path_label = tk.Label(controls_frame, text=db_name, relief='sunken', padx=5, pady=2, width=50, anchor='w')
db_path_label.grid(row=0, column=1, padx=5, pady=5, sticky='ew')
# Group selection
group_label = tk.Label(controls_frame, text="Select Group:")
group_label.grid(row=0, column=2, padx=5, pady=5, sticky='e')
group_selector = ttk.Combobox(controls_frame, state="readonly", width=20)
group_selector.grid(row=0, column=3, padx=5, pady=5, sticky='w')
group_selector.bind("<<ComboboxSelected>>", on_group_selected)
# Buttons frame
button_frame = tk.Frame(controls_frame)
button_frame.grid(row=0, column=4, padx=10, pady=5, sticky='e')
# Refresh button
refresh_icon = tk.PhotoImage(width=1, height=1) # Placeholder for an actual icon
refresh_button = tk.Button(button_frame, text="🔄 Refresh", command=refresh_data,
padx=10, pady=2, compound='left')
refresh_button.pack(side=tk.LEFT, padx=2)
# Show all groups button
show_all_button = tk.Button(button_frame, text="Show All Groups", command=show_all_groups,
padx=10, pady=2)
show_all_button.pack(side=tk.LEFT, padx=2)
# Create treeview with scrollbars
tree_frame = tk.Frame(root)
tree_frame.grid(row=1, column=0, sticky='nsew', padx=5, pady=(0, 5))
# Vertical scrollbar
vsb = ttk.Scrollbar(tree_frame, orient="vertical")
vsb.pack(side='right', fill='y')
# Horizontal scrollbar
hsb = ttk.Scrollbar(tree_frame, orient="horizontal")
hsb.pack(side='bottom', fill='x')
# Create treeview
tree = ttk.Treeview(tree_frame, yscrollcommand=vsb.set, xscrollcommand=hsb.set, selectmode='browse')
tree.pack(expand=True, fill='both')
# Configure scrollbars
vsb.config(command=tree.yview)
hsb.config(command=tree.xview)
# Status bar
status_frame = tk.Frame(root, height=20, bd=1, relief=tk.SUNKEN)
status_frame.grid(row=2, column=0, sticky='ew')
status_frame.grid_columnconfigure(0, weight=1)
status_label = tk.Label(status_frame, text="Ready", anchor='w')
status_label.pack(side=tk.LEFT, padx=5)
# Initial data load
global all_groups
all_groups = {}
refresh_data()
# Make the window resizable
root.minsize(800, 600)
root.mainloop()
if __name__ == "__main__":
create_gui('my_project_data.db')