Initial commit
This commit is contained in:
511
venv/app.py
Normal file
511
venv/app.py
Normal 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')
|
||||
Reference in New Issue
Block a user