Konten Sub Menu "Status Gizi"

Isi Menu "Profil Kesehatan"

(Konten Sub Menu "Status Gizi")


6. Sub Menu  “Status Gizi”

Lanjut kita membuat konten Sub Menu "Status Gizi"

Oke, untuk sub menu "Status Gizi", saya sarankan kita bikin dua fitur utama di layarnya:

  1. Ambil data otomatis dari data_diri.db untuk menghitung status gizi berdasarkan IMT (Indeks Massa Tubuh).
  2. Menampilkan hasil status gizi langsung di layar, termasuk kategori gizi menurut WHO (Kurus, Normal, Overweight, Obesitas).

Struktur filenya kita buat seperti file sub menu lain, misalnya:
sub_menu_status_gizi.py


Kode sub_menu_status_gizi.py

import tkinter as tk
import sqlite3

DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"

def ambil_data_diri():
    """Ambil data berat & tinggi dari database"""
    try:
        conn = sqlite3.connect(DATABASE_PATH)
        c = conn.cursor()
        c.execute("SELECT berat_badan, tinggi_badan FROM data_diri ORDER BY id DESC LIMIT 1")
        hasil = c.fetchone()
        conn.close()
        return hasil  # (berat, tinggi)
    except:
        return None

def show_sub_menu_status_gizi(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan  # Hindari circular import

    # Bersihkan layar
    for widget in root_frame.winfo_children():
        widget.destroy()

    # Judul
    tk.Label(
        root_frame,
        text="Status Gizi",
        font=("Arial", 18, "bold"),
        bg="green",
        fg="orange",
        pady=10
    ).pack(pady=20)

    # Frame info
    info_frame = tk.Frame(root_frame)
    info_frame.pack(pady=10)

    berat_label = tk.Label(info_frame, text="Berat Badan: -", font=("Arial", 12))
    berat_label.grid(row=0, column=0, sticky="w", padx=5, pady=5)

    tinggi_label = tk.Label(info_frame, text="Tinggi Badan: -", font=("Arial", 12))
    tinggi_label.grid(row=1, column=0, sticky="w", padx=5, pady=5)

    hasil_label = tk.Label(root_frame, text="", font=("Arial", 12), fg="blue")
    hasil_label.pack(pady=10)

    # Fungsi hitung status gizi
    def hitung_status_gizi():
        data = ambil_data_diri()
        if not data:
            hasil_label.config(text="⚠ Data tidak ditemukan di database.")
            return

        berat, tinggi = data
        berat_label.config(text=f"Berat Badan: {berat} kg")
        tinggi_label.config(text=f"Tinggi Badan: {tinggi} cm")

        if berat <= 0 or tinggi <= 0:
            hasil_label.config(text="⚠ Data tidak valid.")
            return

        tinggi_m = tinggi / 100
        imt = berat / (tinggi_m ** 2)

        # Kategori WHO
        if imt < 18.5:
            status = "Kurus"
        elif 18.5 <= imt < 25:
            status = "Normal"
        elif 25 <= imt < 30:
            status = "Kelebihan Berat Badan"
        else:
            status = "Obesitas"

        hasil_label.config(text=f"IMT: {imt:.2f} → Status Gizi: {status}")

    # Tombol hitung
    tk.Button(
        root_frame,
        text="Hitung Status Gizi",
        font=("Arial", 12),
        bg="#4CAF50",
        fg="white",
        command=hitung_status_gizi
    ).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)

Cara kerja:

  • Saat masuk ke menu "Status Gizi", user tekan tombol "Hitung Status Gizi".
  • Sistem otomatis mengambil berat & tinggi terakhir dari data_diri.db.
  • Menghitung IMT, lalu menampilkan kategori gizi.
  • Tidak ada input manual — data diambil dari database untuk meminimalkan kesalahan.

Kalau mau, saya bisa tambahkan opsi input manual kalau data di database kosong, jadi menu ini tetap bisa dipakai meskipun user belum mengisi Data Diri.
Mau langsung saya buatkan versi yang ada fallback input manual itu?


Bagaimana perubahan isi file mwnu_profil_kesehatan.py

