Konten Sub Menu "Data Diri"

Isi Menu "Profil Kesehatan"

(Konten Sub Menu "Data Diri")


1. Sub Menu "Data Diri"

Sekarang kita membuat konten masing masing sub menu, pertama Data Diri, ini di bawah menu Profil Kesehatan

Kita akan menambahkan konten sub menu "Data Diri" di bawah menu Profil Kesehatan, sebagai bagian dari aplikasi SmartNutriChefAI. Sub menu ini akan berisi form input seperti: nama, umur, jenis kelamin, tinggi badan, dan berat badan, lalu tombol simpan dan kembali.


✅ Tujuan:

Menambahkan fungsi show_data_diri() di file menu_profil_kesehatan.py.


✅ Struktur:

menu_profil_kesehatan.py
├── show_menu_profil_kesehatan()       # Menu utama Profil Kesehatan
│   └── tombol: "Data Diri" ➜ show_data_diri()
└── show_data_diri()                   # Submenu form input Data Diri

๐Ÿงฉ 1. Tambahkan ke menu_profil_kesehatan.py:

import tkinter as tk
from tkinter import ttk

def show_menu_profil_kesehatan(root_frame):
    from menu_utama import tampilkan_halaman_utama

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

    label_judul = tk.Label(root_frame, text="Profil Kesehatan", font=("Arial", 18, "bold"),
                           bg="green", fg="orange", pady=10)
    label_judul.pack(pady=20, fill="x")

    label_subjudul = tk.Label(root_frame, text="Silakan pilih opsi:", font=("Arial", 12),
                              bg="light blue", fg="green", pady=5)
    label_subjudul.pack(pady=10, fill="x")

    # Tombol submenu
    tombol_data_diri = tk.Button(root_frame, text="Data Diri", font=("Arial", 12),
                                 bg="#2196F3", fg="white", width=30, height=2,
                                 command=lambda: show_data_diri(root_frame))
    tombol_data_diri.pack(pady=10)

    tombol_kembali = tk.Button(root_frame, text="Kembali ke Menu Utama", font=("Arial", 12),
                               bg="#4CAF50", fg="white", command=lambda: tampilkan_halaman_utama(root_frame))
    tombol_kembali.pack(pady=30)


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

    for widget in root_frame.winfo_children():
        widget.destroy()

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

    # Form input
    form_data = {}

    def buat_input(label_text, key):
        frame = tk.Frame(root_frame, bg="light blue", pady=5)
        frame.pack(fill="x", padx=20, pady=5)

        label = tk.Label(frame, text=label_text, font=("Arial", 12),
                         bg="light blue", fg="green", width=20, anchor="w")
        label.pack(side="left")

        entry = tk.Entry(frame, font=("Arial", 12), width=30)
        entry.pack(side="right", padx=10)
        form_data[key] = entry

    # Bidang input
    buat_input("Nama Lengkap:", "nama")
    buat_input("Usia (tahun):", "usia")
    buat_input("Jenis Kelamin:", "jenis_kelamin")
    buat_input("Tinggi Badan (cm):", "tinggi")
    buat_input("Berat Badan (kg):", "berat")

    # Tombol Simpan
    def simpan_data():
        data = {k: v.get() for k, v in form_data.items()}
        print("Data Diri Disimpan:", data)
        # Di sini bisa simpan ke file/database kalau perlu

    tk.Button(root_frame, text="Simpan Data", font=("Arial", 12),
              bg="blue", fg="white", width=20, height=2, command=simpan_data).pack(pady=20)

    # Tombol kembali
    tk.Button(root_frame, text="Kembali", font=("Arial", 12),
              bg="#4CAF50", fg="white", width=20, height=2,
              command=lambda: show_menu_profil_kesehatan(root_frame)).pack(pady=10)

✅ Tampilan yang Akan Muncul

  • Judul: "Data Diri"
  • Form:
    • Nama Lengkap
    • Usia
    • Jenis Kelamin
    • Tinggi Badan
    • Berat Badan
  • Tombol:
    • Simpan Data
    • Kembali

