Konten Sub Menu "Kebutuhan Kalori Harian"
Isi Menu "Profil Kesehatan"
(Konten Sub Menu "Kebutuhan Kalori Harian")
5. Sub Menu “Kebutuhan Kalori Harian”
Lanjut kita membuat konten Sub Menu "Kebutuhan Kalori Harian"
Baik, kita akan membuat Sub Menu "Kebutuhan Kalori Harian" yang:
- Menghitung kebutuhan kalori harian berdasarkan data dari database
data_diri.db(usia, tinggi, berat, jenis kelamin). - Menyediakan input manual jika data di database kosong atau pengguna ingin menghitung ulang.
- Menampilkan hasil perhitungan dan penjelasannya.
📌 Rumus yang akan kita pakai
Kita bisa pakai Harris-Benedict Equation:
BMR (Basal Metabolic Rate)
- Laki-laki:
BMR = 88.362 + (13.397 × berat) + (4.799 × tinggi) − (5.677 × usia) - Perempuan:
BMR = 447.593 + (9.247 × berat) + (3.098 × tinggi) − (4.330 × usia)
Kalori Harian = BMR × Faktor Aktivitas
- Sedentary (jarang bergerak): × 1.2
- Light (aktivitas ringan): × 1.375
- Moderate (aktivitas sedang): × 1.55
- Active (aktivitas berat): × 1.725
- Very Active (sangat berat): × 1.9
📂 File: sub_menu_kebutuhan_kalori.py
import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
import os
DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"
def ambil_data_diri():
if not os.path.exists(DATABASE_PATH):
return None
conn = sqlite3.connect(DATABASE_PATH)
c = conn.cursor()
c.execute("SELECT nama, usia, tinggi_badan, berat_badan, jenis_kelamin FROM data_diri ORDER BY id DESC LIMIT 1")
data = c.fetchone()
conn.close()
return data
def hitung_kalori(usia, tinggi, berat, gender, aktivitas):
if gender.lower() == "laki-laki":
bmr = 88.362 + (13.397 * berat) + (4.799 * tinggi) - (5.677 * usia)
else:
bmr = 447.593 + (9.247 * berat) + (3.098 * tinggi) - (4.330 * usia)
faktor_aktivitas = {
"Sedentary": 1.2,
"Light": 1.375,
"Moderate": 1.55,
"Active": 1.725,
"Very Active": 1.9
}
return round(bmr * faktor_aktivitas[aktivitas], 2)
def show_sub_menu_kebutuhan_kalori(root_frame):
from menu_profil_kesehatan import show_menu_profil_kesehatan
for widget in root_frame.winfo_children():
widget.destroy()
tk.Label(root_frame, text="Kebutuhan Kalori Harian", font=("Arial", 18, "bold"),
bg="green", fg="orange", pady=10).pack(pady=20)
form_frame = tk.Frame(root_frame)
form_frame.pack(pady=10)
# ===== Form Input =====
tk.Label(form_frame, text="Usia:", font=("Arial", 12)).grid(row=0, column=0, sticky="w", pady=5)
entry_usia = tk.Entry(form_frame, width=10)
entry_usia.grid(row=0, column=1, pady=5)
tk.Label(form_frame, text="Tinggi Badan (cm):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", pady=5)
entry_tinggi = tk.Entry(form_frame, width=10)
entry_tinggi.grid(row=1, column=1, pady=5)
tk.Label(form_frame, text="Berat Badan (kg):", font=("Arial", 12)).grid(row=2, column=0, sticky="w", pady=5)
entry_berat = tk.Entry(form_frame, width=10)
entry_berat.grid(row=2, column=1, pady=5)
tk.Label(form_frame, text="Jenis Kelamin:", font=("Arial", 12)).grid(row=3, column=0, sticky="w", pady=5)
gender_var = tk.StringVar()
gender_combo = ttk.Combobox(form_frame, textvariable=gender_var, values=["Laki-laki", "Perempuan"], state="readonly")
gender_combo.grid(row=3, column=1, pady=5)
tk.Label(form_frame, text="Aktivitas:", font=("Arial", 12)).grid(row=4, column=0, sticky="w", pady=5)
aktivitas_var = tk.StringVar()
aktivitas_combo = ttk.Combobox(form_frame, textvariable=aktivitas_var,
values=["Sedentary", "Light", "Moderate", "Active", "Very Active"],
state="readonly")
aktivitas_combo.grid(row=4, column=1, pady=5)
# ===== Hasil =====
label_hasil = tk.Label(root_frame, text="", font=("Arial", 12), fg="blue", justify="left")
label_hasil.pack(pady=10)
# ===== Fungsi Hitung =====
def proses_hitung():
try:
usia = int(entry_usia.get())
tinggi = float(entry_tinggi.get())
berat = float(entry_berat.get())
gender = gender_var.get()
aktivitas = aktivitas_var.get()
if not gender or not aktivitas:
messagebox.showwarning("Validasi", "Pilih jenis kelamin dan aktivitas!")
return
kalori = hitung_kalori(usia, tinggi, berat, gender, aktivitas)
label_hasil.config(
text=f"Usia: {usia} tahun\nTinggi: {tinggi} cm\nBerat: {berat} kg\n"
f"Jenis Kelamin: {gender}\nAktivitas: {aktivitas}\n\n"
f"Kebutuhan Kalori Harian: {kalori} kkal"
)
except ValueError:
messagebox.showerror("Error", "Usia, tinggi, dan berat harus angka!")
# ===== Tombol =====
tk.Button(root_frame, text="Hitung Kalori", font=("Arial", 12), bg="#4CAF50", fg="white",
command=proses_hitung).pack(pady=10)
# ===== Ambil Data dari DB =====
data_db = ambil_data_diri()
if data_db:
nama, usia, tinggi, berat, gender = data_db
entry_usia.insert(0, usia)
entry_tinggi.insert(0, tinggi)
entry_berat.insert(0, berat)
gender_var.set(gender)
# Tombol kembali
tk.Button(root_frame, text="Kembali", font=("Arial", 12), bg="gray", fg="white",
command=lambda: show_menu_profil_kesehatan(root_frame)).pack(pady=20)
Kalau mau, aku bisa langsung buatkan juga tombol sub menu "Kebutuhan Kalori Harian" di menu_profil_kesehatan.py biar langsung terhubung.
Mau aku buatkan sekalian?
Bagaimana dengan perobahan kode pada file menu_profil_kesehatan.py
Kalau kita mau menambahkan Sub Menu "Kebutuhan Kalori Harian" ke file menu_profil_kesehatan.py, berarti kita cukup:
- Import fungsi
show_sub_menu_kebutuhan_kaloridi atas. - Tambah tombolnya ke daftar sub menu.
Karena sebelumnya kamu ingin kode tombol sub menu lebih ringkas dan mudah ditambah, kita bisa sekalian pakai list tombol supaya nambah menu tinggal tambah satu baris saja.
📂 menu_profil_kesehatan.py (versi ringkas & bisa tambah tombol mudah)
# Menu Profil Kesehatan
import tkinter as tk
from sub_menu_data_diri import show_sub_menu_data_diri
from sub_menu_berat_tinggi_badan import show_sub_menu_berat_tinggi_badan
from sub_menu_indeks_massa_tubuh import show_sub_menu_indeks_massa_tubuh
from sub_menu_riwayat_kesehatan import show_sub_menu_riwayat_kesehatan
from sub_menu_kebutuhan_kalori import show_sub_menu_kebutuhan_kalori # ⬅ import baru
def show_menu_profil_kesehatan(root_frame):
from menu_utama import tampilkan_halaman_utama # Hindari circular import
for widget in root_frame.winfo_children():
widget.destroy()
# Judul
tk.Label(
root_frame,
text="Profil Kesehatan",
font=("Arial", 18, "bold"),
bg="green",
fg="orange",
pady=10
).pack(pady=20)
# ===== Daftar Sub Menu =====
sub_menus = [
("Data Diri", show_sub_menu_data_diri),
("Berat & Tinggi Badan", show_sub_menu_berat_tinggi_badan),
("Indeks Massa Tubuh (IMT)", show_sub_menu_indeks_massa_tubuh),
("Riwayat Kesehatan", show_sub_menu_riwayat_kesehatan),
("Kebutuhan Kalori Harian", show_sub_menu_kebutuhan_kalori), # ⬅ menu baru
]
# ===== Buat tombol secara otomatis =====
for i, (text, command) in enumerate(sub_menus):
tk.Button(
root_frame,
text=text,
font=("Arial", 12),
bg="light blue",
fg="black",
command=lambda cmd=command: cmd(root_frame)
).pack(pady=5)
# Tambahkan separator kecuali tombol terakhir
if i < len(sub_menus) - 1:
tk.Frame(root_frame, height=2, bg="gray").pack(fill="x", padx=40, pady=3)
# Tombol kembali
tk.Button(
root_frame,
text="Kembali ke Menu Utama",
font=("Arial", 12),
bg="gray",
fg="white",
command=lambda: tampilkan_halaman_utama(root_frame)
).pack(pady=30)
✅ Keuntungan cara ini
- Lebih ringkas → tambah menu baru cukup tambah satu baris di
sub_menus. - Ada separator otomatis di antara tombol.
- Tidak perlu ulang-ulang
tk.Button(...)untuk setiap menu.
Kalau mau, aku bisa lanjut bikin scroll frame di menu_profil_kesehatan.py ini juga, supaya kalau menunya makin banyak tetap bisa digulir.
Itu cocok kalau nanti menunya bisa lebih dari 8-10 tombol.
Bjatkan tombol "kembali" di dalam file "sub_menu_kebutuhan_kalori.py"
Baik, kalau kita buat tombol "Kembali" di dalam sub_menu_kebutuhan_kalori.py, formatnya mirip dengan sub menu lain yang sudah kita buat.
Saya tuliskan contoh struktur file sub_menu_kebutuhan_kalori.py lengkap dengan tombol kembali:
📂 sub_menu_kebutuhan_kalori.py
import tkinter as tk
from tkinter import messagebox
def show_sub_menu_kebutuhan_kalori(root_frame):
from menu_profil_kesehatan import show_menu_profil_kesehatan # Hindari circular import
# Bersihkan frame
for widget in root_frame.winfo_children():
widget.destroy()
# Judul
tk.Label(
root_frame,
text="Kebutuhan Kalori Harian",
font=("Arial", 18, "bold"),
bg="green",
fg="orange",
pady=10
).pack(pady=20)
# Form input sederhana
tk.Label(root_frame, text="Berat Badan (kg):", font=("Arial", 12)).pack()
berat_entry = tk.Entry(root_frame, font=("Arial", 12))
berat_entry.pack(pady=5)
tk.Label(root_frame, text="Tinggi Badan (cm):", font=("Arial", 12)).pack()
tinggi_entry = tk.Entry(root_frame, font=("Arial", 12))
tinggi_entry.pack(pady=5)
tk.Label(root_frame, text="Usia (tahun):", font=("Arial", 12)).pack()
usia_entry = tk.Entry(root_frame, font=("Arial", 12))
usia_entry.pack(pady=5)
tk.Label(root_frame, text="Jenis Kelamin (L/P):", font=("Arial", 12)).pack()
gender_entry = tk.Entry(root_frame, font=("Arial", 12))
gender_entry.pack(pady=5)
# Fungsi hitung kalori (rumus Harris-Benedict)
def hitung_kalori():
try:
berat = float(berat_entry.get())
tinggi = float(tinggi_entry.get())
usia = int(usia_entry.get())
gender = gender_entry.get().strip().upper()
if gender == "L": # Laki-laki
bmr = 88.362 + (13.397 * berat) + (4.799 * tinggi) - (5.677 * usia)
elif gender == "P": # Perempuan
bmr = 447.593 + (9.247 * berat) + (3.098 * tinggi) - (4.330 * usia)
else:
messagebox.showwarning("Validasi", "Masukkan jenis kelamin L atau P.")
return
messagebox.showinfo("Hasil", f"Kebutuhan Kalori Harian: {bmr:.2f} kkal")
except ValueError:
messagebox.showwarning("Validasi", "Pastikan semua input angka valid.")
# Tombol hitung
tk.Button(
root_frame,
text="Hitung Kalori",
font=("Arial", 12),
bg="#4CAF50",
fg="white",
command=hitung_kalori
).pack(pady=10)
# Tombol kembali
tk.Button(
root_frame,
text="Kembali",
font=("Arial", 12),
bg="gray",
fg="white",
command=lambda: show_menu_profil_kesehatan(root_frame)
).pack(pady=20)
Kalau kamu mau, kita juga bisa bikin perhitungan otomatis langsung dari data di data_diri.db seperti di sub menu IMT, sehingga pengguna tidak perlu mengetik ulang berat, tinggi, dan usia.
Mau saya buatkan versi itu sekalian?
Itu akan terasa lebih praktis dan konsisten.
Buatkan kotak entry berada di samping label text, dan ketika data diinput ke entry dan ditekan tombol 'Hitung Kalori" maka hasil akan tampil di dalam frame (layar) (bukan di kotak pesan), dan teks di dalam kotak entry harua sudah bersih
Oke, berarti kita akan buat layout entry sejajar (horizontal) dengan label teksnya, lalu hasil perhitungan langsung muncul di layar (misalnya di bawah tombol Hitung), bukan di messagebox.
Setelah tombol "Hitung Kalori" ditekan, semua kotak entry otomatis dikosongkan.
Berikut isi file sub_menu_kebutuhan_kalori.py yang sudah sesuai permintaan:
import tkinter as tk
def show_sub_menu_kebutuhan_kalori(root_frame):
from menu_profil_kesehatan import show_menu_profil_kesehatan # Hindari circular import
# Bersihkan frame
for widget in root_frame.winfo_children():
widget.destroy()
# Judul
tk.Label(
root_frame,
text="Kebutuhan Kalori Harian",
font=("Arial", 18, "bold"),
bg="green",
fg="orange",
pady=10
).pack(pady=20)
# Frame form
form_frame = tk.Frame(root_frame)
form_frame.pack(pady=10)
# Label & Entry sejajar
tk.Label(form_frame, text="Berat Badan (kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", padx=5, pady=5)
berat_entry = tk.Entry(form_frame, font=("Arial", 12))
berat_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(form_frame, text="Tinggi Badan (cm):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", padx=5, pady=5)
tinggi_entry = tk.Entry(form_frame, font=("Arial", 12))
tinggi_entry.grid(row=1, column=1, padx=5, pady=5)
tk.Label(form_frame, text="Usia (tahun):", font=("Arial", 12)).grid(row=2, column=0, sticky="w", padx=5, pady=5)
usia_entry = tk.Entry(form_frame, font=("Arial", 12))
usia_entry.grid(row=2, column=1, padx=5, pady=5)
tk.Label(form_frame, text="Jenis Kelamin (L/P):", font=("Arial", 12)).grid(row=3, column=0, sticky="w", padx=5, pady=5)
gender_entry = tk.Entry(form_frame, font=("Arial", 12))
gender_entry.grid(row=3, column=1, padx=5, pady=5)
# Label untuk menampilkan hasil
hasil_label = tk.Label(root_frame, text="", font=("Arial", 12), fg="blue")
hasil_label.pack(pady=10)
# Fungsi hitung kalori
def hitung_kalori():
try:
berat = float(berat_entry.get())
tinggi = float(tinggi_entry.get())
usia = int(usia_entry.get())
gender = gender_entry.get().strip().upper()
if gender == "L": # Laki-laki
bmr = 88.362 + (13.397 * berat) + (4.799 * tinggi) - (5.677 * usia)
elif gender == "P": # Perempuan
bmr = 447.593 + (9.247 * berat) + (3.098 * tinggi) - (4.330 * usia)
else:
hasil_label.config(text="⚠ Masukkan jenis kelamin L atau P.")
return
hasil_label.config(text=f"Kebutuhan Kalori Harian: {bmr:.2f} kkal")
# Kosongkan entry
berat_entry.delete(0, tk.END)
tinggi_entry.delete(0, tk.END)
usia_entry.delete(0, tk.END)
gender_entry.delete(0, tk.END)
except ValueError:
hasil_label.config(text="⚠ Pastikan semua input angka valid.")
# Tombol hitung
tk.Button(
root_frame,
text="Hitung Kalori",
font=("Arial", 12),
bg="#4CAF50",
fg="white",
command=hitung_kalori
).pack(pady=10)
# Tombol kembali
tk.Button(
root_frame,
text="Kembali",
font=("Arial", 12),
bg="gray",
fg="white",
command=lambda: show_menu_profil_kesehatan(root_frame)
).pack(pady=20)
✅ Perubahan yang saya buat:
- Kotak Entry sekarang sejajar dengan label teks (pakai
griddalamform_frame). - Hasil perhitungan muncul langsung di layar (label
hasil_label). - Setelah tombol "Hitung Kalori" ditekan, kotak entry otomatis bersih.
- Pesan validasi juga ditampilkan langsung di layar, bukan lewat kotak pesan pop-up.
Kalau mau lebih praktis lagi, kita bisa otomatis ambil data berat, tinggi, dan usia dari data_diri.db jika sudah ada, sehingga user tidak perlu mengetik ulang.
Kalau mau, saya bisa gabungkan fitur itu di versi berikutnya.
Sampai saat ini perubahan, penyempurnaan, dan tambahan file pada applikasi SmartNutriChefAI adalah:
1. menu_profil_kesehatan.py
Kode programnya adalah berikut:
# menu_profil_kesehatan
import tkinter as tk
from tkinter import ttk
from sub_menu_data_diri import show_sub_menu_data_diri
from sub_menu_berat_tinggi_badan import show_sub_menu_berat_tinggi_badan
from sub_menu_indeks_massa_tubuh import show_sub_menu_indeks_massa_tubuh
from sub_menu_riwayat_kesehatan import show_sub_menu_riwayat_kesehatan
from sub_menu_kebutuhan_kalori import show_sub_menu_kebutuhan_kalori
def show_menu_profil_kesehatan(root_frame):
from menu_utama import tampilkan_halaman_utama # Hindari circular import
for widget in root_frame.winfo_children():
widget.destroy()
# Judul
tk.Label(
root_frame,
text="Profil Kesehatan",
font=("Arial", 18, "bold"),
bg="green",
fg="orange",
padx=10,
pady=10
).pack(pady=20)
# Daftar submenu sebagai list tuple: (teks tombol, fungsi yang dipanggil)
submenus = [
("Data Diri", show_sub_menu_data_diri),
("Berat & Tinggi Badan", show_sub_menu_berat_tinggi_badan),
# Tambahkan submenu lain di sini, contoh:
# ("Kalori Harian", show_sub_menu_kalori_harian),
# ("Riwayat BMI", show_sub_menu_riwayat_bmi),
("Indeks Massa Tubuh \n(IMT)", show_sub_menu_indeks_massa_tubuh), # Tambahkan ini
("Riwayat Kesehatan", show_sub_menu_riwayat_kesehatan),
("Kebutuhan Kalori Harian", show_sub_menu_kebutuhan_kalori),
]
# Buat tombol-tombol sub menu
for teks, fungsi in submenus:
tk.Button(
root_frame,
text=teks,
font=("Arial", 12),
bg="light blue",
fg="black",
command=lambda f=fungsi: f(root_frame)
).pack(pady=10)
# Tambahkan separator antar tombol (kecuali terakhir)
ttk.Separator(root_frame, orient='horizontal').pack(fill='x', padx=40, pady=2)
# Tombol kembali
tk.Button(
root_frame,
text="Kembali ke Menu Utama",
font=("Arial", 12),
bg="gray",
fg="white",
command=lambda: tampilkan_halaman_utama(root_frame)
).pack(pady=30)
2. sub_menu_kebutuhan_kalori.py
Kode programnya adalah berikut:
# Sub Menu Kebutuhan Kalori
import tkinter as tk
from tkinter import ttk
def show_sub_menu_kebutuhan_kalori(root_frame):
from menu_profil_kesehatan import show_menu_profil_kesehatan # Hindari circular import
# Bersihkan frame
for widget in root_frame.winfo_children():
widget.destroy()
# Judul
tk.Label(
root_frame,
text="Kebutuhan Kalori Harian",
font=("Arial", 17, "bold"),
bg="green",
fg="orange",
pady=10
).pack(pady=20)
# Frame form
form_frame = tk.Frame(root_frame)
form_frame.pack(pady=10)
# Label & Entry sejajar
tk.Label(form_frame, text="Berat Badan (kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", padx=5, pady=5)
berat_entry = tk.Entry(form_frame, font=("Arial", 12))
berat_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(form_frame, text="Tinggi Badan (cm):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", padx=5, pady=5)
tinggi_entry = tk.Entry(form_frame, font=("Arial", 12))
tinggi_entry.grid(row=1, column=1, padx=5, pady=5)
tk.Label(form_frame, text="Usia (tahun):", font=("Arial", 12)).grid(row=2, column=0, sticky="w", padx=5, pady=5)
usia_entry = tk.Entry(form_frame, font=("Arial", 12))
usia_entry.grid(row=2, column=1, padx=5, pady=5)
tk.Label(form_frame, text="Jenis Kelamin (L/P):", font=("Arial", 12)).grid(row=3, column=0, sticky="w", padx=5, pady=5)
gender_entry = tk.Entry(form_frame, font=("Arial", 12))
gender_entry.grid(row=3, column=1, padx=5, pady=5)
# Label untuk menampilkan hasil
hasil_label = tk.Label(root_frame, text="", font=("Arial", 12), fg="blue")
hasil_label.pack(pady=10)
# Fungsi hitung kalori
def hitung_kalori():
try:
berat = float(berat_entry.get())
tinggi = float(tinggi_entry.get())
usia = int(usia_entry.get())
gender = gender_entry.get().strip().upper()
if gender == "L": # Laki-laki
bmr = 88.362 + (13.397 * berat) + (4.799 * tinggi) - (5.677 * usia)
elif gender == "P": # Perempuan
bmr = 447.593 + (9.247 * berat) + (3.098 * tinggi) - (4.330 * usia)
else:
hasil_label.config(text="⚠ Masukkan jenis kelamin L atau P.")
return
hasil_label.config(text=f"Kebutuhan Kalori Harian: \n{bmr:.2f} kkal")
# Kosongkan entry
berat_entry.delete(0, tk.END)
tinggi_entry.delete(0, tk.END)
usia_entry.delete(0, tk.END)
gender_entry.delete(0, tk.END)
except ValueError:
hasil_label.config(text="⚠ Pastikan semua input angka valid.")
# Tambahkan separator antar tombol (kecuali terakhir)
ttk.Separator(root_frame, orient='horizontal').pack(fill='x', padx=40, pady=2)
# Tombol hitung
tk.Button(
root_frame,
text="Hitung Kalori",
font=("Arial", 12),
bg="#4CAF50",
fg="white",
command=hitung_kalori
).pack(pady=10)
# Tambahkan separator antar tombol (kecuali terakhir)
ttk.Separator(root_frame, orient='horizontal').pack(fill='x', padx=40, pady=2)
# Tombol kembali
tk.Button(
root_frame,
text="Kembali",
font=("Arial", 12),
bg="gray",
fg="white",
command=lambda: show_menu_profil_kesehatan(root_frame)
).pack(pady=20)
Bersambung Ke: Konten Sub Menu "Status Gizi"
Comments
Post a Comment