Kalau kita menambahkan sub menu baru "Status Gizi", maka file menu_profil_kesehatan.py harus diperbarui supaya tombolnya ikut muncul.

Supaya rapi dan mudah tambah menu lagi nanti, tombol-tombol sub menu akan kita buat pakai loop list — bukan hardcode satu per satu seperti sebelumnya.
Dengan begitu, kalau mau menambah sub menu lain, cukup tambah 1 baris di list.


Perubahan menu_profil_kesehatan.py

# 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
from sub_menu_status_gizi import show_sub_menu_status_gizi

def show_menu_profil_kesehatan(root_frame):
    from menu_utama import tampilkan_halaman_utama  # Hindari circular import

    # Bersihkan layar
    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)

    # List sub menu: (label, fungsi)
    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),
        ("Status Gizi", show_sub_menu_status_gizi),
    ]

    # Loop buat tombol sub menu
    for i, (label, func) in enumerate(sub_menus):
        tk.Button(
            root_frame,
            text=label,
            font=("Arial", 12),
            bg="light blue",
            fg="black",
            command=lambda f=func: f(root_frame)
        ).pack(pady=10)

        # Separator antar tombol (kecuali terakhir)
        if i < len(sub_menus) - 1:
            tk.Frame(root_frame, height=2, bg="gray").pack(fill="x", padx=50, 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)

Keuntungan cara ini:

  • Lebih singkat: Semua tombol sub menu dibuat dari 1 loop.
  • Mudah tambah menu baru: Cukup tambahkan tuple (nama tombol, fungsi) di list sub_menus.
  • Ada separator otomatis antar tombol supaya rapi.

Kalau mau, saya bisa tambahkan ikon kecil di sebelah teks tombol supaya menu ini kelihatan lebih menarik.
Mau saya buatkan versi dengan ikon?


Ketika kode program dieksekusi, dan tombol "Hitung Status Gizi" ditekan, muncul error: Data Tidak Ditemukan di Database

Itu artinya di database data_diri.db belum ada data yang dibaca oleh file sub_menu_status_gizi.py ketika tombol "Hitung Status Gizi" ditekan.

Penyebab umum:

  1. Tabel data_diri kosong — User belum pernah mengisi data melalui menu Data Diri.
  2. Path database salah — Lokasi data_diri.db di kode sub_menu_status_gizi.py tidak sama dengan lokasi penyimpanan di menu Data Diri.
  3. Format tabel tidak sesuai — Kolom yang dibaca (misalnya berat_badan dan tinggi_badan) tidak ada di tabel.

Solusi yang perlu dilakukan

1️⃣ Pastikan path database sama

Di sub_menu_status_gizi.py pastikan:

DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"

Path ini harus sama dengan yang dipakai di sub_menu_data_diri.py.


2️⃣ Pastikan ada data di tabel data_diri

Coba cek manual dengan script sederhana:

import sqlite3

DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"