❗️Catatan:

  • Penyimpanan data masih berupa print() ke konsol. Kalau ingin simpan ke file .json, .txt, atau SQLite, tinggal saya bantu lanjutkan.
  • Jika ingin validasi input (misalnya usia harus angka), itu juga bisa ditambahkan.

Siap lanjut ke submenu berikutnya seperti Kondisi Kesehatan, Tujuan Nutrisi, atau lainnya?


Saya mau simpan datanya ke SQLite, dan validasi input Usia, tinggi badan, betat badan harus angka

Bagus, kita akan menyimpan data ke SQLite dan menambahkan validasi input pada kolom:

  • Usia
  • Tinggi Badan
  • Berat Badan

✅ Perubahan yang Akan Kita Lakukan:

  1. Tambahkan database SQLite (data_diri.db)
  2. Buat tabel data_diri jika belum ada
  3. Validasi input: hanya angka untuk usia, tinggi, dan berat
  4. Simpan data ke SQLite

๐Ÿ“ฆ 1. Buat atau tambahkan fungsi init_db() dan simpan_ke_db(data) ke menu_profil_kesehatan.py

Tambahkan di bagian paling atas:

import sqlite3
import tkinter as tk
from tkinter import messagebox

Lalu tambahkan ini setelah import:

# Inisialisasi database SQLite
def init_db():
    conn = sqlite3.connect("data_diri.db")
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS data_diri (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nama TEXT,
            usia INTEGER,
            jenis_kelamin TEXT,
            tinggi REAL,
            berat REAL
        )
    """)
    conn.commit()
    conn.close()

def simpan_ke_db(data):
    conn = sqlite3.connect("data_diri.db")
    cursor = conn.cursor()
    cursor.execute("""
        INSERT INTO data_diri (nama, usia, jenis_kelamin, tinggi, berat)
        VALUES (?, ?, ?, ?, ?)
    """, (data['nama'], int(data['usia']), data['jenis_kelamin'], float(data['tinggi']), float(data['berat'])))
    conn.commit()
    conn.close()

๐Ÿงฉ 2. Panggil init_db() di awal fungsi show_data_diri()

def show_data_diri(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan
    init_db()  # Panggil ini di awal

๐Ÿ” 3. Ubah fungsi simpan_data() jadi:

    def simpan_data():
        data = {k: v.get().strip() for k, v in form_data.items()}

        # Validasi
        if not data['nama'] or not data['jenis_kelamin']:
            messagebox.showerror("Input Error", "Nama dan Jenis Kelamin tidak boleh kosong.")
            return
        try:
            data['usia'] = int(data['usia'])
            data['tinggi'] = float(data['tinggi'])
            data['berat'] = float(data['berat'])
        except ValueError:
            messagebox.showerror("Input Error", "Usia harus angka, Tinggi dan Berat harus berupa angka desimal.")
            return

        try:
            simpan_ke_db(data)
            messagebox.showinfo("Berhasil", "Data berhasil disimpan ke database.")
        except Exception as e:
            messagebox.showerror("Database Error", f"Gagal menyimpan data: {e}")

✅ Penyesuaian Akhir

  • Pastikan kamu menyimpan file menu_profil_kesehatan.py di direktori sama dengan tempat splash_screen.py dijalankan.
  • File database SQLite data_diri.db akan otomatis dibuat saat kamu buka sub menu "Data Diri".

๐Ÿงช Hasilnya:

Ketika pengguna mengisi:

  • Nama
  • Usia
  • Jenis Kelamin
  • Tinggi
  • Berat

dan menekan Simpan, data akan tervalidasi dan disimpan ke SQLite.


Siap lanjut ke submenu berikutnya seperti:

  • Kondisi Kesehatan
  • Tujuan Nutrisi
  • atau ingin saya bantu buat halaman untuk menampilkan data yang sudah disimpan?

Saya mau data_diri.db disimpan ke path: /storage/emulated/0/AppJadi/SmartNutriChefAI/Database/

Bagus! Kita bisa arahkan penyimpanan database data_diri.db ke folder:

/storage/emulated/0/AppJadi/SmartNutriChefAI/Database/

Namun, perlu memastikan folder tersebut sudah ada sebelum menyimpan database ke sana. Kita akan:


✅ Langkah-Langkah:

  1. Buat folder jika belum ada
  2. Simpan database ke path tersebut
  3. Pastikan semua query tetap berjalan dengan baik

๐Ÿ› ️ 1. Ubah Fungsi init_db() dan simpan_ke_db(data)

Ganti versi sebelumnya dengan versi ini:

import os
import sqlite3
import tkinter as tk
from tkinter import messagebox

# Path lengkap untuk menyimpan database
DB_FOLDER = "/storage/emulated/0/AppJadi/SmartNutriChefAI/Database"
DB_PATH = os.path.join(DB_FOLDER, "data_diri.db")

# Inisialisasi database SQLite
def init_db():
    # Buat folder jika belum ada
    if not os.path.exists(DB_FOLDER):
        os.makedirs(DB_FOLDER)

    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS data_diri (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nama TEXT,
            usia INTEGER,
            jenis_kelamin TEXT,
            tinggi REAL,
            berat REAL
        )
    """)
    conn.commit()
    conn.close()

