05/23 Phase 7
This commit is contained in:
+23
-1
@@ -7,8 +7,9 @@ Analysis screen — three Matplotlib charts embedded in a ttk.Notebook.
|
||||
• Gap — draws since each number last appeared
|
||||
"""
|
||||
|
||||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from tkinter import ttk, filedialog, messagebox
|
||||
|
||||
import numpy as np
|
||||
import matplotlib
|
||||
@@ -18,6 +19,7 @@ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolb
|
||||
|
||||
from db.models import get_all_games, get_game_by_id, get_game_by_name
|
||||
from core.analyzer import frequency_analysis, gap_analysis, positional_frequency
|
||||
from core.exporter import export_frequency_excel, ensure_exports_dir
|
||||
|
||||
_LAST_N_OPTIONS = {
|
||||
"All draws": None,
|
||||
@@ -60,6 +62,7 @@ class AnalysisScreen(ttk.Frame):
|
||||
last_n_cb.bind("<<ComboboxSelected>>", lambda _: self._redraw_frequency())
|
||||
|
||||
ttk.Button(bar, text="↻ Refresh", command=self.refresh).pack(side="right")
|
||||
ttk.Button(bar, text="Export Frequency", command=self._export_frequency).pack(side="right", padx=(0, 4))
|
||||
|
||||
# Notebook with three chart tabs
|
||||
nb = ttk.Notebook(self)
|
||||
@@ -141,6 +144,25 @@ class AnalysisScreen(ttk.Frame):
|
||||
_draw_gap(ax, self._game_id)
|
||||
self._gap_canvas.draw()
|
||||
|
||||
def _export_frequency(self):
|
||||
if self._game_id is None:
|
||||
messagebox.showinfo("Export", "Select a game first.")
|
||||
return
|
||||
ensure_exports_dir()
|
||||
fp = filedialog.asksaveasfilename(
|
||||
title="Export frequency analysis",
|
||||
defaultextension=".xlsx",
|
||||
filetypes=[("Excel workbook", "*.xlsx")],
|
||||
initialfile=f"frequency_{__import__('datetime').datetime.now().strftime('%Y%m%d')}.xlsx",
|
||||
)
|
||||
if not fp:
|
||||
return
|
||||
try:
|
||||
last_n = _LAST_N_OPTIONS.get(self._last_n_var.get())
|
||||
export_frequency_excel(fp, self._game_id, last_n=last_n)
|
||||
except Exception as e:
|
||||
messagebox.showerror("Export failed", str(e))
|
||||
|
||||
|
||||
# ── Pure chart-drawing functions (no Tkinter, just axes) ─────────────────────
|
||||
|
||||
|
||||
+59
-2
@@ -5,10 +5,14 @@ Draw History browser screen.
|
||||
Shows a sortable, filterable Treeview of all draw records.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from tkinter import ttk, filedialog, messagebox
|
||||
|
||||
from db.models import get_all_games, get_game_by_name, get_draws_with_game
|
||||
from core.exporter import (
|
||||
export_draws_excel, export_draws_csv, default_path, ensure_exports_dir,
|
||||
)
|
||||
|
||||
_COLUMNS = ("game", "date", "numbers", "bonus", "multiplier", "source")
|
||||
_LABELS = {
|
||||
@@ -77,7 +81,9 @@ class HistoryScreen(ttk.Frame):
|
||||
ttk.Button(bar, text="Search", command=self._apply_filter).pack(side="left", padx=(0, 4))
|
||||
ttk.Button(bar, text="Clear", command=self._clear_filter).pack(side="left")
|
||||
|
||||
ttk.Button(bar, text="↻ Refresh", command=self.refresh).pack(side="right")
|
||||
ttk.Button(bar, text="↻ Refresh", command=self.refresh).pack(side="right")
|
||||
ttk.Button(bar, text="Export CSV", command=self._export_csv).pack(side="right", padx=(0, 4))
|
||||
ttk.Button(bar, text="Export Excel",command=self._export_excel).pack(side="right", padx=(0, 4))
|
||||
|
||||
# ── Treeview + scrollbars ─────────────────────────────────────────────
|
||||
tree_frame = ttk.Frame(self)
|
||||
@@ -213,3 +219,54 @@ class HistoryScreen(ttk.Frame):
|
||||
for c in _COLUMNS:
|
||||
self._tree.heading(c, text=_LABELS[c])
|
||||
self._apply_filter()
|
||||
|
||||
# ── Export ────────────────────────────────────────────────────────────────
|
||||
|
||||
def _current_filter(self):
|
||||
"""Return (game_id, date_from, date_to) for the active filter."""
|
||||
name = self._game_var.get()
|
||||
if name == "All Games":
|
||||
game_id = None
|
||||
else:
|
||||
g = get_game_by_name(name)
|
||||
game_id = g["id"] if g else None
|
||||
|
||||
raw_from = self._from_entry.get().strip()
|
||||
raw_to = self._to_entry.get().strip()
|
||||
date_from = raw_from if raw_from and raw_from != "YYYY-MM-DD" else None
|
||||
date_to = raw_to if raw_to and raw_to != "YYYY-MM-DD" else None
|
||||
return game_id, date_from, date_to
|
||||
|
||||
def _export_excel(self):
|
||||
ensure_exports_dir()
|
||||
fp = filedialog.asksaveasfilename(
|
||||
title="Export draw history",
|
||||
defaultextension=".xlsx",
|
||||
filetypes=[("Excel workbook", "*.xlsx")],
|
||||
initialfile=f"draws_{__import__('datetime').datetime.now().strftime('%Y%m%d')}.xlsx",
|
||||
)
|
||||
if not fp:
|
||||
return
|
||||
try:
|
||||
game_id, date_from, date_to = self._current_filter()
|
||||
export_draws_excel(fp, game_id=game_id, date_from=date_from, date_to=date_to)
|
||||
self._count_var.set(f"Exported → {os.path.basename(fp)}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Export failed", str(e))
|
||||
|
||||
def _export_csv(self):
|
||||
ensure_exports_dir()
|
||||
fp = filedialog.asksaveasfilename(
|
||||
title="Export draw history",
|
||||
defaultextension=".csv",
|
||||
filetypes=[("CSV file", "*.csv")],
|
||||
initialfile=f"draws_{__import__('datetime').datetime.now().strftime('%Y%m%d')}.csv",
|
||||
)
|
||||
if not fp:
|
||||
return
|
||||
try:
|
||||
game_id, date_from, date_to = self._current_filter()
|
||||
export_draws_csv(fp, game_id=game_id, date_from=date_from, date_to=date_to)
|
||||
self._count_var.set(f"Exported → {os.path.basename(fp)}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Export failed", str(e))
|
||||
|
||||
+45
-1
@@ -5,14 +5,16 @@ Prediction generator screen.
|
||||
Pick a strategy + game + ticket count → generate → save to DB.
|
||||
"""
|
||||
|
||||
import os
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from tkinter import ttk, filedialog, messagebox
|
||||
import logging
|
||||
|
||||
from db.models import get_all_games, get_game_by_name, insert_prediction
|
||||
from core.predictor import (
|
||||
hot_numbers, due_numbers, weighted_random, monte_carlo, positional_pick,
|
||||
)
|
||||
from core.exporter import export_predictions_excel, export_predictions_csv, ensure_exports_dir
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -121,6 +123,14 @@ class PredictorScreen(ttk.Frame):
|
||||
bottom, text="Clear", command=self._clear
|
||||
).pack(side="right", padx=(0, 4))
|
||||
|
||||
ttk.Button(
|
||||
bottom, text="Export CSV", command=self._export_csv, state="normal"
|
||||
).pack(side="right", padx=(0, 4))
|
||||
|
||||
ttk.Button(
|
||||
bottom, text="Export Excel", command=self._export_excel, state="normal"
|
||||
).pack(side="right", padx=(0, 4))
|
||||
|
||||
# ── Callbacks ─────────────────────────────────────────────────────────────
|
||||
|
||||
def refresh(self):
|
||||
@@ -198,3 +208,37 @@ class PredictorScreen(ttk.Frame):
|
||||
self._tree.delete(*self._tree.get_children())
|
||||
self._save_btn.config(state="disabled")
|
||||
self._status_var.set("")
|
||||
|
||||
def _export_excel(self):
|
||||
ensure_exports_dir()
|
||||
fp = filedialog.asksaveasfilename(
|
||||
title="Export predictions",
|
||||
defaultextension=".xlsx",
|
||||
filetypes=[("Excel workbook", "*.xlsx")],
|
||||
initialfile=f"predictions_{__import__('datetime').datetime.now().strftime('%Y%m%d')}.xlsx",
|
||||
)
|
||||
if not fp:
|
||||
return
|
||||
try:
|
||||
game_id = self._game_id
|
||||
export_predictions_excel(fp, game_id=game_id)
|
||||
self._status_var.set(f"Exported → {os.path.basename(fp)}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Export failed", str(e))
|
||||
|
||||
def _export_csv(self):
|
||||
ensure_exports_dir()
|
||||
fp = filedialog.asksaveasfilename(
|
||||
title="Export predictions",
|
||||
defaultextension=".csv",
|
||||
filetypes=[("CSV file", "*.csv")],
|
||||
initialfile=f"predictions_{__import__('datetime').datetime.now().strftime('%Y%m%d')}.csv",
|
||||
)
|
||||
if not fp:
|
||||
return
|
||||
try:
|
||||
game_id = self._game_id
|
||||
export_predictions_csv(fp, game_id=game_id)
|
||||
self._status_var.set(f"Exported → {os.path.basename(fp)}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Export failed", str(e))
|
||||
|
||||
Reference in New Issue
Block a user