conn = sqlite3.connect(DATABASE_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM data_diri")
rows = cursor.fetchall()
print(rows)
conn.close()

Kalau hasilnya [], berarti memang tidak ada data → user harus isi dulu lewat menu Data Diri.


3️⃣ Tambahkan validasi di sub_menu_status_gizi.py

Supaya tidak error dan muncul pesan yang jelas:

cursor.execute("SELECT berat_badan, tinggi_badan FROM data_diri ORDER BY id DESC LIMIT 1")
result = cursor.fetchone()

if result:
    berat_badan, tinggi_badan = result
    # lanjut hitung status gizi...
else:
    messagebox.showwarning("Data Tidak Ditemukan", "Silakan isi data diri Anda terlebih dahulu di menu 'Data Diri'.")
    return

Kalau mau, aku bisa langsung revisikan file sub_menu_status_gizi.py milik kamu supaya:

  • Otomatis memeriksa ketersediaan data
  • Menampilkan peringatan kalau data belum diinput
  • Tidak crash/error walaupun database kosong

Mau saya buatkan langsung revisinya?


Apa iti Status Gizi?.
Data ada tetsedia di database (data_diri.db), file data_diri.db ada di dirwktori dengan path: /storage/emulated/0/AppJadi/SmartNutriChefAI/Database/
Mungkin kode pada isi file sub_menu_status_gizi.py perlu diperbaiki


Oke, saya jelaskan dulu singkat.

Status gizi adalah kondisi tubuh seseorang yang ditentukan oleh keseimbangan antara asupan gizi dan kebutuhan gizi tubuhnya.
Umumnya diukur lewat IMT (Indeks Massa Tubuh) dan dibandingkan dengan kategori WHO:

  • IMT < 18.5 → Kekurangan gizi (underweight)
  • 18.5 ≤ IMT < 25 → Normal
  • 25 ≤ IMT < 30 → Kelebihan berat badan (overweight)
  • IMT ≥ 30 → Obesitas

Kalau datanya sudah ada di database tapi saat tombol Hitung Status Gizi ditekan masih muncul error "Data Tidak Ditemukan", berarti kemungkinan besar kodenya tidak membaca data dengan benar dari data_diri.db.

Saya bisa perbaiki sub_menu_status_gizi.py agar:

  1. Path database sesuai (/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db).
  2. Mengambil data terakhir dari tabel data_diri.
  3. Menghitung IMT otomatis dan menampilkan hasil status gizi di layar, bukan di kotak pesan.
  4. Tidak error walaupun tabel kosong.

Berikut contoh revisinya:

import tkinter as tk
from tkinter import messagebox
import sqlite3

# Path database
DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"

def hitung_status_gizi(berat, tinggi):
    tinggi_meter = tinggi / 100
    imt = berat / (tinggi_meter ** 2)
    if imt < 18.5:
        kategori = "Kurus"
    elif 18.5 <= imt < 25:
        kategori = "Normal"
    elif 25 <= imt < 30:
        kategori = "Gemuk"
    else:
        kategori = "Obesitas"
    return imt, kategori

def show_sub_menu_status_gizi(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan

    # Bersihkan frame
    for widget in root_frame.winfo_children():
        widget.destroy()

    # Judul
    tk.Label(root_frame, text="Status Gizi", font=("Arial", 18, "bold"), bg="green", fg="orange", pady=10).pack(pady=20)

    # Frame untuk hasil
    frame_hasil = tk.Frame(root_frame)
    frame_hasil.pack(pady=20)

    # Ambil data terakhir dari database
    try:
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT berat, tinggi FROM data_diri ORDER BY id DESC LIMIT 1")
        result = cursor.fetchone()
        conn.close()

        if result:
            berat_badan, tinggi_badan = result
            imt, kategori = hitung_status_gizi(berat_badan, tinggi_badan)

            tk.Label(frame_hasil, text=f"Berat Badan: {berat_badan} kg", font=("Arial", 12)).pack()
            tk.Label(frame_hasil, text=f"Tinggi Badan: {tinggi_badan} cm", font=("Arial", 12)).pack()
            tk.Label(frame_hasil, text=f"IMT: {imt:.2f}", font=("Arial", 12, "bold")).pack()
            tk.Label(frame_hasil, text=f"Status Gizi: {kategori}", font=("Arial", 12, "bold")).pack()

        else:
            tk.Label(frame_hasil, text="Data tidak ditemukan. Silakan isi data di menu 'Data Diri'.", font=("Arial", 12), fg="red").pack()

    except sqlite3.Error as e:
        tk.Label(frame_hasil, text=f"Error membaca database: {e}", font=("Arial", 12), fg="red").pack()

    # 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=30)

Dengan kode ini:

  • Dia akan membaca data terakhir dari data_diri.db.
  • Menampilkan berat, tinggi, IMT, dan kategori status gizi langsung di layar.
  • Tidak akan crash jika database kosong → muncul pesan peringatan di layar, bukan messagebox.
  • Path sudah sesuai dengan yang kamu pakai di menu Data Diri.

Kalau mau, saya juga bisa tambahkan fitur input manual di halaman Status Gizi supaya user bisa hitung tanpa harus mengubah database.
Mau saya tambahkan juga?


Kode yang benar:
SELECT berat, tinggi FROM data_diri
Sudah tampil Hasil hitungan Status Gizi, langsung ditampilkan di frame (layar) berdasarkan data dari database. Sekarang tambahkan juga hitungan manualnya dengan ada tombol "Hitung Status Gizi"

Oke, berarti kita sudah tahu kolomnya adalah berat dan tinggi, jadi query database sudah aman.
Sekarang saya buatkan versi sub_menu_status_gizi.py yang:

  1. Menampilkan hasil Status Gizi langsung dari database (data terakhir).
  2. Menambahkan form input manual untuk menghitung status gizi dengan memasukkan berat & tinggi di kotak entry.
  3. Menampilkan hasilnya di layar, bukan messagebox.
  4. Membersihkan kotak entry setelah tombol ditekan.

import tkinter as tk
from tkinter import messagebox
import sqlite3

DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"

def ambil_data_dari_db():
    """Ambil data berat dan tinggi terakhir dari database."""
    try:
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT berat, tinggi FROM data_diri ORDER BY id DESC LIMIT 1")
        data = cursor.fetchone()
        conn.close()
        return data if data else None
    except Exception as e:
        print("Error membaca database:", e)
        return None

def hitung_status_gizi(berat, tinggi):
    """Hitung IMT dan status gizi berdasarkan berat & tinggi."""
    try:
        tinggi_m = tinggi / 100  # cm -> meter
        imt = berat / (tinggi_m ** 2)

        if imt < 18.5:
            kategori = "Kurus"
        elif 18.5 <= imt < 25:
            kategori = "Normal"
        elif 25 <= imt < 30:
            kategori = "Gemuk"
        else:
            kategori = "Obesitas"

        return imt, kategori
    except ZeroDivisionError:
        return None, "Tinggi tidak valid"

def show_sub_menu_status_gizi(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan

    # Bersihkan frame
    for widget in root_frame.winfo_children():
        widget.destroy()

    # Judul
    tk.Label(root_frame, text="Status Gizi", font=("Arial", 18, "bold"),
             bg="green", fg="orange", pady=10).pack(pady=20)

    # Frame untuk hasil dari database
    frame_db = tk.LabelFrame(root_frame, text="Berdasarkan Data dari Database", font=("Arial", 12, "bold"))
    frame_db.pack(pady=10, padx=10, fill="x")

    hasil_db_label = tk.Label(frame_db, text="", font=("Arial", 12), justify="left")
    hasil_db_label.pack(padx=10, pady=10, anchor="w")

    # Ambil dan tampilkan hasil dari database
    data_db = ambil_data_dari_db()
    if data_db:
        berat, tinggi = data_db
        imt, kategori = hitung_status_gizi(berat, tinggi)
        hasil_db_label.config(
            text=f"Berat Badan : {berat} kg\nTinggi Badan : {tinggi} cm\nIMT : {imt:.2f}\nStatus Gizi : {kategori}"
        )
    else:
        hasil_db_label.config(text="Belum ada data di database.")

    # Separator
    tk.Label(root_frame, text="").pack(pady=5)

    # Frame untuk hitung manual
    frame_manual = tk.LabelFrame(root_frame, text="Hitung Manual", font=("Arial", 12, "bold"))
    frame_manual.pack(pady=10, padx=10, fill="x")

    # Input manual
    tk.Label(frame_manual, text="Berat Badan (kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", padx=5, pady=5)
    entry_berat = tk.Entry(frame_manual, font=("Arial", 12))
    entry_berat.grid(row=0, column=1, padx=5, pady=5)

    tk.Label(frame_manual, text="Tinggi Badan (cm):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", padx=5, pady=5)
    entry_tinggi = tk.Entry(frame_manual, font=("Arial", 12))
    entry_tinggi.grid(row=1, column=1, padx=5, pady=5)

    # Label hasil manual
    hasil_manual_label = tk.Label(frame_manual, text="", font=("Arial", 12), justify="left", fg="blue")
    hasil_manual_label.grid(row=3, column=0, columnspan=2, pady=10)

    def proses_hitung_manual():
        try:
            berat = float(entry_berat.get())
            tinggi = float(entry_tinggi.get())
            imt, kategori = hitung_status_gizi(berat, tinggi)
            if imt:
                hasil_manual_label.config(
                    text=f"IMT : {imt:.2f}\nStatus Gizi : {kategori}"
                )
            else:
                hasil_manual_label.config(text="Tinggi tidak valid.")
            # Bersihkan entry
            entry_berat.delete(0, tk.END)
            entry_tinggi.delete(0, tk.END)
        except ValueError:
            messagebox.showwarning("Validasi", "Masukkan angka yang benar untuk berat dan tinggi.")

    # Tombol hitung manual
    tk.Button(frame_manual, text="Hitung Status Gizi", font=("Arial", 12),
              bg="#4CAF50", fg="white", command=proses_hitung_manual).grid(row=2, column=0, columnspan=2, 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:

  • Query database sudah pakai SELECT berat, tinggi.
  • Hasil dari database langsung tampil di layar.
  • Ada bagian hitung manual dengan entry di samping label.
  • Setelah tombol ditekan, hasil langsung tampil di layar & entry dibersihkan.

Kalau mau, saya bisa tambahkan validasi otomatis supaya kalau di database berat/tinggi kosong atau 0, bagian database tidak error tapi memberi pesan.
Mau saya tambahkan validasinya juga?


Kategori yang dihasilkan berdasarkan hitungan IMT dan Status Gizi berdasarkan dari database, buatkan warna teks IMT dan Status Gizi beserta nilainya buat berwarna biru.

Oke, berarti kita akan modifikasi bagian hasil dari database supaya nilai IMT dan Status Gizi tampil berwarna biru, sementara label “Berat Badan” dan “Tinggi Badan” tetap warna hitam biasa.

Berikut perbaikannya di file sub_menu_status_gizi.py:

import tkinter as tk
from tkinter import messagebox
import sqlite3

DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"

def ambil_data_dari_db():
    """Ambil data berat dan tinggi terakhir dari database."""
    try:
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()
        cursor.execute("SELECT berat, tinggi FROM data_diri ORDER BY id DESC LIMIT 1")
        data = cursor.fetchone()
        conn.close()
        return data if data else None
    except Exception as e:
        print("Error membaca database:", e)
        return None

def hitung_status_gizi(berat, tinggi):
    """Hitung IMT dan status gizi berdasarkan berat & tinggi."""
    try:
        tinggi_m = tinggi / 100  # cm -> meter
        imt = berat / (tinggi_m ** 2)

        if imt < 18.5:
            kategori = "Kurus"
        elif 18.5 <= imt < 25:
            kategori = "Normal"
        elif 25 <= imt < 30:
            kategori = "Gemuk"
        else:
            kategori = "Obesitas"

        return imt, kategori
    except ZeroDivisionError:
        return None, "Tinggi tidak valid"

def show_sub_menu_status_gizi(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan

    # Bersihkan frame
    for widget in root_frame.winfo_children():
        widget.destroy()

    # Judul
    tk.Label(root_frame, text="Status Gizi", font=("Arial", 18, "bold"),
             bg="green", fg="orange", pady=10).pack(pady=20)

    # Frame untuk hasil dari database
    frame_db = tk.LabelFrame(root_frame, text="Berdasarkan Data dari Database", font=("Arial", 12, "bold"))
    frame_db.pack(pady=10, padx=10, fill="x")

    # Ambil data database
    data_db = ambil_data_dari_db()
    if data_db:
        berat, tinggi = data_db
        imt, kategori = hitung_status_gizi(berat, tinggi)

        # Berat & Tinggi
        tk.Label(frame_db, text=f"Berat Badan : {berat} kg", font=("Arial", 12)).pack(anchor="w", padx=10, pady=2)
        tk.Label(frame_db, text=f"Tinggi Badan : {tinggi} cm", font=("Arial", 12)).pack(anchor="w", padx=10, pady=2)

        # IMT (warna biru)
        tk.Label(frame_db, text=f"IMT : {imt:.2f}", font=("Arial", 12, "bold"), fg="blue").pack(anchor="w", padx=10, pady=2)

        # Status Gizi (warna biru)
        tk.Label(frame_db, text=f"Status Gizi : {kategori}", font=("Arial", 12, "bold"), fg="blue").pack(anchor="w", padx=10, pady=2)
    else:
        tk.Label(frame_db, text="Belum ada data di database.", font=("Arial", 12)).pack(anchor="w", padx=10, pady=5)

    # Frame untuk hitung manual
    frame_manual = tk.LabelFrame(root_frame, text="Hitung Manual", font=("Arial", 12, "bold"))
    frame_manual.pack(pady=10, padx=10, fill="x")

    tk.Label(frame_manual, text="Berat Badan (kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", padx=5, pady=5)
    entry_berat = tk.Entry(frame_manual, font=("Arial", 12))
    entry_berat.grid(row=0, column=1, padx=5, pady=5)

    tk.Label(frame_manual, text="Tinggi Badan (cm):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", padx=5, pady=5)
    entry_tinggi = tk.Entry(frame_manual, font=("Arial", 12))
    entry_tinggi.grid(row=1, column=1, padx=5, pady=5)

    # Label hasil manual
    hasil_manual_label = tk.Label(frame_manual, text="", font=("Arial", 12), justify="left")
    hasil_manual_label.grid(row=3, column=0, columnspan=2, pady=10)

    def proses_hitung_manual():
        try:
            berat = float(entry_berat.get())
            tinggi = float(entry_tinggi.get())
            imt, kategori = hitung_status_gizi(berat, tinggi)
            if imt:
                hasil_manual_label.config(
                    text=f"IMT : {imt:.2f}\nStatus Gizi : {kategori}",
                    fg="blue"  # Hasil manual juga warna biru
                )
            else:
                hasil_manual_label.config(text="Tinggi tidak valid.", fg="red")

            entry_berat.delete(0, tk.END)
            entry_tinggi.delete(0, tk.END)
        except ValueError:
            messagebox.showwarning("Validasi", "Masukkan angka yang benar untuk berat dan tinggi.")

    tk.Button(frame_manual, text="Hitung Status Gizi", font=("Arial", 12),
              bg="#4CAF50", fg="white", command=proses_hitung_manual).grid(row=2, column=0, columnspan=2, 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:

  1. Nilai IMT dan Status Gizi dari database sekarang tampil dengan warna biru.
  2. Bagian hitung manual juga akan menampilkan hasilnya dengan warna biru supaya konsisten.
  3. Format tetap rapi: berat dan tinggi tetap hitam, IMT & Status Gizi saja yang biru.

Kalau mau, saya bisa bikin warna berbeda untuk tiap kategori (misalnya hijau untuk normal, kuning untuk gemuk, merah untuk obesitas).
Mau saya buat begitu juga?


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

from sub_menu_status_gizi import show_sub_menu_status_gizi


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),

        ("Status Gizi", show_sub_menu_status_gizi),

]


    # 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_status_gizi.py

Kode programnya adalah berikut:


# Sub Menu Status Gizi

import tkinter as tk

from tkinter import ttk

from tkinter import messagebox

import sqlite3


DATABASE_PATH = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/data_diri.db"


def ambil_data_dari_db():

    """Ambil data berat dan tinggi terakhir dari database."""

    try:

        conn = sqlite3.connect(DATABASE_PATH)

        cursor = conn.cursor()

        cursor.execute("SELECT berat, tinggi FROM data_diri ORDER BY id DESC LIMIT 1")

        data = cursor.fetchone()

        conn.close()

        return data if data else None

    except Exception as e:

        print("Error membaca database:", e)

        return None


def hitung_status_gizi(berat, tinggi):

    """Hitung IMT dan status gizi berdasarkan berat & tinggi."""

    try:

        tinggi_m = tinggi / 100  # cm -> meter

        imt = berat / (tinggi_m ** 2)


        if imt < 18.5:

            kategori = "Kurus"

        elif 18.5 <= imt < 25:

            kategori = "Normal"

        elif 25 <= imt < 30:

            kategori = "Gemuk"

        else:

            kategori = "Obesitas"


        return imt, kategori

    except ZeroDivisionError:

        return None, "Tinggi tidak valid"


def show_sub_menu_status_gizi(root_frame):

    from menu_profil_kesehatan import show_menu_profil_kesehatan


    # Bersihkan frame

    for widget in root_frame.winfo_children():

        widget.destroy()


    # Judul

    tk.Label(root_frame, text="Status Gizi", font=("Arial", 18, "bold"),

             bg="green", fg="orange", pady=10).pack(pady=20)


    # Frame untuk hasil dari database

    frame_db = tk.LabelFrame(root_frame, text="Berdasarkan Data dari Database", font=("Arial", 12, "bold"))

    frame_db.pack(pady=10, padx=10, fill="x")


    # Ambil data database

    data_db = ambil_data_dari_db()

    if data_db:

        berat, tinggi = data_db

        imt, kategori = hitung_status_gizi(berat, tinggi)


        # Berat & Tinggi

        tk.Label(frame_db, text=f"Berat Badan : {berat} kg", font=("Arial", 12)).pack(anchor="w", padx=10, pady=2)

        tk.Label(frame_db, text=f"Tinggi Badan : {tinggi} cm", font=("Arial", 12)).pack(anchor="w", padx=10, pady=2)


        # IMT (warna biru)

        tk.Label(frame_db, text=f"IMT : {imt:.2f}", font=("Arial", 12, "bold"), fg="blue").pack(anchor="w", padx=10, pady=2)


        # Status Gizi (warna biru)

        tk.Label(frame_db, text=f"Status Gizi : {kategori}", font=("Arial", 12, "bold"), fg="blue").pack(anchor="w", padx=10, pady=2)

    else:

        tk.Label(frame_db, text="Belum ada data di database.", font=("Arial", 12)).pack(anchor="w", padx=10, pady=5)

        

    # Tambahkan separator antar tombol (kecuali terakhir)

    ttk.Separator(root_frame, orient='horizontal').pack(fill='x', padx=40, pady=2)              


    # Frame untuk hitung manual

    frame_manual = tk.LabelFrame(root_frame, text="Hitung Manual", font=("Arial", 12, "bold"))

    frame_manual.pack(pady=10, padx=10, fill="x")


    tk.Label(frame_manual, text="Berat Badan (kg):", font=("Arial", 12)).grid(row=0, column=0, sticky="w", padx=5, pady=5)

    entry_berat = tk.Entry(frame_manual, font=("Arial", 12))

    entry_berat.grid(row=0, column=1, padx=5, pady=5)


    tk.Label(frame_manual, text="Tinggi Badan (cm):", font=("Arial", 12)).grid(row=1, column=0, sticky="w", padx=5, pady=5)

    entry_tinggi = tk.Entry(frame_manual, font=("Arial", 12))

    entry_tinggi.grid(row=1, column=1, padx=5, pady=5)

    

    # Label hasil manual

    hasil_manual_label = tk.Label(frame_manual, text="", font=("Arial", 12), justify="left")

    hasil_manual_label.grid(row=3, column=0, columnspan=2, pady=10)


    def proses_hitung_manual():

        try:

            berat = float(entry_berat.get())

            tinggi = float(entry_tinggi.get())

            imt, kategori = hitung_status_gizi(berat, tinggi)

            if imt:

                hasil_manual_label.config(

                    text=f"IMT : {imt:.2f}\nStatus Gizi : {kategori}",

                    fg="blue"  # Hasil manual juga warna biru

                )

            else:

                hasil_manual_label.config(text="Tinggi tidak valid.", fg="red")


            entry_berat.delete(0, tk.END)

            entry_tinggi.delete(0, tk.END)

        except ValueError:

            messagebox.showwarning("Validasi", "Masukkan angka yang benar untuk berat dan tinggi.")


    # Tambahkan separator antar tombol (kecuali terakhir)

    ttk.Separator(root_frame, orient='horizontal').pack(fill='x', padx=40, pady=2)         


    # Tombol hitung manual

    tk.Button(frame_manual, text="Hitung Status Gizi", font=("Arial", 12),

              bg="#4CAF50", fg="white", command=proses_hitung_manual).grid(row=2, column=0, columnspan=2, 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 "Kondisi Khusus"




Comments

Popular posts from this blog

Isi Menu "Setting"

Isi Menu "Riwayat Aktivitas" (Bagian 2)