def simpan_ke_db(data):
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        INSERT INTO data_diri (nama, usia, jenis_kelamin, tinggi, berat)
        VALUES (?, ?, ?, ?, ?)
    """, (data['nama'], int(data['usia']), data['jenis_kelamin'], float(data['tinggi']), float(data['berat'])))
    conn.commit()
    conn.close()

๐Ÿงช Testing

Setelah kamu jalankan aplikasi:

  • Folder /storage/emulated/0/AppJadi/SmartNutriChefAI/Database/ akan otomatis dibuat jika belum ada.
  • File data_diri.db akan tersimpan di sana.
  • Data pengguna yang diinput pada menu "Data Diri" akan masuk ke database.

⚠️ Catatan Tambahan (penting untuk Android atau termux):

Jika kamu menjalankan ini di Android (via Pydroid atau termux), pastikan:

  • Aplikasi punya izin menulis ke storage.
  • Jalur /storage/emulated/0/... tersedia dan bisa diakses.

Jika perlu, tambahkan permission di Pydroid:
Settings → Permissions → Allow Storage Access


Ingin dilanjut ke fitur berikutnya, misalnya:

  • Menampilkan data yang sudah disimpan
  • Edit data pengguna
  • atau submenu selanjutnya seperti Kondisi Kesehatan?

Maunya file dibuat terpisah antara file menu dengan file sub menu seperti antara file menu_profil_kesehatan.py dengan file sub_menu_data_diri.py, dan dan ketika user menginput data dirinya pertama kali, dan ketika sudah di input data, lalu tombol "Simpan data* ditekan, maka data akan tersimpan ke database, dan teks pada kotak entry harus sudah bersih,

Baik! Ini penjelasan dan implementasi sesuai permintaan Anda:

✅ Tujuan:

  • Memisahkan file menu utama (menu_profil_kesehatan.py) dengan sub-menu (sub_menu_data_diri.py)
  • Agar struktur aplikasi lebih modular, terorganisir, dan mudah dikembangkan

๐Ÿ“‚ Struktur Direktori Disarankan

/SmartNutriChefAI/
│
├── splash_screen.py
├── menu_utama.py
├── menu_profil_kesehatan.py
├── sub_menu_data_diri.py      ✅ File baru untuk "Data Diri"
│
├── Database/
│   └── data_diri.db

✅ 1. menu_profil_kesehatan.py

import tkinter as tk
from sub_menu_data_diri import show_sub_menu_data_diri

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
    label_judul = tk.Label(root_frame, text="Menu Profil Kesehatan", font=("Arial", 18, "bold"), bg="green", fg="orange", padx=10, pady=10)
    label_judul.pack(pady=20)

    # Submenu tombol
    submenus = [
        ("Data Diri", lambda: show_sub_menu_data_diri(root_frame)),
        # Bisa tambah lagi: ("Hitung BMI", func_lainnya), dll.
    ]

    for label, command in submenus:
        lbl = tk.Label(root_frame, text=label, font=("Arial", 12), bg="light blue", fg="green")
        lbl.pack(pady=5)
        btn = tk.Button(root_frame, text=f"Buka {label}", command=command, font=("Arial", 12), bg="#4CAF50", fg="white")
        btn.pack(pady=5)

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

import tkinter as tk
from tkinter import messagebox
import sqlite3
import os

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

def init_db():
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS data_diri (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nama TEXT NOT NULL,
            usia INTEGER NOT NULL,
            jenis_kelamin TEXT,
            tinggi REAL NOT NULL,
            berat REAL NOT NULL
        )
    """)
    conn.commit()
    conn.close()

