math_programs_gui.py`
این نسخه را کاملتر کردم: همه `Program 1` تا `Program 15` را در یک رابط فارسی آوردم، دکمه `ذخیره نمودار` اضافه شد، چیدمان مرتبتر شد، و کد طوری نوشته شده که مستقیم بتوانید با `PyInstaller` از آن `exe` بسازید. برای `Program 12` هم از همان فرم تحلیلی قبلی یعنی `ln((ax+b)/(cx+d))` استفاده کردم.
فایل پیشنهادی: `math_programs_gui.py`
```python
import math
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class MathProgramsApp:
def __init__(self, root):
self.root = root
self.root.title("نرم افزار برنامه هاي رياضي 1 تا 15")
self.root.geometry("1100x720")
self.root.minsize(980, 620)
self.current_figure = None
self.entries = {}
self.program_var = tk.StringVar()
self.program_fields = {
"Program 1 - مارپيچ استوانه اي": ["a", "t_max", "step"],
"Program 2 - تصوير کره": ["a", "step"],
"Program 3 - انتگرال مستطيلي": ["a", "b", "n"],
"Program 4 - انتگرال سيمپسون": ["a", "b", "n"],
"Program 5 - sinc(x)": ["xmin", "xmax", "step"],
"Program 6 - چندجمله اي": ["coeffs", "xmin", "xmax", "step"],
"Program 7 - x و sin(x) و x sin(x)": ["xmin", "xmax", "step"],
"Program 8 - a sin(x) + b cos(x)": ["a", "b", "xmin", "xmax", "step"],
"Program 9 - tan(ax+b)/(cx+d)": ["a", "b", "c", "d", "xmin", "xmax", "step"],
"Program 10 - ln((ax+b)/(cx+d))": ["a", "b", "c", "d", "xmin", "xmax", "step"],
"Program 11 - چندجمله اي پيشرفته": ["coeffs", "xmin", "xmax", "step"],
"Program 12 - لگاريتم کسري": ["a", "b", "c", "d", "xmin", "xmax", "step"],
"Program 13 - atan(ax^3+bx^2+cx+d)": ["a", "b", "c", "d", "xmin", "xmax", "step"],
"Program 14 - tan((ax+b)/(cx+d))": ["a", "b", "c", "d", "xmin", "xmax", "step"],
"Program 15 - atan((ax-b)/(cx+d))": ["a", "b", "c", "d", "xmin", "xmax", "step"],
}
self.defaults = {
"a": "1",
"b": "1",
"c": "1",
"d": "1",
"n": "100",
"step": "0.05",
"xmin": "-10",
"xmax": "10",
"t_max": "6.283185307179586",
"coeffs": "1,-3,2",
}
self.build_ui()
self.update_fields()
def build_ui(self):
self.root.columnconfigure(0, weight=0)
self.root.columnconfigure(1, weight=1)
self.root.rowconfigure(0, weight=1)
left = ttk.Frame(self.root, padding=12)
left.grid(row=0, column=0, sticky="ns")
left.columnconfigure(0, weight=1)
right = ttk.Frame(self.root, padding=12)
right.grid(row=0, column=1, sticky="nsew")
right.rowconfigure(1, weight=1)
right.columnconfigure(0, weight=1)
title = ttk.Label(left, text="برنامه هاي رياضي 1 تا 15", font=("Tahoma", 14, "bold"))
title.grid(row=0, column=0, sticky="ew", pady=(0, 10))
ttk.Label(left, text="انتخاب برنامه:", font=("Tahoma", 10, "bold")).grid(
row=1, column=0, sticky="w", pady=(0, 4)
)
combo = ttk.Combobox(
left,
textvariable=self.program_var,
values=list(self.program_fields.keys()),
state="readonly",
width=34,
justify="right",
)
combo.grid(row=2, column=0, sticky="ew", pady=(0, 10))
combo.bind("<>", self.update_fields)
self.program_var.set(list(self.program_fields.keys())[0])
self.fields_frame = ttk.LabelFrame(left, text="ورودي ها", padding=10)
self.fields_frame.grid(row=3, column=0, sticky="new", pady=(0, 10))
self.fields_frame.columnconfigure(1, weight=1)
btns = ttk.Frame(left)
btns.grid(row=4, column=0, sticky="ew", pady=(0, 10))
btns.columnconfigure(0, weight=1)
btns.columnconfigure(1, weight=1)
ttk.Button(btns, text="رسم / اجرا", command=self.run_program).grid(
row=0, column=0, sticky="ew", padx=(0, 4)
)
ttk.Button(btns, text="ذخيره نمودار", command=self.save_plot).grid(
row=0, column=1, sticky="ew", padx=(4, 0)
)
bottom_btns = ttk.Frame(left)
bottom_btns.grid(row=5, column=0, sticky="ew", pady=(0, 10))
bottom_btns.columnconfigure(0, weight=1)
bottom_btns.columnconfigure(1, weight=1)
ttk.Button(bottom_btns, text="پاک کردن نتيجه", command=self.clear_result).grid(
row=0, column=0, sticky="ew", padx=(0, 4)
)
ttk.Button(bottom_btns, text="خروج", command=self.root.quit).grid(
row=0, column=1, sticky="ew", padx=(4, 0)
)
help_text = (
"راهنما:\n"
"- coeffs را با ويرگول وارد کنيد. مثال: 1,-3,2\n"
"- براي سيمپسون، n بايد زوج باشد.\n"
"- براي ذخيره نمودار، ابتدا يک نمودار رسم کنيد."
)
ttk.Label(left, text=help_text, justify="right").grid(row=6, column=0, sticky="ew")
ttk.Label(right, text="نمايش نمودار", font=("Tahoma", 12, "bold")).grid(
row=0, column=0, sticky="w", pady=(0, 8)
)
self.plot_frame = ttk.Frame(right)
self.plot_frame.grid(row=1, column=0, sticky="nsew")
self.result_frame = ttk.LabelFrame(right, text="نتيجه", padding=10)
self.result_frame.grid(row=2, column=0, sticky="ew", pady=(10, 0))
self.result_var = tk.StringVar(value="آماده")
ttk.Label(self.result_frame, textvariable=self.result_var, justify="right").pack(fill="x")
def update_fields(self, event=None):
for widget in self.fields_frame.winfo_children():
widget.destroy()
self.entries.clear()
fields = self.program_fields[self.program_var.get()]
for i, field in enumerate(fields):
ttk.Label(self.fields_frame, text=f"{field} :").grid(
row=i, column=0, sticky="e", padx=(0, 8), pady=4
)
entry = ttk.Entry(self.fields_frame, justify="right", width=28)
entry.grid(row=i, column=1, sticky="ew", pady=4)
entry.insert(0, self.defaults.get(field, ""))
self.entries[field] = entry
def clear_result(self):
self.result_var.set("آماده")
def get_float(self, name):
return float(self.entries[name].get().strip())
def get_int(self, name):
return int(self.entries[name].get().strip())
def parse_coeffs(self):
text = self.entries["coeffs"].get().strip()
if not text:
raise ValueError("فهرست coeffs خالي است.")
return [float(part.strip()) for part in text.split(",")]
def make_figure(self, title):
fig = plt.Figure(figsize=(7.2, 4.8), dpi=100)
ax = fig.add_subplot(111)
ax.set_title(title)
ax.axhline(0, color="black", linewidth=0.8)
ax.axvline(0, color="black", linewidth=0.8)
ax.grid(True, linestyle="--", alpha=0.35)
return fig, ax
def show_figure(self, fig):
for widget in self.plot_frame.winfo_children():
widget.destroy()
canvas = FigureCanvasTkAgg(fig, master=self.plot_frame)
canvas.draw()
canvas.get_tk_widget().pack(fill="both", expand=True)
toolbar_frame = ttk.Frame(self.plot_frame)
toolbar_frame.pack(fill="x")
self.current_figure = fig
def save_plot(self):
if self.current_figure is None:
messagebox.showwarning("هشدار", "ابتدا يک نمودار رسم کنيد.")
return
file_path = filedialog.asksaveasfilename(
title="ذخيره نمودار",
defaultextension=".png",
filetypes=[
("PNG Image", "*.png"),
("JPEG Image", "*.jpg"),
("PDF File", "*.pdf"),
("SVG File", "*.svg"),
],
)
if not file_path:
return
self.current_figure.savefig(file_path, bbox_inches="tight")
self.result_var.set(f"نمودار ذخيره شد: {file_path}")
def safe_divide(self, num, den):
if abs(den) < 1e-10:
return np.nan
return num / den
def run_program(self):
try:
name = self.program_var.get()
if name == "Program 1 - مارپيچ استوانه اي":
self.program_1()
elif name == "Program 2 - تصوير کره":
self.program_2()
elif name == "Program 3 - انتگرال مستطيلي":
value = self.program_3()
self.result_var.set(f"مقدار انتگرال مستطيلي = {value}")
elif name == "Program 4 - انتگرال سيمپسون":
value = self.program_4()
self.result_var.set(f"مقدار انتگرال سيمپسون = {value}")
elif name == "Program 5 - sinc(x)":
self.program_5()
elif name == "Program 6 - چندجمله اي":
self.program_6()
elif name == "Program 7 - x و sin(x) و x sin(x)":
self.program_7()
elif name == "Program 8 - a sin(x) + b cos(x)":
self.program_8()
elif name == "Program 9 - tan(ax+b)/(cx+d)":
self.program_9()
elif name == "Program 10 - ln((ax+b)/(cx+d))":
self.program_10()
elif name == "Program 11 - چندجمله اي پيشرفته":
self.program_11()
elif name == "Program 12 - لگاريتم کسري":
self.program_12()
elif name == "Program 13 - atan(ax^3+bx^2+cx+d)":
self.program_13()
elif name == "Program 14 - tan((ax+b)/(cx+d))":
self.program_14()
elif name == "Program 15 - atan((ax-b)/(cx+d))":
self.program_15()
except Exception as exc:
messagebox.showerror("خطا", str(exc))
def program_1(self):
a = self.get_float("a")
t_max = self.get_float("t_max")
step = self.get_float("step")
t = np.arange(0, t_max + step, step)
x = a * np.cos(t)
y = a * np.sin(t)
fig, ax = self.make_figure("Program 1 - مارپيچ استوانه اي")
ax.plot(x, y, color="blue")
ax.set_aspect("equal", adjustable="box")
ax.set_xlim(-abs(a) - 1, abs(a) + 1)
ax.set_ylim(-abs(a) - 1, abs(a) + 1)
self.show_figure(fig)
self.result_var.set("تصوير دو بعدي مسير استوانه اي رسم شد.")
def program_2(self):
a = self.get_float("a")
step = self.get_float("step")
phi = np.arange(0, math.pi + step, step)
theta = np.arange(0, 2 * math.pi + step, step)
xs = []
ys = []
for p in phi:
for t in theta:
xs.append(a * math.sin(p) * math.cos(t))
ys.append(a * math.sin(p) * math.sin(t))
fig, ax = self.make_figure("Program 2 - تصوير کره")
ax.scatter(xs, ys, s=4, color="darkgreen")
ax.set_aspect("equal", adjustable="box")
ax.set_xlim(-abs(a) - 1, abs(a) + 1)
ax.set_ylim(-abs(a) - 1, abs(a) + 1)
self.show_figure(fig)
self.result_var.set("تصوير کره رسم شد.")
def program_3(self):
a = self.get_float("a")
b = self.get_float("b")
n = self.get_int("n")
if n <= 0:
raise ValueError("n بايد بزرگ تر از صفر باشد.")
def f(x):
return x * math.sin(x)
h = (b - a) / n
s = 0.0
for i in range(n):
x = a + i * h
s += f(x)
return s * h
def program_4(self):
a = self.get_float("a")
b = self.get_float("b")
n = self.get_int("n")
if n <= 0 or n % 2 != 0:
raise ValueError("در روش سيمپسون، n بايد مثبت و زوج باشد.")
def f(x):
return 1 / (1 + x ** 2)
h = (b - a) / n
s1 = sum(f(a + i * h) for i in range(1, n, 2))
s2 = sum(f(a + i * h) for i in range(2, n, 2))
return (h / 3) * (f(a) + f(b) + 4 * s1 + 2 * s2)
def program_5(self):
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = np.where(np.abs(x) < 1e-10, 1.0, np.sin(x) / x)
fig, ax = self.make_figure("Program 5 - sinc(x)")
ax.plot(x, y, color="purple")
ax.set_xlim(xmin, xmax)
ax.set_ylim(-0.5, 1.2)
self.show_figure(fig)
self.result_var.set("تابع sinc(x) رسم شد.")
def program_6(self):
coeffs = self.parse_coeffs()
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = np.zeros_like(x, dtype=float)
for j, coeff in enumerate(coeffs):
y += coeff * x ** j
fig, ax = self.make_figure("Program 6 - چندجمله اي")
ax.plot(x, y, color="brown")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("نمودار چندجمله اي رسم شد.")
def program_7(self):
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y1 = x
y2 = np.sin(x)
y3 = y1 * y2
fig, ax = self.make_figure("Program 7 - x و sin(x) و x sin(x)")
ax.plot(x, y1, label="f(x)=x")
ax.plot(x, y2, label="g(x)=sin(x)")
ax.plot(x, y3, label="h(x)=x sin(x)")
ax.set_xlim(xmin, xmax)
ax.legend()
self.show_figure(fig)
self.result_var.set("سه تابع هم زمان رسم شدند.")
def program_8(self):
a = self.get_float("a")
b = self.get_float("b")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = a * np.sin(x) + b * np.cos(x)
fig, ax = self.make_figure("Program 8 - a sin(x) + b cos(x)")
ax.plot(x, y, color="teal")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("تابع a sin(x) + b cos(x) رسم شد.")
def program_9(self):
a = self.get_float("a")
b = self.get_float("b")
c = self.get_float("c")
d = self.get_float("d")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = []
for xv in x:
den = c * xv + d
ang = a * xv + b
if abs(den) < 1e-10 or abs(math.cos(ang)) < 1e-10:
y.append(np.nan)
else:
y.append(math.tan(ang) / den)
fig, ax = self.make_figure("Program 9 - tan(ax+b)/(cx+d)")
ax.plot(x, y, color="red")
ax.set_xlim(xmin, xmax)
ax.set_ylim(-10, 10)
self.show_figure(fig)
self.result_var.set("تابع کسري تانژانت رسم شد.")
def program_10(self):
a = self.get_float("a")
b = self.get_float("b")
c = self.get_float("c")
d = self.get_float("d")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = []
for xv in x:
den = c * xv + d
if abs(den) < 1e-10:
y.append(np.nan)
continue
z = (a * xv + b) / den
if z <= 0:
y.append(np.nan)
else:
y.append(math.log(z))
fig, ax = self.make_figure("Program 10 - ln((ax+b)/(cx+d))")
ax.plot(x, y, color="orange")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("تابع لگاريتمي کسري رسم شد.")
def program_11(self):
coeffs = self.parse_coeffs()
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = np.zeros_like(x, dtype=float)
for j, coeff in enumerate(coeffs):
y += coeff * x ** j
fig, ax = self.make_figure("Program 11 - چندجمله اي پيشرفته")
ax.plot(x, y, color="navy")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("چندجمله اي برنامه 11 رسم شد.")
def program_12(self):
a = self.get_float("a")
b = self.get_float("b")
c = self.get_float("c")
d = self.get_float("d")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = []
for xv in x:
den = c * xv + d
if abs(den) < 1e-10:
y.append(np.nan)
continue
z = (a * xv + b) / den
if z <= 0:
y.append(np.nan)
else:
y.append(math.log(z))
fig, ax = self.make_figure("Program 12 - لگاريتم کسري")
ax.plot(x, y, color="darkorange")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("برنامه 12 رسم شد.")
def program_13(self):
a = self.get_float("a")
b = self.get_float("b")
c = self.get_float("c")
d = self.get_float("d")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = np.arctan(a * x ** 3 + b * x ** 2 + c * x + d)
fig, ax = self.make_figure("Program 13 - atan(ax^3+bx^2+cx+d)")
ax.plot(x, y, color="magenta")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("تابع آرکتان چندجمله اي رسم شد.")
def program_14(self):
a = self.get_float("a")
b = self.get_float("b")
c = self.get_float("c")
d = self.get_float("d")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = []
for xv in x:
den = c * xv + d
if abs(den) < 1e-10:
y.append(np.nan)
continue
u = (a * xv + b) / den
if abs(math.cos(u)) < 1e-10:
y.append(np.nan)
else:
y.append(math.tan(u))
fig, ax = self.make_figure("Program 14 - tan((ax+b)/(cx+d))")
ax.plot(x, y, color="darkred")
ax.set_xlim(xmin, xmax)
ax.set_ylim(-10, 10)
self.show_figure(fig)
self.result_var.set("تانژانت کسر خطي رسم شد.")
def program_15(self):
a = self.get_float("a")
b = self.get_float("b")
c = self.get_float("c")
d = self.get_float("d")
xmin = self.get_float("xmin")
xmax = self.get_float("xmax")
step = self.get_float("step")
x = np.arange(xmin, xmax + step, step)
y = []
for xv in x:
den = c * xv + d
if abs(den) < 1e-10:
y.append(np.nan)
else:
y.append(math.atan((a * xv - b) / den))
fig, ax = self.make_figure("Program 15 - atan((ax-b)/(cx+d))")
ax.plot(x, y, color="darkblue")
ax.set_xlim(xmin, xmax)
self.show_figure(fig)
self.result_var.set("آرکتان کسر خطي رسم شد.")
def main():
root = tk.Tk()
style = ttk.Style()
try:
style.theme_use("clam")
except tk.TclError:
pass
app = MathProgramsApp(root)
root.mainloop()
if __name__ == "__main__":
main()
```
برای اجرا:
```bash
pip install numpy matplotlib
python math_programs_gui.py
```
برای ساخت فایل `exe`:
```bash
pip install pyinstaller
pyinstaller --onefile --windowed math_programs_gui.py
```
اگر خواستید آیکون هم داشته باشد:
```bash
pyinstaller --onefile --windowed --icon=app.ico math_programs_gui.py
```
نکتههای مهم:
- فایل نهایی داخل پوشه `dist` ساخته میشود.
- چون برنامه `tkinter` و `matplotlib` دارد، `--windowed` بهتر است تا پنجره کنسول باز نشود.
- اگر فونت فارسی روی بعضی سیستمها خوب نبود، میشود فونت رابط را روی `B Nazanin` یا `Vazirmatn` تنظیم کرد.
اگر بخواهی، قدم بعدی طبیعی اینهاست:
1. نسخه را به چند تب جداگانه تقسیم کنم: `رسم توابع`، `انتگرالگیری`، `توابع کسری`
2. دکمه `ذخيره PDF` و `چاپ` هم اضافه کنم
3. برای هر برنامه توضیح فرمول و نمونه ورودی فارسی داخل خود نرمافزار بگذارم
4. فایل `spec` آماده `PyInstaller` هم بدهم تا ساخت `exe` راحتتر و پایدارتر شود