Untitled
unknown
plain_text
2 years ago
39 kB
7
Indexable
import sqlite3
import sys
import numpy as np
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QApplication, QWidget, QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QFormLayout, \
QLineEdit, QTableWidget, QTableWidgetItem, QTabWidget, QMenu, QAction, QComboBox, QButtonGroup, QLabel, QRadioButton
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
def create_connection():
try:
return sqlite3.connect('nutrition.db')
except sqlite3.Error as e:
print(e)
return None
def create_table(conn):
try:
cursor = conn.cursor()
cursor.execute("""CREATE TABLE IF NOT EXISTS foods (
name TEXT NOT NULL,
calories REAL,
lipids REAL,
carbohydrates REAL,
protein REAL,
price REAL
);""")
conn.commit()
except sqlite3.Error as e:
print(e)
def insert_food(conn, food):
try:
cursor = conn.cursor()
cursor.execute("INSERT INTO foods(name, calories, lipids, carbohydrates, protein, price) VALUES (?, ?, ?, ?, ?, ?)", food)
conn.commit()
except sqlite3.Error as e:
print(e)
def get_foods(conn):
try:
cursor = conn.cursor()
cursor.execute("SELECT * FROM foods ORDER BY name ASC")
return cursor.fetchall()
except sqlite3.Error as e:
print(e)
return []
def delete_food(conn, food_name):
try:
cursor = conn.cursor()
cursor.execute("DELETE FROM foods WHERE name = ?", (food_name,))
conn.commit()
except sqlite3.Error as e:
print(e)
def update_food(conn, old_name, new_food):
try:
cursor = conn.cursor()
cursor.execute("""UPDATE foods
SET name = ?, calories = ?, lipids = ?, carbohydrates = ?, protein = ?, price = ?
WHERE name = ?""",
(*new_food, old_name))
conn.commit()
except sqlite3.Error as e:
print(e)
def create_progress_table(conn):
try:
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS progress (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
weight REAL,
body_fat REAL,
muscle_mass REAL,
waist_size REAL, -- Add waist_size column
chest_size REAL,
thigh_size REAL,
biceps_size REAL,
notes TEXT
);
""")
conn.commit()
except sqlite3.Error as e:
print(e)
def insert_progress(conn, progress):
try:
cursor = conn.cursor()
cursor.execute("INSERT INTO progress(date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", progress)
conn.commit()
except sqlite3.Error as e:
print(e)
def get_progress(conn):
try:
cursor = conn.cursor()
cursor.execute("SELECT * FROM progress ORDER BY date ASC")
return cursor.fetchall()
except sqlite3.Error as e:
print(e)
return []
def delete_progress(conn, progress_id):
try:
cursor = conn.cursor()
cursor.execute("DELETE FROM progress WHERE id = ?", (progress_id,))
conn.commit()
except sqlite3.Error as e:
print(e)
def update_progress(conn, progress_id, progress):
try:
cursor = conn.cursor()
cursor.execute("""
UPDATE progress
SET date = ?, weight = ?, body_fat = ?, muscle_mass = ?, waist_size = ?, chest_size = ?, Thigh_size = ?, Biceps_size = ?, notes = ?
WHERE id = ?
""", (*progress, progress_id))
conn.commit()
except sqlite3.Error as e:
print(e)
class AddFoodDialog(QDialog):
def __init__(self, parent=None, food=None):
super(AddFoodDialog, self).__init__(parent)
self.setWindowTitle('Add Food Item' if food is None else 'Edit Food Item')
self.layout = QFormLayout(self)
self.food = food
self.nameEdit = QLineEdit(self)
self.caloriesEdit = QLineEdit(self)
self.lipidsEdit = QLineEdit(self)
self.carbsEdit = QLineEdit(self)
self.proteinEdit = QLineEdit(self)
self.priceEdit = QLineEdit(self)
self.nameEdit.setStyleSheet("background-color: lightyellow; font-weight: bold;")
if food:
self.nameEdit.setText(food[0])
self.caloriesEdit.setText(str(food[1]))
self.lipidsEdit.setText(str(food[2]))
self.carbsEdit.setText(str(food[3]))
self.proteinEdit.setText(str(food[4]))
self.priceEdit.setText(str(food[5]))
self.layout.addRow('Name:', self.nameEdit)
self.layout.addRow('Calories:', self.caloriesEdit)
self.layout.addRow('Lipids:', self.lipidsEdit)
self.layout.addRow('Carbohydrates:', self.carbsEdit)
self.layout.addRow('Protein:', self.proteinEdit)
self.layout.addRow('Price:', self.priceEdit)
self.addButton = QPushButton('Add' if food is None else 'Update', self)
self.cancelButton = QPushButton('Cancel', self)
self.addButton.clicked.connect(self.add_food)
self.cancelButton.clicked.connect(self.reject)
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.addButton)
buttonLayout.addWidget(self.cancelButton)
self.layout.addRow(buttonLayout)
def add_food(self):
try:
name = self.nameEdit.text()
calories = float(self.caloriesEdit.text())
lipids = float(self.lipidsEdit.text())
carbs = float(self.carbsEdit.text())
protein = float(self.proteinEdit.text())
price = float(self.priceEdit.text())
food = (name, calories, lipids, carbs, protein, price)
if self.food:
old_name = self.food[0]
update_food(conn, old_name, food)
else:
insert_food(conn, food)
self.accept() # Close the dialog on success
except ValueError:
# Handle invalid input
pass
class FoodDatabaseDialog(QDialog):
foodAdded = pyqtSignal() # Signal to emit when food is added or updated
foodDeleted = pyqtSignal() # New signal for when a food is deleted
def __init__(self, parent=None):
super(FoodDatabaseDialog, self).__init__(parent)
self.setWindowTitle('Food Database')
self.setGeometry(300, 300, 500, 400)
self.layout = QVBoxLayout(self)
addButton = QPushButton('Add Food', self)
deleteButton = QPushButton('Delete Selected Food', self)
addButton.setStyleSheet("background-color: navy; color: white;")
deleteButton.setStyleSheet("background-color: red; color: white;")
addButton.clicked.connect(self.open_add_dialog)
deleteButton.clicked.connect(self.delete_food)
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(addButton)
buttonLayout.addWidget(deleteButton)
self.layout.addLayout(buttonLayout)
self.table = QTableWidget(self)
self.table.setColumnCount(6)
self.table.setHorizontalHeaderLabels(['Name', 'Calories', 'Lipids', 'Carbohydrates', 'Protein', 'Price'])
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.show_context_menu)
self.update_table()
self.layout.addWidget(self.table)
def show_context_menu(self, position):
menu = QMenu(self)
edit_action = QAction("Edit", self)
edit_action.triggered.connect(self.edit_food)
menu.addAction(edit_action)
menu.exec_(self.table.mapToGlobal(position))
def edit_food(self):
selected_row = self.table.currentRow()
if selected_row >= 0:
name = self.table.item(selected_row, 0).text()
calories = float(self.table.item(selected_row, 1).text())
lipids = float(self.table.item(selected_row, 2).text())
carbs = float(self.table.item(selected_row, 3).text())
protein = float(self.table.item(selected_row, 4).text())
price = float(self.table.item(selected_row, 5).text())
food = (name, calories, lipids, carbs, protein, price)
dialog = AddFoodDialog(self, food)
if dialog.exec_():
self.update_table()
self.foodAdded.emit() # Emit the signal after the dialog has successfully added or edited a food
def open_add_dialog(self):
dialog = AddFoodDialog(self)
if dialog.exec_():
self.update_table()
self.foodAdded.emit() # Emit the signal after the dialog has successfully added a food
def delete_food(self):
selected_row = self.table.currentRow()
if selected_row >= 0:
food_name = self.table.item(selected_row, 0).text()
delete_food(conn, food_name)
self.update_table()
self.foodDeleted.emit() # Emit the signal after the food is deleted
def update_table(self):
foods = get_foods(conn)
self.table.setRowCount(len(foods))
for i, (name, calories, lipids, carbs, protein, price) in enumerate(foods):
nameItem = QTableWidgetItem(name)
nameItem.setBackground(QColor(173, 216, 230))
self.table.setItem(i, 0, nameItem)
self.table.setItem(i, 1, QTableWidgetItem(str(calories)))
self.table.setItem(i, 2, QTableWidgetItem(str(lipids)))
self.table.setItem(i, 3, QTableWidgetItem(str(carbs)))
self.table.setItem(i, 4, QTableWidgetItem(str(protein)))
self.table.setItem(i, 5, QTableWidgetItem(str(price)))
class MealPlannerDialog(QDialog):
def __init__(self, parent=None):
super(MealPlannerDialog, self).__init__(parent)
self.setWindowTitle('Meal Planner')
self.setGeometry(300, 300, 600, 500)
self.layout = QVBoxLayout(self)
self.conn = create_connection()
self.genderCombo = QComboBox(self)
self.genderCombo.addItems(['Male', 'Female'])
self.weightEdit = QLineEdit(self)
self.heightEdit = QLineEdit(self)
self.ageEdit = QLineEdit(self)
self.bodyFatEdit = QLineEdit(self)
self.activityCombo = QComboBox(self)
self.activityCombo.addItems([
'Sedentary (little or no exercise)',
'Lightly active (exercise 1-3 times/week)',
'Active (daily exercise or intense exercise 3-4 times/week)',
'Very active (intense exercise 6-7 times/week)',
'Super active (very intense exercise daily, or physical job)'
])
self.primaryGoalCombo = QComboBox(self)
self.primaryGoalCombo.addItems([
'Build Muscle (Male - Body Fat % ≤ 8-12, Female - Body Fat % ≤ 18-22)',
'Lose Fat & Build Muscle Equally (Male - Body Fat % ≈ 12-18, Female - Body Fat % ≈ 22-28)',
'Lose Fat (Male - Body Fat % ≥ 18-20+, Female - Body Fat % ≥ 28-30+)'
])
self.trainingExperienceGroup = QButtonGroup(self)
self.beginnerRadio = QRadioButton("Beginner (0-2 years of lifting)")
self.intermediateRadio = QRadioButton("Intermediate (2-5 years of lifting)")
self.advancedRadio = QRadioButton("Advanced (5+ years of lifting)")
self.trainingExperienceGroup.addButton(self.beginnerRadio)
self.trainingExperienceGroup.addButton(self.intermediateRadio)
self.trainingExperienceGroup.addButton(self.advancedRadio)
calculatorLayout = QFormLayout()
calculatorLayout.addRow('Gender:', self.genderCombo)
calculatorLayout.addRow('Weight (kg):', self.weightEdit)
calculatorLayout.addRow('Height (cm):', self.heightEdit)
calculatorLayout.addRow('Age (years):', self.ageEdit)
calculatorLayout.addRow('Body Fat %:', self.bodyFatEdit)
calculatorLayout.addRow('Activity Level:', self.activityCombo)
calculatorLayout.addRow('Primary Goal:', self.primaryGoalCombo)
calculatorLayout.addRow("Training Experience:", self.beginnerRadio)
calculatorLayout.addRow("", self.intermediateRadio)
calculatorLayout.addRow("", self.advancedRadio)
self.layout.addLayout(calculatorLayout)
self.totalPriceLabel = QLabel('Total Price: €0.00', self) # Add this line
self.layout.addWidget(self.totalPriceLabel) # Add this line
self.needsDisplay = QLabel('Daily Needs: ', self)
calculatorLayout.addRow(self.needsDisplay)
self.mealTypeCombo = QComboBox(self)
self.mealTypeCombo.addItems(['Breakfast', 'Lunch', 'Snack', 'Dinner'])
self.foodCombo = QComboBox(self)
self.foodCombo.setMinimumWidth(200) # Set the minimum width to 200 pixels or another value that fits your needs
self.quantityEdit = QLineEdit(self)
self.addButton = QPushButton('Add Meal', self)
self.clearAllButton = QPushButton('Clear All', self)
self.deleteMealButton = QPushButton('Delete Meal', self)
self.clearAllButton.clicked.connect(self.clear_meals)
self.clearAllButton.setFixedSize(100, 30)
self.addButton.clicked.connect(self.add_food_to_meal)
self.deleteMealButton.clicked.connect(self.delete_selected_meal)
self.mealTable = QTableWidget(self)
self.mealTable.setColumnCount(8) # Adjusted for detailed nutritional info
self.mealTable.setHorizontalHeaderLabels(
['Meal', 'Food', 'Quantity (g)', 'Calories (kcal)', 'Proteins (g)', 'Carbs (g)', 'Fats (g)', 'Price (€)'])
# Layout for Meal Creation
mealCreationLayout = QHBoxLayout()
mealCreationLayout.addWidget(self.mealTypeCombo)
mealCreationLayout.addWidget(self.foodCombo, 1) # Stretch factor for better spacing
mealCreationLayout.addWidget(self.quantityEdit)
mealCreationLayout.addWidget(self.addButton)
mealCreationLayout.addWidget(self.deleteMealButton) # Add the delete button to the layout
mealCreationLayout.addWidget(self.clearAllButton)
self.layout.addLayout(mealCreationLayout)
self.layout.addWidget(self.mealTable)
# Ensure this is called to fetch database information
self.populate_food_combo()
self.total_calories = 0.0
self.total_proteins = 0.0
self.total_carbs = 0.0
self.total_fats = 0.0
self.daily_caloric_needs = 0.0
self.layout.addLayout(mealCreationLayout)
self.layout.addWidget(self.mealTable)
# Connect signals to slots
self.connect_signals()
def connect_signals(self):
# Connect signals from input widgets to the calculate_needs method
self.genderCombo.currentIndexChanged.connect(self.calculate_needs)
self.weightEdit.textChanged.connect(self.calculate_needs)
self.heightEdit.textChanged.connect(self.calculate_needs)
self.ageEdit.textChanged.connect(self.calculate_needs)
self.bodyFatEdit.textChanged.connect(self.calculate_needs)
self.activityCombo.currentIndexChanged.connect(self.calculate_needs)
self.primaryGoalCombo.currentIndexChanged.connect(self.calculate_needs)
self.trainingExperienceGroup.buttonClicked.connect(self.calculate_needs)
def populate_food_combo(self):
foods = get_foods(self.conn)
self.foodCombo.clear() # Clear existing items before adding new ones
for food in foods:
self.foodCombo.addItem(food[0])
def add_food_to_meal(self):
try:
meal_type = self.mealTypeCombo.currentText()
food_name = self.foodCombo.currentText()
# Check if quantity input is empty
if self.quantityEdit.text().strip() == '':
raise ValueError("Quantity cannot be empty")
quantity = float(self.quantityEdit.text())
food_nutrition = self.get_nutritional_values(food_name, quantity)
# Calculate total price
total_price = food_nutrition['price'] * quantity
# Update total nutritional values and total price
self.total_calories += food_nutrition['calories']
self.total_proteins += food_nutrition['proteins']
self.total_carbs += food_nutrition['carbs']
self.total_fats += food_nutrition['fats']
self.update_intake_ratio_display()
# Add meal data to the table
row_position = self.mealTable.rowCount()
self.mealTable.insertRow(row_position)
self.mealTable.setItem(row_position, 0, QTableWidgetItem(meal_type))
self.mealTable.setItem(row_position, 1, QTableWidgetItem(food_name))
self.mealTable.setItem(row_position, 2, QTableWidgetItem(str(quantity)))
self.mealTable.setItem(row_position, 3, QTableWidgetItem(str(food_nutrition['calories'])))
self.mealTable.setItem(row_position, 4, QTableWidgetItem(str(food_nutrition['proteins'])))
self.mealTable.setItem(row_position, 5, QTableWidgetItem(str(food_nutrition['carbs'])))
self.mealTable.setItem(row_position, 6, QTableWidgetItem(str(food_nutrition['fats'])))
self.mealTable.setItem(row_position, 7, QTableWidgetItem(str(total_price))) # Display total price
# Recalculate nutritional needs
self.calculate_needs()
# Update total price label
self.update_total_price()
except ValueError as ve:
print(f"Error adding food to meal: {ve}")
def update_total_price(self):
total_price = sum(float(self.mealTable.item(row, 7).text()) for row in range(self.mealTable.rowCount()))
self.totalPriceLabel.setText(f'Total Price: €{total_price:.2f}') # Update the label here
def get_nutritional_values(self, food_name, quantity):
food_data = next((food for food in get_foods(self.conn) if food[0] == food_name), None)
if food_data:
return {
'calories': food_data[1] * quantity,
'proteins': food_data[4] * quantity,
'carbs': food_data[3] * quantity,
'fats': food_data[2] * quantity,
'price': food_data[5] # Fetch price from database
}
else:
return {'calories': 0, 'proteins': 0, 'carbs': 0, 'fats': 0, 'price': 0}
def update_intake_ratio_display(self):
if self.daily_caloric_needs > 0:
# Assuming self.daily_protein_needs, self.daily_carbs_needs, and self.daily_fats_needs are also calculated and stored
caloric_ratio = self.total_calories / self.daily_caloric_needs
protein_ratio = self.total_proteins / self.daily_protein_needs if self.daily_protein_needs > 0 else 0
carbs_ratio = self.total_carbs / self.daily_carbs_needs if self.daily_carbs_needs > 0 else 0
fats_ratio = self.total_fats / self.daily_fats_needs if self.daily_fats_needs > 0 else 0
self.needsDisplay.setText(f"Daily Nutritional Needs:\n"
f"Calories: {self.total_calories:.2f} kcal / {self.daily_caloric_needs:.2f} kcal\n"
f"Protein: {self.total_proteins:.2f} g / {self.daily_protein_needs:.2f} g\n"
f"Carbs: {self.total_carbs:.2f} g / {self.daily_carbs_needs:.2f} g\n"
f"Fats: {self.total_fats:.2f} g / {self.daily_fats_needs:.2f} g")
else:
self.needsDisplay.setText("Daily Nutritional Needs: N/A")
def calculate_needs(self):
try:
gender = self.genderCombo.currentText()
weight = float(self.weightEdit.text()) # Weight in kilograms
height = float(self.heightEdit.text()) # Height in centimeters
age = int(self.ageEdit.text())
activity_level = self.activityCombo.currentText()
primary_goal = self.primaryGoalCombo.currentText()
training_experience = self.get_selected_training_experience()
# Calculate BMR using Mifflin-St Jeor formula
bmr = 10 * weight + 6.25 * height - 5 * age + (5 if gender == 'Male' else -161)
# Adjust for activity level
activity_factors = {
'Sedentary (little or no exercise)': 1.2,
'Lightly active (exercise 1-3 times/week)': 1.375,
'Active (daily exercise or intense exercise 3-4 times/week)': 1.55,
'Very active (intense exercise 6-7 times/week)': 1.725,
'Super active (very intense exercise daily, or physical job)': 1.9
}
maintenance_calories = bmr * activity_factors[activity_level]
# Adjust caloric needs based on primary goal and training experience
if 'Lose Fat & Build Muscle Equally' in primary_goal:
self.daily_caloric_needs = maintenance_calories
elif 'Build Muscle' in primary_goal:
if training_experience == 'Beginner (0-2 years of lifting)':
self.daily_caloric_needs = maintenance_calories * 1.25
elif training_experience == 'Intermediate (2-5 years of lifting)':
self.daily_caloric_needs = maintenance_calories * 1.175
else: # Advanced (5+ years of lifting)
self.daily_caloric_needs = maintenance_calories * 1.15
else: # 'Lose Fat'
self.daily_caloric_needs = maintenance_calories * 0.85 # Adjust as needed
# Example calculations for protein, carbs, and fat needs
self.daily_protein_needs = weight * 1.6 # Example: 1.6g per kg of body weight
self.daily_carbs_needs = (self.daily_caloric_needs * 0.5) / 4 # Example: 50% of calories from carbs
self.daily_fats_needs = (self.daily_caloric_needs * 0.25) / 9 # Example: 25% of calories from fats
self.needsDisplay.setText(f"Daily Nutritional Needs:\n"
f"Calories: {self.daily_caloric_needs:.2f} kcal\n"
f"Protein: {self.daily_protein_needs:.2f} g\n"
f"Carbs: {self.daily_carbs_needs:.2f} g\n"
f"Fats: {self.daily_fats_needs:.2f} g")
self.update_intake_ratio_display()
except ValueError:
self.needsDisplay.setText("Invalid input. Please enter correct values.")
def get_selected_training_experience(self):
selected_button = self.trainingExperienceGroup.checkedButton()
if selected_button:
return selected_button.text()
return "Unknown"
def delete_selected_meal(self):
selected_row = self.mealTable.currentRow()
if selected_row != -1: # -1 means no row is selected
# Update total price by subtracting the price of the deleted meal
deleted_price = float(self.mealTable.item(selected_row, 7).text())
self.total_calories -= float(self.mealTable.item(selected_row, 3).text())
self.total_proteins -= float(self.mealTable.item(selected_row, 4).text())
self.total_carbs -= float(self.mealTable.item(selected_row, 5).text())
self.total_fats -= float(self.mealTable.item(selected_row, 6).text())
self.mealTable.removeRow(selected_row)
self.update_total_price() # Update the total price after deletion
# Recalculate nutritional needs
self.calculate_needs()
def clear_meals(self):
# Clear the meal table
self.mealTable.setRowCount(0)
# Reset total nutritional values
self.total_calories = 0.0
self.total_proteins = 0.0
self.total_carbs = 0.0
self.total_fats = 0.0
# Update the display
self.update_intake_ratio_display()
# Update the total price label
self.update_total_price()
def update_food_combo(self):
self.foodCombo.clear() # Clear the existing items
self.populate_food_combo() # Repopulate the combo box
def update_total_nutrition(self):
# Reset total nutritional values
self.total_calories = 0.0
self.total_proteins = 0.0
self.total_carbs = 0.0
self.total_fats = 0.0
# Recalculate totals based on remaining items in the table
for row in range(self.mealTable.rowCount()):
# Assuming calories, proteins, carbs, and fats are in columns 3, 4, 5, and 6
self.total_calories += float(self.mealTable.item(row, 3).text())
self.total_proteins += float(self.mealTable.item(row, 4).text())
self.total_carbs += float(self.mealTable.item(row, 5).text())
self.total_fats += float(self.mealTable.item(row, 6).text())
# Update display of totals
self.update_intake_ratio_display()
class AddProgressDialog(QDialog):
def __init__(self, parent=None, progress=None):
super(AddProgressDialog, self).__init__(parent)
self.setWindowTitle('Add Measurement Entry' if progress is None else 'Edit Measurement Entry')
self.layout = QFormLayout(self)
self.progress = progress
self.dateEdit = QLineEdit(self)
self.weightEdit = QLineEdit(self)
self.bodyFatEdit = QLineEdit(self)
self.muscleMassEdit = QLineEdit(self)
self.waistSizeEdit = QLineEdit(self)
self.chestSizeEdit = QLineEdit(self)
self.thighSizeEdit = QLineEdit(self)
self.bicepsSizeEdit = QLineEdit(self)
self.notesEdit = QLineEdit(self) # Define notesEdit
if progress:
self.dateEdit.setText(progress[1])
self.weightEdit.setText(str(progress[2]))
self.bodyFatEdit.setText(str(progress[3]))
self.muscleMassEdit.setText(str(progress[4]))
self.waistSizeEdit.setText(str(progress[5]))
self.chestSizeEdit.setText(str(progress[6]))
self.thighSizeEdit.setText(str(progress[7]))
self.bicepsSizeEdit.setText(str(progress[8]))
self.notesEdit.setText(progress[9]) # Set text for notesEdit
self.layout.addRow('Date:', self.dateEdit)
self.layout.addRow('Weight (kg):', self.weightEdit)
self.layout.addRow('Body Fat (%):', self.bodyFatEdit)
self.layout.addRow('Muscle Mass (%):', self.muscleMassEdit)
self.layout.addRow('Waist Size (cm) :', self.waistSizeEdit)
self.layout.addRow('Chest Size (cm) :', self.chestSizeEdit)
self.layout.addRow('Thigh Size (cm) :', self.thighSizeEdit)
self.layout.addRow('Biceps Size (cm) :', self.bicepsSizeEdit)
self.layout.addRow('Notes:', self.notesEdit) # Add notesEdit to layout
self.addButton = QPushButton('Add' if progress is None else 'Update', self)
self.cancelButton = QPushButton('Cancel', self)
self.addButton.clicked.connect(self.add_progress)
self.cancelButton.clicked.connect(self.reject)
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(self.addButton)
buttonLayout.addWidget(self.cancelButton)
self.layout.addRow(buttonLayout)
def add_progress(self):
try:
date = self.dateEdit.text()
weight = float(self.weightEdit.text())
body_fat = float(self.bodyFatEdit.text())
muscle_mass = float(self.muscleMassEdit.text())
waist_size = float(self.waistSizeEdit.text())
chest_size = float(self.chestSizeEdit.text())
thigh_size = float(self.thighSizeEdit.text())
biceps_size = float(self.bicepsSizeEdit.text())
notes = self.notesEdit.text()
progress = (date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size, notes)
if self.progress:
update_progress(conn, self.progress[0], progress)
else:
insert_progress(conn, progress)
self.accept()
except ValueError:
pass
class ProgressDialog(QDialog):
def __init__(self, parent=None):
super(ProgressDialog, self).__init__(parent)
self.setWindowTitle('Body Measurements Tracker')
self.setGeometry(300, 300, 600, 400)
self.layout = QVBoxLayout(self)
addButton = QPushButton('Add Measurement Entry', self)
deleteButton = QPushButton('Delete Selected Entry', self)
bodyCompChartsButton = QPushButton('Body Composition Charts', self)
bodyMeasurementsChartsButton = QPushButton('Body Measurements Charts', self)
addButton.clicked.connect(self.open_add_dialog)
deleteButton.clicked.connect(self.delete_progress)
bodyCompChartsButton.clicked.connect(self.show_body_composition_charts)
bodyMeasurementsChartsButton.clicked.connect(self.show_body_measurements_charts)
buttonLayout = QHBoxLayout()
buttonLayout.addWidget(addButton)
buttonLayout.addWidget(deleteButton)
self.layout.addLayout(buttonLayout)
chartsButtonLayout = QHBoxLayout()
chartsButtonLayout.addWidget(bodyCompChartsButton)
chartsButtonLayout.addWidget(bodyMeasurementsChartsButton)
self.layout.addLayout(chartsButtonLayout)
self.table = QTableWidget(self)
self.table.setColumnCount(10) # Adjust column count to match the number of columns
self.table.setHorizontalHeaderLabels(['ID', 'Date', 'Weight', 'Body Fat', 'Muscle Mass', 'Waist Size', 'Chest Size', 'Thigh Size', 'Biceps Size', 'Notes'])
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.show_context_menu)
self.update_table()
self.layout.addWidget(self.table)
def show_context_menu(self, position):
menu = QMenu(self)
edit_action = QAction("Edit", self)
edit_action.triggered.connect(self.edit_progress)
menu.addAction(edit_action)
menu.exec_(self.table.mapToGlobal(position))
def edit_progress(self):
selected_row = self.table.currentRow()
if selected_row >= 0:
progress_id = int(self.table.item(selected_row, 0).text())
date = self.table.item(selected_row, 1).text()
weight = float(self.table.item(selected_row, 2).text())
body_fat = float(self.table.item(selected_row, 3).text())
muscle_mass = float(self.table.item(selected_row, 4).text())
waist_size = float(self.table.item(selected_row, 5).text())
chest_size = float(self.table.item(selected_row, 6).text())
thigh_size = float(self.table.item(selected_row, 7).text())
biceps_size = float(self.table.item(selected_row, 8).text())
notes = self.table.item(selected_row, 9).text()
progress = (progress_id, date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size, notes)
dialog = AddProgressDialog(self, progress)
if dialog.exec_():
self.update_table()
def open_add_dialog(self):
dialog = AddProgressDialog(self)
if dialog.exec_():
self.update_table()
def delete_progress(self):
selected_row = self.table.currentRow()
if selected_row >= 0:
progress_id = int(self.table.item(selected_row, 0).text())
delete_progress(conn, progress_id)
self.update_table()
def update_table(self):
progress_data = get_progress(conn)
self.table.setRowCount(len(progress_data))
for i, (progress_id, date, weight, body_fat, muscle_mass, waist_size, chest_size, thigh_size, biceps_size, notes) in enumerate(progress_data):
self.table.setItem(i, 0, QTableWidgetItem(str(progress_id)))
self.table.setItem(i, 1, QTableWidgetItem(date))
self.table.setItem(i, 2, QTableWidgetItem(str(weight)))
self.table.setItem(i, 3, QTableWidgetItem(str(body_fat)))
self.table.setItem(i, 4, QTableWidgetItem(str(muscle_mass)))
self.table.setItem(i, 5, QTableWidgetItem(str(waist_size)))
self.table.setItem(i, 6, QTableWidgetItem(str(chest_size)))
self.table.setItem(i, 7, QTableWidgetItem(str(thigh_size)))
self.table.setItem(i, 8, QTableWidgetItem(str(biceps_size)))
self.table.setItem(i, 9, QTableWidgetItem(notes))
self.table.hideColumn(0)
def show_body_composition_charts(self):
data = self.get_table_data()
dialog = BodyCompositionChartsDialog(data)
dialog.exec_()
def show_body_measurements_charts(self):
# Code to display body measurements charts
pass
def get_table_data(self):
rows = self.table.rowCount()
data = []
for row in range(rows):
date = self.table.item(row, 1).text()
weight = float(self.table.item(row, 2).text())
body_fat = float(self.table.item(row, 3).text())
muscle_mass = float(self.table.item(row, 4).text())
data.append((date, weight, body_fat, muscle_mass))
return data
class BodyCompositionChartsDialog(QDialog):
def __init__(self, data, parent=None):
super(BodyCompositionChartsDialog, self).__init__(parent)
self.setWindowTitle('Body Composition Charts')
self.layout = QVBoxLayout(self)
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.layout.addWidget(self.canvas)
self.plot_data(data)
self.add_vertical_line()
def plot_data(self, data):
dates, weights, body_fats, muscle_masses = zip(*data)
dates = np.array(dates)
weights = np.array(weights)
body_fats = np.array(body_fats)
muscle_masses = np.array(muscle_masses)
self.ax1 = self.fig.add_subplot(211)
self.ax2 = self.fig.add_subplot(212)
# Plot body fat and muscle mass
self.ax1.plot(dates, body_fats, 'ro-', label='Body Fat (%)')
self.ax1.plot(dates, muscle_masses, 'go-', label='Muscle Mass (%)')
self.ax1.legend(loc='center left', bbox_to_anchor=(1, 0.5))
self.ax1.set_xticks([dates[0], dates[-1]])
self.ax1.set_xticklabels([dates[0], dates[-1]])
self.ax1.set_title('Body Fat and Muscle Mass over Time')
self.ax1.set_xlabel('Date')
self.ax1.set_ylim(0, 100) # Ensure y-axis goes from 0 to 100%
# Plot weight
self.ax2.plot(dates, weights, 'bo-', label='Weight (kg)')
self.ax2.legend(loc='center left', bbox_to_anchor=(1, 0.5))
self.ax2.set_xticks([dates[0], dates[-1]])
self.ax2.set_xticklabels([dates[0], dates[-1]])
self.ax2.set_title('Weight over Time')
self.ax2.set_xlabel('Date')
max_weight = max(weights)
self.ax2.set_ylim(0, max_weight * 1.2) # Set y-axis to 20% higher than the maximum weight
self.fig.tight_layout()
self.canvas.draw()
def add_vertical_line(self):
self.vertical_line = None
self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
def on_mouse_move(self, event):
if event.inaxes:
if not self.vertical_line:
self.vertical_line = self.ax1.axvline(x=event.xdata, color='k', linestyle='--')
self.vertical_line2 = self.ax2.axvline(x=event.xdata, color='k', linestyle='--')
else:
# Only update if the difference is significant
if abs(self.vertical_line.get_xdata()[0] - event.xdata) > 0.1:
self.vertical_line.set_xdata([event.xdata]) # Convert to sequence type
self.vertical_line2.set_xdata([event.xdata]) # Convert to sequence type
self.canvas.draw_idle()
else:
if self.vertical_line:
self.vertical_line.remove()
self.vertical_line2.remove()
self.vertical_line = None
self.vertical_line2 = None
self.canvas.draw_idle()
class App(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 800, 600)
self.setWindowTitle('NutriGeniePro')
# Create the tab widget
tabWidget = QTabWidget(self)
foodDatabaseTab = FoodDatabaseDialog()
mealPlannerTab = MealPlannerDialog()
progressTab = ProgressDialog()
# Connect signals to slots if necessary
foodDatabaseTab.foodAdded.connect(mealPlannerTab.update_food_combo)
foodDatabaseTab.foodDeleted.connect(mealPlannerTab.update_food_combo)
# Add tabs to the tab widget
tabWidget.addTab(foodDatabaseTab, "Food Database")
tabWidget.addTab(mealPlannerTab, "Meal Planner")
tabWidget.addTab(progressTab, "Body Measurements Tracker")
# Set the layout
layout = QVBoxLayout(self)
layout.addWidget(tabWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
conn = create_connection()
create_table(conn)
create_progress_table(conn)
mainApp = App()
mainApp.show()
sys.exit(app.exec_())
Editor is loading...
Leave a Comment