def show_sub_menu_data_diri(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan

    init_db()
    for widget in root_frame.winfo_children():
        widget.destroy()

    tk.Label(root_frame, text="Formulir Data Diri", font=("Arial", 18, "bold"), bg="green", fg="orange", padx=10, pady=10).pack(pady=20)

    fields = {}

    def buat_input(label, key):
        tk.Label(root_frame, text=label, font=("Arial", 12), bg="light blue", fg="green").pack(pady=5)
        entry = tk.Entry(root_frame, font=("Arial", 12), width=30)
        entry.pack(pady=5)
        fields[key] = entry

    buat_input("Nama", "nama")
    buat_input("Usia", "usia")
    buat_input("Jenis Kelamin (L/P)", "jenis_kelamin")
    buat_input("Tinggi Badan (cm)", "tinggi")
    buat_input("Berat Badan (kg)", "berat")

    def simpan_data():
        try:
            nama = fields["nama"].get()
            usia = int(fields["usia"].get())
            jenis_kelamin = fields["jenis_kelamin"].get()
            tinggi = float(fields["tinggi"].get())
            berat = float(fields["berat"].get())

            if not nama or not jenis_kelamin:
                raise ValueError("Nama dan Jenis Kelamin tidak boleh kosong.")

            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            cursor.execute("""
                INSERT INTO data_diri (nama, usia, jenis_kelamin, tinggi, berat)
                VALUES (?, ?, ?, ?, ?)
            """, (nama, usia, jenis_kelamin, tinggi, berat))
            conn.commit()
            conn.close()

            messagebox.showinfo("Sukses", "Data berhasil disimpan.")
            for entry in fields.values():
                entry.delete(0, tk.END)

        except ValueError as ve:
            messagebox.showerror("Input Salah", f"Kesalahan input: {ve}")
        except Exception as e:
            messagebox.showerror("Error", f"Terjadi kesalahan: {str(e)}")

    tk.Button(root_frame, text="Simpan Data", font=("Arial", 12), bg="#4CAF50", fg="white", command=simpan_data).pack(pady=20)

    tk.Button(root_frame, text="Kembali", font=("Arial", 12), bg="gray", fg="white", command=lambda: show_menu_profil_kesehatan(root_frame)).pack(pady=10)

๐Ÿ” Langkah Selanjutnya?

Jika sudah benar:

  • Lanjutkan dengan edit data diri
  • Tambahkan submenu hitung BMI
  • Atau tampilkan data yang telah disimpan

Beritahu saya bagian selanjutnya yang ingin Anda bangun. Saya siap bantu ๐Ÿ’ป


Buatkan setiap kotak entry berada di samping label teksnya, dan buat validasi input Usia, tinggi badan, berat badan harus angka, 

Baik! Berikut ini adalah versi terbaru dari file sub_menu_data_diri.py sesuai permintaan Anda:

✅ Perubahan:

  1. Label teks berada di samping kiri kotak entry (menggunakan tk.Frame dan pack(side=...))
  2. Validasi: Usia, Tinggi, dan Berat Badan wajib berupa angka.
  3. Layout lebih rapi dengan margin/padding yang sesuai.

✅ Kode Lengkap sub_menu_data_diri.py

import tkinter as tk
from tkinter import messagebox
import sqlite3
import os

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

def init_db():
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS data_diri (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nama TEXT NOT NULL,
            usia INTEGER NOT NULL,
            jenis_kelamin TEXT,
            tinggi REAL NOT NULL,
            berat REAL NOT NULL
        )
    """)
    conn.commit()
    conn.close()

def show_sub_menu_data_diri(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan

    init_db()
    for widget in root_frame.winfo_children():
        widget.destroy()

    tk.Label(root_frame, text="Formulir Data Diri", font=("Arial", 18, "bold"),
             bg="green", fg="orange", padx=10, pady=10).pack(pady=20)

    fields = {}

    def buat_input(label_text, key):
        frame = tk.Frame(root_frame)
        frame.pack(pady=5)
        label = tk.Label(frame, text=label_text, font=("Arial", 12), bg="light blue", fg="green", width=20, anchor='w')
        label.pack(side=tk.LEFT, padx=5)
        entry = tk.Entry(frame, font=("Arial", 12), width=30)
        entry.pack(side=tk.LEFT, padx=5)
        fields[key] = entry

    buat_input("Nama", "nama")
    buat_input("Usia", "usia")
    buat_input("Jenis Kelamin (L/P)", "jenis_kelamin")
    buat_input("Tinggi Badan (cm)", "tinggi")
    buat_input("Berat Badan (kg)", "berat")

    def simpan_data():
        try:
            nama = fields["nama"].get().strip()
            usia_str = fields["usia"].get().strip()
            jenis_kelamin = fields["jenis_kelamin"].get().strip()
            tinggi_str = fields["tinggi"].get().strip()
            berat_str = fields["berat"].get().strip()

            # Validasi angka
            if not usia_str.isdigit():
                raise ValueError("Usia harus berupa angka bulat.")
            if not tinggi_str.replace('.', '', 1).isdigit():
                raise ValueError("Tinggi harus berupa angka.")
            if not berat_str.replace('.', '', 1).isdigit():
                raise ValueError("Berat harus berupa angka.")

            usia = int(usia_str)
            tinggi = float(tinggi_str)
            berat = float(berat_str)

            if not nama or not jenis_kelamin:
                raise ValueError("Nama dan Jenis Kelamin tidak boleh kosong.")

            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            cursor.execute("""
                INSERT INTO data_diri (nama, usia, jenis_kelamin, tinggi, berat)
                VALUES (?, ?, ?, ?, ?)
            """, (nama, usia, jenis_kelamin, tinggi, berat))
            conn.commit()
            conn.close()

            messagebox.showinfo("Sukses", "Data berhasil disimpan.")
            for entry in fields.values():
                entry.delete(0, tk.END)

        except ValueError as ve:
            messagebox.showerror("Validasi Gagal", str(ve))
        except Exception as e:
            messagebox.showerror("Error", f"Terjadi kesalahan: {str(e)}")

    # Tombol simpan
    tk.Button(root_frame, text="Simpan Data", font=("Arial", 12),
              bg="#4CAF50", fg="white", command=simpan_data).pack(pady=20)

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

✅ Penjelasan Validasi

  • usia_str.isdigit() → memastikan usia adalah bilangan bulat.
  • tinggi_str.replace('.', '', 1).isdigit() → validasi angka pecahan seperti 170.5
  • Semua input dikosongkan kembali dengan entry.delete(0, tk.END) setelah berhasil simpan.

Kalau sudah sesuai, saya siap bantu lanjut ke fitur berikutnya seperti edit data pengguna atau menampilkan data. Mau dilanjutkan?


Buatkan satu tombol lagi di antara tombol "Simpan data" dan tombol "Kembali" yaitu tombol "Edit Data" untuk mengedit (memperbarui) data diri pengguna. Dengan begitu, user bisa memperbarui data dirinya dengan menekan tombol "Edit Data" ini, Untuk itu tolong tambahkan fitur Edit Data Pengguna agar pengguna dapat mengubah data diri yang sebelumnya telah disimpan ke database SQLite.

Bagus, kita lanjutkan! ๐Ÿ™Œ

๐ŸŽฏ Tujuan:

Ketika tombol "Edit Data" ditekan, data pengguna yang terakhir disimpan di database akan ditampilkan kembali ke dalam Entry untuk diedit, lalu setelah diubah, pengguna bisa tekan "Simpan Perubahan".


✅ Fitur "Edit Data Pengguna"

Kita akan lakukan perubahan berikut:

  1. Tambah tombol "Edit Data" di bawah tombol "Simpan Data".
  2. Ketika ditekan, sistem akan:
    • Mengambil data terakhir dari database
    • Menampilkannya di form
    • Mengubah tombol "Simpan Data" menjadi "Simpan Perubahan" sementara

✅ Kode Lengkap Final sub_menu_data_diri.py (dengan fitur Edit)

import tkinter as tk
from tkinter import messagebox
import sqlite3
import os

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

def init_db():
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    conn = sqlite3.connect(DB_PATH)
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS data_diri (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            nama TEXT NOT NULL,
            usia INTEGER NOT NULL,
            jenis_kelamin TEXT,
            tinggi REAL NOT NULL,
            berat REAL NOT NULL
        )
    """)
    conn.commit()
    conn.close()

