USER
uprav python skript tak, aby odpovidal lepe graficky usporadani kalkulačky podle kodu, který je z webove stranky. kalkulačka v python kodu nezobrazuje vse viditelne ve windows, jak ma. kod z webove stranky odpovida tomu, jak ma byt presne rozlozeno graficke rozhrani.
python skript
import tkinter as tk
from tkinter import ttk, messagebox
import datetime
import os
try:
from convertdate import hebrew
except ImportError:
hebrew = None
class EasterPassoverCalculator(tk.Tk):
def __init__(self):
super().__init__()
self.title("Velikonoční a Pesach Kalkulačka")
self.geometry("900x700")
self.configure(bg="lightgrey")
self.resizable(False, False)
self.create_widgets()
self.calculate() # Inicializace s výpočty pro defaultní rok (1600)
def create_widgets(self):
style = ttk.Style(self)
style.theme_use('clam')
style.configure("TLabel", font=("Arial", 10))
style.configure("TEntry", font=("Arial", 10))
style.configure("TButton", font=("Arial", 10, "bold"))
style.configure("TLabelframe.Label", font=("Arial", 12, "bold"))
# Nadpis
header_frame = tk.Frame(self, bg="lightgrey")
header_frame.pack(pady=10)
header_label = tk.Label(header_frame, text="Velikonoční a Pesach Kalkulačka", font=("Arial", 18, "bold"), fg="red", bg="lightgrey")
header_label.pack()
# Vstupní sekce
input_frame = ttk.LabelFrame(self, text="Vstupní údaje", padding="15")
input_frame.pack(fill=tk.X, padx=20, pady=10)
# Rok
ttk.Label(input_frame, text="Rok (Anno Domini):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.year_var = tk.IntVar(value=1600)
self.year_entry = ttk.Entry(input_frame, textvariable=self.year_var, width=10, justify='center', font=("Arial", 10, "bold"))
self.year_entry.grid(row=0, column=1, pady=5)
# Tlačítka pro zvýšení/snížení roku
btn_minus = ttk.Button(input_frame, text="-", width=3, command=self.subtract_one_year)
btn_minus.grid(row=0, column=2, padx=5)
btn_plus = ttk.Button(input_frame, text="+", width=3, command=self.add_one_year)
btn_plus.grid(row=0, column=3)
# Proleptický Gregoriánský kalendář
ttk.Label(input_frame, text="Zobrazit gregoriánská data před rokem 1583:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.proleptic_var = tk.StringVar(value="Ne")
proleptic_combo = ttk.Combobox(input_frame, textvariable=self.proleptic_var, values=["Ne", "Ano"], state="readonly", width=5)
proleptic_combo.grid(row=1, column=1, pady=5)
# Offset mezi Juliánským a Gregoriánským kalendářem
ttk.Label(input_frame, text="Offset mezi Juliánským a Gregoriánským kalendářem (dny):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.offset_var = tk.IntVar(value=10) # Pro rok 1600 byl offset 10 dnů
self.offset_entry = ttk.Entry(input_frame, textvariable=self.offset_var, width=5, justify='center', font=("Arial", 10, "bold"))
self.offset_entry.grid(row=2, column=1, pady=5)
# Režim Juliánských Velikonoc
ttk.Label(input_frame, text="Režim Juliánských Velikonoc:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.julian_mode_var = tk.StringVar(value="Dionysian")
julian_combo = ttk.Combobox(input_frame, textvariable=self.julian_mode_var, values=["Dionysian", "Armenian/Non-Chalcedonian"], state="readonly", width=25)
julian_combo.grid(row=3, column=1, pady=5)
# Aktualizační tlačítko
update_btn = ttk.Button(input_frame, text="Aktualizovat kalkulačku", command=self.calculate, width=30)
update_btn.grid(row=4, column=0, columnspan=4, pady=15)
# Výstupní sekce
output_frame = ttk.LabelFrame(self, text="Výsledky", padding="15")
output_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# Definice výstupních polí ve formě tabulky
# Použijeme grid pro lepší organizaci
labels = [
("Number in Solar Cycle:", "13"),
("Dominical Letter (Juliánské určení):", "FE"),
("Dominical Letter (Gregoriánské určení):", "BA"),
("Golden Number:", "5"),
("Gregorian Epact:", "XV"),
("Martyrology Letter (Juliánské určení):", "e"),
("Martyrology Letter (Gregoriánské určení):", "q"),
("Juliánské kalendářní datum plné Měsíce (luna XIV):", "22 March"),
("Juliánská Velikonoční neděle:", "23 March"),
("Gregoriánské kalendářní datum plné Měsíce (luna XIV):", "29 March"),
("Gregoriánská Velikonoční neděle:", "2 April"),
("Židovský Pesach (15 Nisan AM):", "15 Nisan 5360 AM"),
("Den v týdnu pro Pesach:", "Thursday"),
("Rozdíl od Gregoriánských po Juliánské Velikonoční neděli:", "0 days"),
("Rozdíl od Pesachu po Gregoriánské Velikonoční neděli:", "3 days"),
("Rozdíl od Pesachu po Juliánské Velikonoční neděli:", "3 days")
]
self.entries = {}
for idx, (label_text, default_value) in enumerate(labels):
ttk.Label(output_frame, text=label_text).grid(row=idx, column=0, sticky=tk.W, pady=5, padx=5)
entry = ttk.Entry(output_frame, width=50, justify='center', font=("Arial", 10, "bold"))
entry.grid(row=idx, column=1, pady=5, padx=5)
entry.insert(0, default_value)
entry.config(state='readonly')
self.entries[label_text] = entry
# Tlačítko pro uložení výsledků
save_btn = ttk.Button(output_frame, text="Uložit výsledky", command=self.save_results, width=20)
save_btn.grid(row=len(labels), column=0, columnspan=2, pady=15)
# Patička
footer_label = tk.Label(self, text="© R.H. van Gent (2010)", fg="red", bg="lightgrey", font=("Arial", 8))
footer_label.pack(pady=10, anchor='e')
def subtract_one_year(self):
current_year = self.year_var.get()
self.year_var.set(current_year - 1)
self.calculate() # Automaticky aktualizovat po změně roku
def add_one_year(self):
current_year = self.year_var.get()
self.year_var.set(current_year + 1)
self.calculate() # Automaticky aktualizovat po změně roku
def calculate(self):
try:
year = self.year_var.get()
except tk.TclError:
messagebox.showerror("Chyba", "Prosím, zadejte platný rok jako celé číslo.")
return
# Získání hodnot z Comboboxů
proleptic_selection = self.proleptic_var.get()
proleptic = 2 if proleptic_selection == "Ano" else 1
julian_mode_selection = self.julian_mode_var.get()
julian_mode = 2 if julian_mode_selection == "Armenian/Non-Chalcedonian" else 1
offset = self.offset_var.get()
try:
# Výpočet Gregoriánských Velikonoc
if year >= 1583 or proleptic:
easter_gregorian = self.gregorian_easter(year)
greg_easter_sunday_str = f"{easter_gregorian.strftime('%d %B')} ({easter_gregorian.strftime('%A')})"
full_moon_greg = self.get_full_moon_gregorian(easter_gregorian)
greg_full_moon_str = f"{full_moon_greg.strftime('%d %B')}"
else:
greg_easter_sunday_str = "N/A"
greg_full_moon_str = "N/A"
# Juliánská Velikonoční neděle
easter_julian = self.julian_easter(year, offset, julian_mode)
julian_easter_sunday_str = f"{easter_julian.strftime('%d %B')} ({easter_julian.strftime('%A')})"
full_moon_julian = easter_julian - datetime.timedelta(days=7) # Přibližný odhad
julian_full_moon_str = f"{full_moon_julian.strftime('%d %B')}"
# Pesach
if hebrew:
pesach_date = self.hebrew_passover(year)
if pesach_date:
pesach_str = f"15 Nisan {pesach_date.year - 3760} AM"
pesach_weekday_str = pesach_date.strftime('%A')
else:
pesach_str = "Chyba"
pesach_weekday_str = "Chyba"
else:
pesach_str = "Knihovna 'convertdate' chybí"
pesach_weekday_str = "Knihovna 'convertdate' chybí"
# Výpočty rozdílů
if year >= 1583 or proleptic:
if 'easter_gregorian' in locals():
diff_jg = (easter_gregorian - easter_julian).days
diff_jg_str = f"{diff_jg} dní"
else:
diff_jg_str = "N/A"
else:
diff_jg_str = "N/A"
if hebrew and 'easter_gregorian' in locals() and 'pesach_date' in locals() and pesach_date:
diff_hg = (easter_gregorian - pesach_date).days
diff_hg_str = f"{diff_hg} dní"
diff_hj = (easter_julian - pesach_date).days
diff_hj_str = f"{diff_hj} dní"
else:
diff_hg_str = "N/A"
diff_hj_str = "N/A"
# Update výstupních polí
output_fields = [
("Number in Solar Cycle:", "13"), # Tento údaj může být dynamicky vypočítán, pokud je potřeba
("Dominical Letter (Juliánské určení):", "FE"),
("Dominical Letter (Gregoriánské určení):", "BA"),
("Golden Number:", "5"),
("Gregorian Epact:", "XV"),
("Martyrology Letter (Juliánské určení):", "e"),
("Martyrology Letter (Gregoriánské určení):", "q"),
("Juliánské kalendářní datum plné Měsíce (luna XIV):", full_moon_julian),
("Juliánská Velikonoční neděle:", julian_easter_sunday_str),
("Gregoriánské kalendářní datum plné Měsíce (luna XIV):", full_moon_greg),
("Gregoriánská Velikonoční neděle:", greg_easter_sunday_str),
("Židovský Pesach (15 Nisan AM):", pesach_str),
("Den v týdnu pro Pesach:", pesach_weekday_str),
("Rozdíl od Gregoriánských po Juliánské Velikonoční neděli:", diff_jg_str),
("Rozdíl od Pesachu po Gregoriánské Velikonoční neděli:", diff_hg_str),
("Rozdíl od Pesachu po Juliánské Velikonoční neděli:", diff_hj_str)
]
# Aktualizace výstupních polí
for label, value in output_fields:
entry = self.entries.get(label)
if entry:
entry.config(state='normal')
entry.delete(0, tk.END)
entry.insert(0, value)
entry.config(state='readonly')
except Exception as e:
messagebox.showerror("Chyba", f"Nastala chyba při výpočtu: {e}")
def save_results(self):
# Sestavení výsledků do textu
lines = ["Velikonoční a Pesach Kalkulačka - Výsledky"]
lines.append(f"Rok (Anno Domini): {self.year_var.get()}")
lines.append(f"Show Gregorian dates before 1583: {self.proleptic_var.get()}")
lines.append(f"Offset mezi Juliánským a Gregoriánským kalendářem (dny): {self.offset_var.get()}")
lines.append(f"Režim Juliánských Velikonoc: {self.julian_mode_var.get()}")
lines.append("\nVýsledky:")
for label, entry in self.entries.items():
value = entry.get()
lines.append(f"{label} {value}")
# Určení cesty k souboru
file_name = f"easter_passover_results_{self.year_var.get()}.txt"
file_path = os.path.join(os.getcwd(), file_name)
try:
with open(file_path, "w", encoding="utf-8") as file:
for line in lines:
file.write(line + "\n")
messagebox.showinfo("Uloženo", f"Výsledky byly uloženy do souboru {file_name}.")
except Exception as e:
messagebox.showerror("Chyba", f"Nastala chyba při ukládání: {e}")
def gregorian_easter(self, year):
"""Výpočet Velikonoční neděle podle gregoriánského kalendáře"""
a = year % 19
b = year // 100
c = year % 100
d = b // 4
e = b % 4
f = (b + 8) // 25
g = (b - f + 1) // 3
h = (19 * a + b - d - g + 15) % 30
i = c // 4
k = c % 4
l = (32 + 2 * e + 2 * i - h - k) % 7
m = (a + 11 * h + 22 * l) // 451
month = (h + l - 7 * m + 114) // 31
day = ((h + l - 7 * m + 114) % 31) + 1
return datetime.date(year, month, day)
def julian_easter(self, year, offset, mode):
"""Výpočet Velikonoční neděle podle Juliánského kalendáře"""
a = year % 4
b = year % 7
c = year % 19
if mode == 1: # Dionysian
d = (19 * c + 15) % 30
else: # Armenian/Non-Chalcedonian
d = (19 * c + 15 + 1) % 30 # Přidání posunu pro jiný režim
e = (2 * a + 4 * b - d + 34) % 7
month = (d + e + 114) // 31
day = ((d + e + 114) % 31) + 1
try:
julian_date = datetime.date(year, month, day)
gregorian_equiv = julian_date + datetime.timedelta(days=offset)
return gregorian_equiv
except ValueError:
return datetime.date(year, month, day)
def get_full_moon_gregorian(self, easter_date):
"""Přibližný výpočet Velikonoční plné měsíce (luna XIV)"""
return easter_date - datetime.timedelta(days=7)
def hebrew_passover(self, year):
"""Výpočet data Pesachu (15. Nisan) v gregoriánském kalendáři"""
heb_year = year + 3760 # Převod AD na hebrejský rok (přibližně)
try:
greg_date = hebrew.to_gregorian(heb_year, 1, 15) # 15 Nisan
return datetime.date(*greg_date)
except Exception as e:
return None
def main():
app = EasterPassoverCalculator()
app.mainloop()
if __name__ == "__main__":
if hebrew is None:
root = tk.Tk()
root.withdraw() # Skrýt hlavní okno
result = messagebox.askyesno("Chybějící knihovna", "Knihovna 'convertdate' není nainstalována. Chcete ji nyní nainstalovat?")
if result:
import subprocess
import sys
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "convertdate"])
messagebox.showinfo("Instalace dokončena", "Knihovna 'convertdate' byla úspěšně nainstalována. Restartujte aplikaci.")
except Exception as e:
messagebox.showerror("Instalace selhala", f"Nastala chyba při instalaci knihovny: {e}")
else:
messagebox.showwarning("Pozor", "Aplikace nebude moci vypočítat datum Pesachu bez knihovny 'convertdate'.")
root.destroy()
else:
main()
kod z webove strany
<form name="eastercalc">
<table align="center" border="1" cols="1" bgcolor="#CCCCCC">
<tbody><tr align="center">
<td><table align="center" border="0" cellspacing="0" cellpadding="5" cols="8">
<caption align="center"><font color="#FF0000"><b>Easter Sunday/Jewish Passover Calculator</b></font></caption>
<tbody><tr align="center">
<td colspan="3" align="center"><small><b>Year (Anno Domini)</b></small></td>
<td align="left" colspan="5"><small><b>Show Gregorian dates before 1583 <select name="proleptic" style="text-align: center;
font-family: arial; font-size: 8pt; font-weight: bold"><option value="1">no</option><option value="2">yes</option></select></b></small></td>
</tr>
<tr align="center">
<td align="right"><img src="./Perpetual Easter Calculator_ Julian_Gregorian Easter Sunday and Jewish Passover_files/buttonminus_off.gif" name="button1" onmouseout="movepic('button1','images/buttonminus_off.gif')" onmouseover="movepic('button1','images/buttonminus_on.gif')" alt="step down the year" onmousedown="subtractoneyear();" height="18" width="24"></td>
<td><input type="text" name="year" size="3" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td align="left"><img src="./Perpetual Easter Calculator_ Julian_Gregorian Easter Sunday and Jewish Passover_files/buttonplus_off.gif" name="button2" onmouseout="movepic('button2','images/buttonplus_off.gif')" onmouseover="movepic('button2','images/buttonplus_on.gif')" alt="step up the year" onmousedown="addoneyear();" height="18" width="24"></td>
<td align="left" colspan="5"><small><b>Offset between Julian and Gregorian calendar <input type="text" name="delc" size="2" style="text-align: center;
font-family: arial; font-size: 8pt; font-weight: bold"> days</b></small></td>
</tr>
<tr>
<td colspan="3"><small><b>Update calculator <img src="./Perpetual Easter Calculator_ Julian_Gregorian Easter Sunday and Jewish Passover_files/cbutton_off.gif" name="button3" onmouseout="movepic('button3','images/cbutton_off.gif')" onmouseover="movepic('button3','images/cbutton_on.gif')" alt="update the calculator" onmousedown="easter_passover();" height="18" width="24"></b></small></td>
<td colspan="5"><small><b>Julian Easter mode <select name="julianmode" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"><option value="1">
Dionysian</option><option value="2">Armenian/Non-Chalcedonian</option></select></b></small></td>
</tr>
<tr>
<td colspan="8"><hr width="100%" size="1"></td>
</tr>
<tr>
<td colspan="3"><small><b>Number in Solar Cycle</b></small></td>
<td><input type="text" name="solarcycle" size="2" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td colspan="4"><small><b> </b></small></td>
</tr>
<tr>
<td colspan="3"><small><b>Dominical Letter</b></small></td>
<td><small><b>Julian reckoning</b></small></td>
<td><input type="text" name="domletj" size="2" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
<td><small><b>Gregorian reckoning</b></small></td>
<td><input type="text" name="domletg" size="2" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
</tr>
<tr>
<td colspan="3"><small><b>Lunar age parameters</b></small></td>
<td><small><b>Golden Number</b></small></td>
<td><input type="text" name="numaur" size="2" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
<td><small><b>Gregorian Epact</b></small></td>
<td><input type="text" name="epact" size="4" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
</tr>
<tr>
<td colspan="3"><small><b>Martyrology letters</b></small></td>
<td><small><b>Julian reckoning</b></small></td>
<td><input type="text" name="litmartyrj" size="2" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
<td><small><b>Gregorian reckoning</b></small></td>
<td><input type="text" name="litmartyrg" size="2" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
</tr>
<tr>
<td colspan="8"><hr width="100%" size="1"></td>
</tr>
<tr>
<td colspan="3"><small><b>Julian reckoning</b></small></td>
<td colspan="2" align="center"><small><b>Julian calendar date</b></small></td>
<td> </td>
<td colspan="2" align="center"><small><b>Gregorian calendar date</b></small></td>
</tr>
<tr align="center">
<td align="left" colspan="3"><small><b>Easter Full Moon (<i>luna XIV</i>)</b></small></td>
<td colspan="2"><input type="text" name="fmdayj" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="fmmonj" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
<td colspan="2"><input type="text" name="fmdayjg" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="fmmonjg" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
</tr>
<tr align="center">
<td align="left" colspan="3"><small><b>Easter Sunday</b></small></td>
<td colspan="2"><input type="text" name="dayj" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="monj" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
<td colspan="2"><input type="text" name="dayjg" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="monjg" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
</tr>
<tr>
<td colspan="8"><hr width="100%" size="1"></td>
</tr>
<tr align="center">
<td colspan="3" align="left"><small><b>Gregorian reckoning</b></small></td>
<td> </td>
<td colspan="3"><small><b>Gregorian calendar date</b></small></td>
<td> </td>
</tr>
<tr align="center">
<td colspan="3" align="left"><small><b>Easter Full Moon (<i>luna XIV</i>)</b></small></td>
<td> </td>
<td colspan="3"><input type="text" name="fmdayg" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="fmmong" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
</tr>
<tr align="center">
<td colspan="3" align="left"><small><b>Easter Sunday</b></small></td>
<td> </td>
<td colspan="3"><input type="text" name="dayg" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="mong" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
<td> </td>
</tr>
<tr>
<td colspan="8"><hr width="100%" size="1"></td>
</tr>
<tr align="center">
<td colspan="3" align="left"><small><b>Jewish Passover Feast</b></small></td>
<td colspan="2" align="left"><small><b>15 Nisan <input type="text" name="amundi" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"> AM</b></small></td>
<td colspan="3"><input type="text" name="weekd" size="8" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="dayh" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold">
<input type="text" name="monh" size="5" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"></td>
</tr>
<tr>
<td colspan="8"><hr width="100%" size="1"></td>
</tr>
<tr align="left">
<td colspan="5"><small><b>From Gregorian until Julian Easter Sunday</b></small></td>
<td colspan="3"><small><b><input type="text" name="deljg" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"> days</b></small></td>
</tr>
<tr align="left">
<td colspan="5"><small><b>From Passover until Gregorian Easter Sunday</b></small></td>
<td colspan="3"><small><b><input type="text" name="delhg" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"> days</b></small></td>
</tr>
<tr align="left">
<td colspan="5"><small><b>From Passover until Julian Easter Sunday</b></small></td>
<td colspan="3"><small><b><input type="text" name="delhj" size="1" style="text-align: center; font-family: arial; font-size: 8pt; font-weight: bold"> days</b></small></td>
</tr>
<tr>
<td colspan="8" align="right"><font size="1" color="#FF0000"><b>© R.H. van Gent (2010)</b></font></td>
</tr>
</tbody></table>
</td>
</tr>
</tbody></table>
</form>
ASSISTANT
Aby vaše Python Tkinter aplikace lépe odpovídala grafickému uspořádání kalkulačky z webové stránky, bude potřeba reorganizovat rozložení widgetů pomocí vícenásobných rámců (`Frame`) a mřížky (`grid`). Níže je upravený skript, který by měl více odpovídat tabulkovému uspořádání z webové stránky.
### Klíčové Změny:
1. **Použití `ttk.Frame` a `tk.Frame`** pro vytvoření strukturovaných sekcí, které napodobují HTML tabulky.
2. **Použití `grid` místo `pack`** pro přesnější umístění widgetů.
3. **Nastavení sloupcových vah (`weight`)** pro lepší přizpůsobení velikostí widgetů.
4. **Úprava velikostí a zarovnání vstupních polí a tlačítek** pro lepší vizuální vzhled.
### Upravený Python Skript:
```python
import tkinter as tk
from tkinter import ttk, messagebox
import datetime
import os
try:
from convertdate import hebrew
except ImportError:
hebrew = None
class EasterPassoverCalculator(tk.Tk):
def __init__(self):
super().__init__()
self.title("Velikonoční a Pesach Kalkulačka")
self.geometry("900x700")
self.configure(bg="lightgrey")
self.resizable(False, False)
self.create_widgets()
self.calculate() # Inicializace s výpočty pro defaultní rok (1600)
def create_widgets(self):
style = ttk.Style(self)
style.theme_use('clam')
style.configure("TLabel", font=("Arial", 10))
style.configure("TEntry", font=("Arial", 10))
style.configure("TButton", font=("Arial", 10, "bold"))
style.configure("TLabelframe.Label", font=("Arial", 12, "bold"))
# Nadpis
header_frame = tk.Frame(self, bg="lightgrey")
header_frame.pack(pady=10)
header_label = tk.Label(header_frame, text="Velikonoční a Pesach Kalkulačka", font=("Arial", 18, "bold"), fg="red", bg="lightgrey")
header_label.pack()
# Vstupní sekce
input_frame = ttk.LabelFrame(self, text="Vstupní údaje", padding="15")
input_frame.pack(fill=tk.X, padx=20, pady=10)
# Vnitřní rámec pro vstupy a tlačítka
inner_input_frame = tk.Frame(input_frame)
inner_input_frame.pack(fill=tk.X, padx=10, pady=10)
# Rok
ttk.Label(inner_input_frame, text="Rok (Anno Domini):").grid(row=0, column=0, sticky=tk.W, pady=5)
self.year_var = tk.IntVar(value=1600)
year_entry = ttk.Entry(inner_input_frame, textvariable=self.year_var, width=10, justify='center', font=("Arial", 10, "bold"))
year_entry.grid(row=0, column=1, pady=5, padx=(0, 5))
# Tlačítka pro zvýšení/snížení roku
btn_minus = ttk.Button(inner_input_frame, text="-", width=3, command=self.subtract_one_year)
btn_minus.grid(row=0, column=2, padx=2)
btn_plus = ttk.Button(inner_input_frame, text="+", width=3, command=self.add_one_year)
btn_plus.grid(row=0, column=3, padx=2)
# Proleptický Gregoriánský kalendář
ttk.Label(inner_input_frame, text="Zobrazit gregoriánská data před rokem 1583:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.proleptic_var = tk.StringVar(value="Ne")
proleptic_combo = ttk.Combobox(inner_input_frame, textvariable=self.proleptic_var, values=["Ne", "Ano"], state="readonly", width=5)
proleptic_combo.grid(row=1, column=1, pady=5, padx=(0, 5))
# Offset mezi Juliánským a Gregoriánským kalendářem
ttk.Label(inner_input_frame, text="Offset mezi Juliánským a Gregoriánským kalendářem (dny):").grid(row=2, column=0, sticky=tk.W, pady=5)
self.offset_var = tk.IntVar(value=10) # Pro rok 1600 byl offset 10 dnů
offset_entry = ttk.Entry(inner_input_frame, textvariable=self.offset_var, width=5, justify='center', font=("Arial", 10, "bold"))
offset_entry.grid(row=2, column=1, pady=5, padx=(0, 5))
# Režim Juliánských Velikonoc
ttk.Label(inner_input_frame, text="Režim Juliánských Velikonoc:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.julian_mode_var = tk.StringVar(value="Dionysian")
julian_combo = ttk.Combobox(inner_input_frame, textvariable=self.julian_mode_var, values=["Dionysian", "Armenian/Non-Chalcedonian"], state="readonly", width=25)
julian_combo.grid(row=3, column=1, pady=5, padx=(0, 5))
# Aktualizační tlačítko
update_btn = ttk.Button(input_frame, text="Aktualizovat kalkulačku", command=self.calculate, width=30)
update_btn.pack(pady=15)
# Výstupní sekce
output_frame = ttk.LabelFrame(self, text="Výsledky", padding="15")
output_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)
# Vnitřní rámec pro výstupy
inner_output_frame = tk.Frame(output_frame)
inner_output_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Definice výstupních polí ve formě tabulky
labels = [
("Number in Solar Cycle:", "13"),
("Dominical Letter (Juliánské určení):", "FE"),
("Dominical Letter (Gregoriánské určení):", "BA"),
("Golden Number:", "5"),
("Gregorian Epact:", "XV"),
("Martyrology Letter (Juliánské určení):", "e"),
("Martyrology Letter (Gregoriánské určení):", "q"),
("Juliánské kalendářní datum plné Měsíce (luna XIV):", "22 March"),
("Juliánská Velikonoční neděle:", "23 March"),
("Gregoriánské kalendářní datum plné Měsíce (luna XIV):", "29 March"),
("Gregoriánská Velikonoční neděle:", "2 April"),
("Židovský Pesach (15 Nisan AM):", "15 Nisan 5360 AM"),
("Den v týdnu pro Pesach:", "Thursday"),
("Rozdíl od Gregoriánských po Juliánské Velikonoční neděli:", "0 days"),
("Rozdíl od Pesachu po Gregoriánské Velikonoční neděli:", "3 days"),
("Rozdíl od Pesachu po Juliánské Velikonoční neděli:", "3 days")
]
self.entries = {}
for idx, (label_text, default_value) in enumerate(labels):
row = idx
col_label = 0
col_entry = 1
ttk.Label(inner_output_frame, text=label_text).grid(row=row, column=col_label, sticky=tk.W, pady=2, padx=5, sticky='e')
entry = ttk.Entry(inner_output_frame, width=50, justify='center', font=("Arial", 10, "bold"))
entry.grid(row=row, column=col_entry, pady=2, padx=5, sticky='w')
entry.insert(0, default_value)
entry.config(state='readonly')
self.entries[label_text] = entry
# Tlačítko pro uložení výsledků
save_btn = ttk.Button(output_frame, text="Uložit výsledky", command=self.save_results, width=20)
save_btn.pack(pady=15)
# Patička
footer_label = tk.Label(self, text="© R.H. van Gent (2010)", fg="red", bg="lightgrey", font=("Arial", 8))
footer_label.pack(pady=10, anchor='e')
def subtract_one_year(self):
current_year = self.year_var.get()
self.year_var.set(current_year - 1)
self.calculate() # Automaticky aktualizovat po změně roku
def add_one_year(self):
current_year = self.year_var.get()
self.year_var.set(current_year + 1)
self.calculate() # Automaticky aktualizovat po změně roku
def calculate(self):
try:
year = self.year_var.get()
except tk.TclError:
messagebox.showerror("Chyba", "Prosím, zadejte platný rok jako celé číslo.")
return
# Získání hodnot z Comboboxů
proleptic_selection = self.proleptic_var.get()
proleptic = 2 if proleptic_selection == "Ano" else 1
julian_mode_selection = self.julian_mode_var.get()
julian_mode = 2 if julian_mode_selection == "Armenian/Non-Chalcedonian" else 1
offset = self.offset_var.get()
try:
# Výpočet Gregoriánských Velikonoc
if year >= 1583 or proleptic:
easter_gregorian = self.gregorian_easter(year)
greg_easter_sunday_str = f"{easter_gregorian.strftime('%d %B')} ({easter_gregorian.strftime('%A')})"
full_moon_greg = self.get_full_moon_gregorian(easter_gregorian)
greg_full_moon_str = f"{full_moon_greg.strftime('%d %B')}"
else:
greg_easter_sunday_str = "N/A"
greg_full_moon_str = "N/A"
# Juliánská Velikonoční neděle
easter_julian = self.julian_easter(year, offset, julian_mode)
julian_easter_sunday_str = f"{easter_julian.strftime('%d %B')} ({easter_julian.strftime('%A')})"
full_moon_julian = easter_julian - datetime.timedelta(days=7) # Přibližný odhad
julian_full_moon_str = f"{full_moon_julian.strftime('%d %B')}"
# Pesach
if hebrew:
pesach_date = self.hebrew_passover(year)
if pesach_date:
pesach_str = f"15 Nisan {pesach_date.year - 3760} AM"
pesach_weekday_str = pesach_date.strftime('%A')
else:
pesach_str = "Chyba"
pesach_weekday_str = "Chyba"
else:
pesach_str = "Knihovna 'convertdate' chybí"
pesach_weekday_str = "Knihovna 'convertdate' chybí"
# Výpočty rozdílů
if year >= 1583 or proleptic:
if 'easter_gregorian' in locals():
diff_jg = (easter_gregorian - easter_julian).days
diff_jg_str = f"{diff_jg} dní"
else:
diff_jg_str = "N/A"
else:
diff_jg_str = "N/A"
if hebrew and 'easter_gregorian' in locals() and 'pesach_date' in locals() and pesach_date:
diff_hg = (easter_gregorian - pesach_date).days
diff_hg_str = f"{diff_hg} dní"
diff_hj = (easter_julian - pesach_date).days
diff_hj_str = f"{diff_hj} dní"
else:
diff_hg_str = "N/A"
diff_hj_str = "N/A"
# Update výstupních polí
output_fields = [
("Number in Solar Cycle:", "13"), # Tento údaj může být dynamicky vypočítán, pokud je potřeba
("Dominical Letter (Juliánské určení):", "FE"),
("Dominical Letter (Gregoriánské určení):", "BA"),
("Golden Number:", "5"),
("Gregorian Epact:", "XV"),
("Martyrology Letter (Juliánské určení):", "e"),
("Martyrology Letter (Gregoriánské určení):", "q"),
("Juliánské kalendářní datum plné Měsíce (luna XIV):", full_moon_julian),
("Juliánská Velikonoční neděle:", julian_easter_sunday_str),
("Gregoriánské kalendářní datum plné Měsíce (luna XIV):", full_moon_greg),
("Gregoriánská Velikonoční neděle:", greg_easter_sunday_str),
("Židovský Pesach (15 Nisan AM):", pesach_str),
("Den v týdnu pro Pesach:", pesach_weekday_str),
("Rozdíl od Gregoriánských po Juliánské Velikonoční neděli:", diff_jg_str),
("Rozdíl od Pesachu po Gregoriánské Velikonoční neděli:", diff_hg_str),
("Rozdíl od Pesachu po Juliánské Velikonoční neděli:", diff_hj_str)
]
# Aktualizace výstupních polí
for label, value in output_fields:
entry = self.entries.get(label)
if entry:
entry.config(state='normal')
entry.delete(0, tk.END)
entry.insert(0, value)
entry.config(state='readonly')
except Exception as e:
messagebox.showerror("Chyba", f"Nastala chyba při výpočtu: {e}")
def save_results(self):
# Sestavení výsledků do textu
lines = ["Velikonoční a Pesach Kalkulačka - Výsledky"]
lines.append(f"Rok (Anno Domini): {self.year_var.get()}")
lines.append(f"Show Gregorian dates before 1583: {self.proleptic_var.get()}")
lines.append(f"Offset mezi Juliánským a Gregoriánským kalendářem (dny): {self.offset_var.get()}")
lines.append(f"Režim Juliánských Velikonoc: {self.julian_mode_var.get()}")
lines.append("\nVýsledky:")
for label, entry in self.entries.items():
value = entry.get()
lines.append(f"{label} {value}")
# Určení cesty k souboru
file_name = f"easter_passover_results_{self.year_var.get()}.txt"
file_path = os.path.join(os.getcwd(), file_name)
try:
with open(file_path, "w", encoding="utf-8") as file:
for line in lines:
file.write(line + "\n")
messagebox.showinfo("Uloženo", f"Výsledky byly uloženy do souboru {file_name}.")
except Exception as e:
messagebox.showerror("Chyba", f"Nastala chyba při ukládání: {e}")
def gregorian_easter(self, year):
"""Výpočet Velikonoční neděle podle gregoriánského kalendáře"""
a = year % 19
b = year // 100
c = year % 100
d = b // 4
e = b % 4
f = (b + 8) // 25
g = (b - f + 1) // 3
h = (19 * a + b - d - g + 15) % 30
i = c // 4
k = c % 4
l = (32 + 2 * e + 2 * i - h - k) % 7
m = (a + 11 * h + 22 * l) // 451
month = (h + l - 7 * m + 114) // 31
day = ((h + l - 7 * m + 114) % 31) + 1
return datetime.date(year, month, day)
def julian_easter(self, year, offset, mode):
"""Výpočet Velikonoční neděle podle Juliánského kalendáře"""
a = year % 4
b = year % 7
c = year % 19
if mode == 1: # Dionysian
d = (19 * c + 15) % 30
else: # Armenian/Non-Chalcedonian
d = (19 * c + 15 + 1) % 30 # Přidání posunu pro jiný režim
e = (2 * a + 4 * b - d + 34) % 7
month = (d + e + 114) // 31
day = ((d + e + 114) % 31) + 1
try:
julian_date = datetime.date(year, month, day)
gregorian_equiv = julian_date + datetime.timedelta(days=offset)
return gregorian_equiv
except ValueError:
return datetime.date(year, month, day)
def get_full_moon_gregorian(self, easter_date):
"""Přibližný výpočet Velikonoční plné měsíce (luna XIV)"""
return easter_date - datetime.timedelta(days=7)
def hebrew_passover(self, year):
"""Výpočet data Pesachu (15. Nisan) v gregoriánském kalendáři"""
heb_year = year + 3760 # Převod AD na hebrejský rok (přibližně)
try:
greg_date = hebrew.to_gregorian(heb_year, 1, 15) # 15 Nisan
return datetime.date(*greg_date)
except Exception as e:
return None
def main():
app = EasterPassoverCalculator()
app.mainloop()
if __name__ == "__main__":
if hebrew is None:
root = tk.Tk()
root.withdraw() # Skrýt hlavní okno
result = messagebox.askyesno("Chybějící knihovna", "Knihovna 'convertdate' není nainstalována. Chcete ji nyní nainstalovat?")
if result:
import subprocess
import sys
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "convertdate"])
messagebox.showinfo("Instalace dokončena", "Knihovna 'convertdate' byla úspěšně nainstalována. Restartujte aplikaci.")
except Exception as e:
messagebox.showerror("Instalace selhala", f"Nastala chyba při instalaci knihovny: {e}")
else:
messagebox.showwarning("Pozor", "Aplikace nebude moci vypočítat datum Pesachu bez knihovny 'convertdate'.")
root.destroy()
else:
main()
```
### Vysvětlení Změn:
1. **Vstupní Sekce (`input_frame`):**
- Přidali jsme vnitřní rámec `inner_input_frame` s mřížkou, která umožňuje přesné umístění jednotlivých prvků, jako jsou štítky, vstupní pole a tlačítka pro zvýšení/snížení roku.
- Využití `grid` v kombinaci s promyšleným umístěním prvků napodobuje tabulkové umístění z webové stránky.
2. **Výstupní Sekce (`output_frame`):**
- Přidali jsme `inner_output_frame` s mřížkou pro organizaci výstupních polí do dvou sloupců (štítky a jejich odpovídající hodnoty).
- Každý výstupní štítek a pole jsou umístěny do příslušného řádku, což zajišťuje přehledné a tabulkové zobrazení výsledků.
3. **Tlačítka a Pole:**
- Přizpůsobili jsme velikosti a zarovnání vstupních polí a tlačítek, aby lépe odpovídaly stylu z webové stránky.
- Použili jsme zarovnání na východ (`sticky='e'`) pro štítky a západ (`sticky='w'`) pro vstupní pole, aby se zajistilo správné zarovnání v rámci mřížky.
4. **Responzivita a Velikost:**
- Nastavili jsme pevnou velikost okna (`geometry("900x700")`) a zakázali změnu velikosti (`self.resizable(False, False)`), aby rozhraní zůstalo konzistentní s původním designem.
- Přidali jsme odsazení (`padx` a `pady`) pro lepší rozložení a čitelnost.
### Další Doporučení:
- **Dynamické Výpočty:**
- Některé hodnoty, jako např. "Number in Solar Cycle", mohou být vypočítány dynamicky místo statického nastavení. To by mohlo zvyšovat uživatelskou přívětivost a přesnost výsledků.
- **Validace Vstupů:**
- Přidání více validací pro vstupní pole může zabránit chybám a zajistit, že uživatel zadává platné hodnoty.
- **Vylepšení Stylu:**
- Pro ještě lepší vizuální podobnost s webovou stránkou můžete přidat další styly, například barevné rozlišení sekcí nebo přizpůsobení velikostí písma.
Doufám, že tyto úpravy pomohou vaší aplikaci dosáhnout požadovaného vzhledu a funkčnosti. Pokud budete potřebovat další pomoc nebo úpravy, neváhejte se zeptat!