def show_sub_menu_data_diri(root_frame):
    from menu_profil_kesehatan import show_menu_profil_kesehatan

    init_db()
    for widget in root_frame.winfo_children():
        widget.destroy()

    tk.Label(root_frame, text="Formulir Data Diri", font=("Arial", 18, "bold"),
             bg="green", fg="orange", padx=10, pady=10).pack(pady=20)

    fields = {}
    current_edit_id = [None]  # gunakan list agar bisa dimodifikasi di nested function

    def buat_input(label_text, key):
        frame = tk.Frame(root_frame)
        frame.pack(pady=5)
        label = tk.Label(frame, text=label_text, font=("Arial", 12), bg="light blue", fg="green", width=20, anchor='w')
        label.pack(side=tk.LEFT, padx=5)
        entry = tk.Entry(frame, font=("Arial", 12), width=30)
        entry.pack(side=tk.LEFT, padx=5)
        fields[key] = entry

    buat_input("Nama", "nama")
    buat_input("Usia", "usia")
    buat_input("Jenis Kelamin (L/P)", "jenis_kelamin")
    buat_input("Tinggi Badan (cm)", "tinggi")
    buat_input("Berat Badan (kg)", "berat")

    def bersihkan_entry():
        for entry in fields.values():
            entry.delete(0, tk.END)
        current_edit_id[0] = None
        tombol_simpan.config(text="Simpan Data")

    def ambil_data_form():
        nama = fields["nama"].get().strip()
        usia_str = fields["usia"].get().strip()
        jenis_kelamin = fields["jenis_kelamin"].get().strip()
        tinggi_str = fields["tinggi"].get().strip()
        berat_str = fields["berat"].get().strip()

        # Validasi angka
        if not usia_str.isdigit():
            raise ValueError("Usia harus berupa angka bulat.")
        if not tinggi_str.replace('.', '', 1).isdigit():
            raise ValueError("Tinggi harus berupa angka.")
        if not berat_str.replace('.', '', 1).isdigit():
            raise ValueError("Berat harus berupa angka.")
        if not nama or not jenis_kelamin:
            raise ValueError("Nama dan Jenis Kelamin tidak boleh kosong.")

        return (
            nama,
            int(usia_str),
            jenis_kelamin,
            float(tinggi_str),
            float(berat_str)
        )

    def simpan_data():
        try:
            data = ambil_data_form()
            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()

            if current_edit_id[0] is not None:
                # UPDATE data
                cursor.execute("""
                    UPDATE data_diri SET nama=?, usia=?, jenis_kelamin=?, tinggi=?, berat=?
                    WHERE id=?
                """, data + (current_edit_id[0],))
                messagebox.showinfo("Sukses", "Data berhasil diperbarui.")
            else:
                # INSERT data
                cursor.execute("""
                    INSERT INTO data_diri (nama, usia, jenis_kelamin, tinggi, berat)
                    VALUES (?, ?, ?, ?, ?)
                """, data)
                messagebox.showinfo("Sukses", "Data berhasil disimpan.")

            conn.commit()
            conn.close()
            bersihkan_entry()
        except ValueError as ve:
            messagebox.showerror("Validasi Gagal", str(ve))
        except Exception as e:
            messagebox.showerror("Error", f"Terjadi kesalahan: {str(e)}")

    def edit_data():
        try:
            conn = sqlite3.connect(DB_PATH)
            cursor = conn.cursor()
            cursor.execute("SELECT * FROM data_diri ORDER BY id DESC LIMIT 1")
            result = cursor.fetchone()
            conn.close()

            if result:
                current_edit_id[0] = result[0]  # Simpan id yang sedang diedit
                fields["nama"].delete(0, tk.END)
                fields["nama"].insert(0, result[1])
                fields["usia"].delete(0, tk.END)
                fields["usia"].insert(0, str(result[2]))
                fields["jenis_kelamin"].delete(0, tk.END)
                fields["jenis_kelamin"].insert(0, result[3])
                fields["tinggi"].delete(0, tk.END)
                fields["tinggi"].insert(0, str(result[4]))
                fields["berat"].delete(0, tk.END)
                fields["berat"].insert(0, str(result[5]))
                tombol_simpan.config(text="Simpan Perubahan")
            else:
                messagebox.showinfo("Info", "Belum ada data yang dapat diedit.")
        except Exception as e:
            messagebox.showerror("Error", f"Gagal mengambil data: {str(e)}")

    # Tombol Simpan / Simpan Perubahan
    tombol_simpan = tk.Button(root_frame, text="Simpan Data", font=("Arial", 12),
                              bg="#4CAF50", fg="white", command=simpan_data)
    tombol_simpan.pack(pady=10)

    # Tombol Edit Data
    tk.Button(root_frame, text="Edit Data", font=("Arial", 12),
              bg="orange", fg="white", command=edit_data).pack(pady=5)

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

✅ Struktur Tombol

[Simpan Data]   ← Menyimpan baru atau simpan perubahan
[Edit Data]     ← Memuat data terakhir ke form untuk diedit
[Kembali]

๐Ÿ” Alur:

  1. User isi data ➝ klik Simpan Data.
  2. User klik Edit Data ➝ data sebelumnya otomatis tampil.
  3. User ubah ➝ klik Simpan Perubahan.

Siap lanjut ke fitur berikutnya? Misalnya:

  • Menampilkan daftar riwayat input
  • Validasi jenis kelamin
  • Hapus data

Silakan beri instruksi selanjutnya.


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 sub_menu_data_diri import show_sub_menu_data_diri


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

    label_judul = tk.Label(root_frame, text="Profil Kesehatan", font=("Arial", 18, "bold"), bg="green", fg="orange", padx=10, pady=10)

    label_judul.pack(pady=20)


    # Submenu tombol

    submenus = [

        ("Data Diri", lambda: show_sub_menu_data_diri(root_frame)),

        # Bisa tambah lagi: ("Hitung BMI", func_lainnya), dll.

    ]


    for label, command in submenus:

        lbl = tk.Label(root_frame, text=label, font=("Arial", 12), bg="light blue", fg="green")

        lbl.pack(pady=5)

        btn = tk.Button(root_frame, text=f"Buka {label}", command=command, font=("Arial", 12), bg="#4CAF50", fg="white")

        btn.pack(pady=5)


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

Kode programnya adalah berikut:


# Sub Meny Data Diri

import tkinter as tk

from tkinter import messagebox

import sqlite3

import os


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


def init_db():

    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)

    conn = sqlite3.connect(DB_PATH)

    cursor = conn.cursor()

    cursor.execute("""

        CREATE TABLE IF NOT EXISTS data_diri (

            id INTEGER PRIMARY KEY AUTOINCREMENT,

            nama TEXT NOT NULL,

            usia INTEGER NOT NULL,

            jenis_kelamin TEXT,

            tinggi REAL NOT NULL,

            berat REAL NOT NULL

        )

    """)

    conn.commit()

    conn.close()


def show_sub_menu_data_diri(root_frame):

    from menu_profil_kesehatan import show_menu_profil_kesehatan


    init_db()

    for widget in root_frame.winfo_children():

        widget.destroy()


    tk.Label(root_frame, text="Formulir Data Diri", font=("Arial", 18, "bold"),

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


    fields = {}

    current_edit_id = [None]  # gunakan list agar bisa dimodifikasi di nested function


    def buat_input(label_text, key):

        frame = tk.Frame(root_frame)

        frame.pack(pady=5)

        label = tk.Label(frame, text=label_text, font=("Arial", 8), bg="light blue", fg="dark green", width=16, anchor='w')

        label.pack(side=tk.LEFT, padx=5)

        entry = tk.Entry(frame, font=("Arial", 8), width=30)

        entry.pack(side=tk.LEFT, padx=5)

        fields[key] = entry


    buat_input("Nama", "nama")

    buat_input("Usia", "usia")

    buat_input("Jenis Kelamin (L/P)", "jenis_kelamin")

    buat_input("Tinggi Badan (cm)", "tinggi")

    buat_input("Berat Badan (kg)", "berat")


    def bersihkan_entry():

        for entry in fields.values():

            entry.delete(0, tk.END)

        current_edit_id[0] = None

        tombol_simpan.config(text="Simpan Data")


    def ambil_data_form():

        nama = fields["nama"].get().strip()

        usia_str = fields["usia"].get().strip()

        jenis_kelamin = fields["jenis_kelamin"].get().strip()

        tinggi_str = fields["tinggi"].get().strip()

        berat_str = fields["berat"].get().strip()


        # Validasi angka

        if not usia_str.isdigit():

            raise ValueError("Usia harus berupa angka bulat.")

        if not tinggi_str.replace('.', '', 1).isdigit():

            raise ValueError("Tinggi harus berupa angka.")

        if not berat_str.replace('.', '', 1).isdigit():

            raise ValueError("Berat harus berupa angka.")

        if not nama or not jenis_kelamin:

            raise ValueError("Nama dan Jenis Kelamin tidak boleh kosong.")


        return (

            nama,

            int(usia_str),

            jenis_kelamin,

            float(tinggi_str),

            float(berat_str)

        )


    def simpan_data():

        try:

            data = ambil_data_form()

            conn = sqlite3.connect(DB_PATH)

            cursor = conn.cursor()


            if current_edit_id[0] is not None:

                # UPDATE data

                cursor.execute("""

                    UPDATE data_diri SET nama=?, usia=?, jenis_kelamin=?, tinggi=?, berat=?

                    WHERE id=?

                """, data + (current_edit_id[0],))

                messagebox.showinfo("Sukses", "Data berhasil diperbarui.")

            else:

                # INSERT data

                cursor.execute("""

                    INSERT INTO data_diri (nama, usia, jenis_kelamin, tinggi, berat)

                    VALUES (?, ?, ?, ?, ?)

                """, data)

                messagebox.showinfo("Sukses", "Data berhasil disimpan.")


            conn.commit()

            conn.close()

            bersihkan_entry()

        except ValueError as ve:

            messagebox.showerror("Validasi Gagal", str(ve))

        except Exception as e:

            messagebox.showerror("Error", f"Terjadi kesalahan: {str(e)}")


    def edit_data():

        try:

            conn = sqlite3.connect(DB_PATH)

            cursor = conn.cursor()

            cursor.execute("SELECT * FROM data_diri ORDER BY id DESC LIMIT 1")

            result = cursor.fetchone()

            conn.close()


            if result:

                current_edit_id[0] = result[0]  # Simpan id yang sedang diedit

                fields["nama"].delete(0, tk.END)

                fields["nama"].insert(0, result[1])

                fields["usia"].delete(0, tk.END)

                fields["usia"].insert(0, str(result[2]))

                fields["jenis_kelamin"].delete(0, tk.END)

                fields["jenis_kelamin"].insert(0, result[3])

                fields["tinggi"].delete(0, tk.END)

                fields["tinggi"].insert(0, str(result[4]))

                fields["berat"].delete(0, tk.END)

                fields["berat"].insert(0, str(result[5]))

                tombol_simpan.config(text="Simpan Perubahan")

            else:

                messagebox.showinfo("Info", "Belum ada data yang dapat diedit.")

        except Exception as e:

            messagebox.showerror("Error", f"Gagal mengambil data: {str(e)}")


    # Tombol Simpan / Simpan Perubahan

    tombol_simpan = tk.Button(root_frame, text="Simpan Data", font=("Arial", 12),

                              bg="#4CAF50", fg="white", command=simpan_data)

    tombol_simpan.pack(pady=10)


    # Tombol Edit Data

    tk.Button(root_frame, text="Edit Data", font=("Arial", 12),

              bg="orange", fg="white", command=edit_data).pack(pady=5)


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

.

Bersambung Ke: Konten Sub Menu "Berat & Tinggi Badan"



Comments

Popular posts from this blog

Isi Menu "Setting"

Isi Menu "Riwayat Aktivitas" (Bagian 2)