第四篇【传奇开心果系列】beeware的Toga开发移动应用示例:健身追踪应用-灵析社区

JOHO

系列博文目录

beeware的Toga开发移动应用示例系列

博文目录

前言

健身追踪应用:使用 Beeware的toga集成库和sqlite3嵌入式数据库开发人员可以开发健康和健身应用程序,如健康追踪应用、锻炼计划应用等。通过与移动设备的传感器和健康数据接口进行交互,可以实现数据收集、分析和展示等功能。

一、记录存储运动活动数据

下面是使用beeware的toga和SQLite3实现健身追踪应用的示例代码:


import toga

from toga.style import Pack

from toga.style.pack import COLUMN, ROW

import sqlite3

class FitnessApp(toga.App):

def startup(self):

self.db_conn = sqlite3.connect('fitness_tracker.db')

self.create_table()

self.main_window = toga.MainWindow(title=self.name)

self.main_window.content = self.build_main_box()

self.main_window.show()

def create_table(self):

cursor = self.db_conn.cursor()

cursor.execute('''

CREATE TABLE IF NOT EXISTS activities (

id INTEGER PRIMARY KEY AUTOINCREMENT,

activity_type TEXT,

time TEXT,

distance REAL,

calories REAL

)

''')

self.db_conn.commit()

def add_activity(self, widget):

activity_type = self.activity_type.value

time = self.time.value

distance = float(self.distance.value)

calories = float(self.calories.value)

cursor = self.db_conn.cursor()

cursor.execute('''

INSERT INTO activities (activity_type, time, distance, calories)

VALUES (?, ?, ?, ?)

''', (activity_type, time, distance, calories))

self.db_conn.commit()

self.activity_type.value = ''

self.time.value = ''

self.distance.value = ''

self.calories.value = ''

def build_main_box(self):

activity_label = toga.Label('运动类型:', style=Pack(padding=(0, 5)))

self.activity_type = toga.TextInput(style=Pack(flex=1))

time_label = toga.Label('时间:', style=Pack(padding=(0, 5)))

self.time = toga.TextInput(style=Pack(flex=1))

distance_label = toga.Label('距离:', style=Pack(padding=(0, 5)))

self.distance = toga.TextInput(style=Pack(flex=1))

calories_label = toga.Label('消耗卡路里:', style=Pack(padding=(0, 5)))

self.calories = toga.TextInput(style=Pack(flex=1))

add_button = toga.Button('添加运动', on_press=self.add_activity, style=Pack(padding=5))

activity_box = toga.Box(children=[activity_label, self.activity_type], style=Pack(direction=ROW, padding=5))

time_box = toga.Box(children=[time_label, self.time], style=Pack(direction=ROW, padding=5))

distance_box = toga.Box(children=[distance_label, self.distance], style=Pack(direction=ROW, padding=5))

calories_box = toga.Box(children=[calories_label, self.calories], style=Pack(direction=ROW, padding=5))

main_box = toga.Box(

children=[activity_box, time_box, distance_box, calories_box, add_button],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

以上代码是一个简单的健身追踪应用示例,使用了beeware的Toga作为GUI库,sqlite3作为数据库存储运动记录。用户可以通过界面输入运动类型、时间、距离和消耗的卡路里,并点击"添加运动"按钮将数据保存到SQLite数据库中。

二、添加添加统计显示功能

要为健身追踪应用添加统计数据分析功能,你可以修改示例代码,添加相应的功能和界面元素。下面是一个简单的示例,展示如何计算每周、每月和每年的运动时长和消耗的卡路里,并在界面上显示统计信息:


import datetime

import calendar

class FitnessApp(toga.App):

# ...

def calculate_weekly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE time >= ? AND time <= ?

''', (self.get_start_of_week(), self.get_end_of_week()))

result = cursor.fetchone()

return result[0], result[1]

def calculate_monthly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE time >= ? AND time <= ?

''', (self.get_start_of_month(), self.get_end_of_month()))

result = cursor.fetchone()

return result[0], result[1]

def calculate_yearly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE time >= ? AND time <= ?

''', (self.get_start_of_year(), self.get_end_of_year()))

result = cursor.fetchone()

return result[0], result[1]

def get_start_of_week(self):

today = datetime.date.today()

start_of_week = today - datetime.timedelta(days=today.weekday())

return start_of_week.isoformat()

def get_end_of_week(self):

today = datetime.date.today()

end_of_week = today + datetime.timedelta(days=6 - today.weekday())

return end_of_week.isoformat()

def get_start_of_month(self):

today = datetime.date.today()

start_of_month = today.replace(day=1)

return start_of_month.isoformat()

def get_end_of_month(self):

today = datetime.date.today()

_, last_day = calendar.monthrange(today.year, today.month)

end_of_month = today.replace(day=last_day)

return end_of_month.isoformat()

def get_start_of_year(self):

today = datetime.date.today()

start_of_year = today.replace(month=1, day=1)

return start_of_year.isoformat()

def get_end_of_year(self):

today = datetime.date.today()

end_of_year = today.replace(month=12, day=31)

return end_of_year.isoformat()

def build_stats_box(self):

weekly_label = toga.Label('每周统计:', style=Pack(padding=(0, 5)))

weekly_time, weekly_calories = self.calculate_weekly_stats()

weekly_stats = toga.Label(f'运动时长: {weekly_time} 小时, 消耗卡路里: {weekly_calories}', style=Pack(padding=(0, 5)))

monthly_label = toga.Label('每月统计:', style=Pack(padding=(0, 5)))

monthly_time, monthly_calories = self.calculate_monthly_stats()

monthly_stats = toga.Label(f'运动时长: {monthly_time} 小时, 消耗卡路里: {monthly_calories}', style=Pack(padding=(0, 5)))

yearly_label = toga.Label('每年统计:', style=Pack(padding=(0, 5)))

yearly_time, yearly_calories = self.calculate_yearly_stats()

yearly_stats = toga.Label(f'运动时长: {yearly_time} 小时, 消耗卡路里: {yearly_calories}', style=Pack(padding=(0, 5)))

stats_box = toga.Box(

children=[weekly_label, weekly_stats, monthly_label, monthly_stats, yearly_label, yearly_stats],

style=Pack(direction=COLUMN, padding=10)

)

return stats_box

def build_main_box(self):

# ...

stats_box = self.build_stats_box()

main_box = toga.Box(

children=[activity_box, time_box, distance_box, calories_box, add_button, stats_box],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

# ...

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

在上述示例中,我们添加了calculate_weekly_stats()calculate_monthly_stats()calculate_yearly_stats()方法来计算每周、每月和每年的运动时长和消耗的卡路里。然后,在build_stats_box()方法中,我们创建了显示统计信息的标签,并将其添加到界面中的stats_box中。最后,将stats_box添加到主界面的布局中。

这样,用户就可以在健身追踪应用中查看每周、每月和每年的运动统计信息了。

三、添加图表显示数据分析功能

要为健身追踪应用添加数据分析功能,你可以使用Python的数据分析库(如pandas和matplotlib)来处理和可视化运动数据。下面是一个示例代码,展示如何使用pandas和matplotlib对健身数据进行分析和绘图:


import pandas as pd

import matplotlib.pyplot as plt

class FitnessApp(toga.App):

# ...

def analyze_data(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT activity_type, SUM(time) as total_time, SUM(calories) as total_calories

FROM activities

GROUP BY activity_type

''')

result = cursor.fetchall()

data = pd.DataFrame(result, columns=['Activity Type', 'Total Time', 'Total Calories'])



# 绘制柱状图

data.plot(x='Activity Type', y='Total Time', kind='bar', legend=False)

plt.title('Total Time Spent on Each Activity')

plt.xlabel('Activity Type')

plt.ylabel('Total Time (hours)')

plt.show()

# 绘制饼图

data.plot(x='Activity Type', y='Total Calories', kind='pie', labels=data['Activity Type'], autopct='%1.1f%%')

plt.title('Total Calories Burned for Each Activity')

plt.ylabel('')

plt.show()

def build_main_box(self):

# ...

analyze_button = toga.Button('数据分析', on_press=self.analyze_data, style=Pack(padding=5))

# ...

main_box = toga.Box(

children=[activity_box, time_box, distance_box, calories_box, add_button, analyze_button, stats_box],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

# ...

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

在上述示例中,我们添加了analyze_data()方法来从数据库中获取运动数据,并使用pandas创建一个DataFrame对象。然后,我们使用matplotlib库来绘制柱状图和饼图,展示每种运动类型的总时长和总消耗卡路里。

build_main_box()方法中,我们创建了一个"数据分析"按钮,并将其添加到主界面的布局中。当用户点击该按钮时,analyze_data()方法会被调用,进行数据分析和绘图操作。

四、增加健身计划管理

要为健身追踪应用添加健身计划管理功能,你可以修改示例代码,添加相应的功能和界面元素。下面是一个简单的示例,展示如何创建、查看和管理健身计划:


class FitnessApp(toga.App):

# ...

def create_plan(self, widget):

plan_name = self.plan_name.value

plan_description = self.plan_description.value

cursor = self.db_conn.cursor()

cursor.execute('''

INSERT INTO plans (name, description)

VALUES (?, ?)

''', (plan_name, plan_description))

self.db_conn.commit()

self.plan_name.value = ''

self.plan_description.value = ''

def view_plans(self, widget):

cursor = self.db_conn.cursor()

cursor.execute('SELECT name, description FROM plans')

plans = cursor.fetchall()

plan_list = toga.Table(

headings=['计划名称', '计划描述'],

data=plans,

style=Pack(flex=1)

)

self.plan_window = toga.Window(title='健身计划列表')

self.plan_window.content = plan_list

self.plan_window.show()

def build_main_box(self):

# ...

plan_name_label = toga.Label('计划名称:', style=Pack(padding=(0, 5)))

self.plan_name = toga.TextInput(style=Pack(flex=1))

plan_description_label = toga.Label('计划描述:', style=Pack(padding=(0, 5)))

self.plan_description = toga.TextInput(style=Pack(flex=1))

create_plan_button = toga.Button('创建计划', on_press=self.create_plan, style=Pack(padding=5))

view_plans_button = toga.Button('查看计划', on_press=self.view_plans, style=Pack(padding=5))

plan_box = toga.Box(

children=[plan_name_label, self.plan_name, plan_description_label, self.plan_description],

style=Pack(direction=COLUMN, padding=10)

)

main_box = toga.Box(

children=[activity_box, time_box, distance_box, calories_box, add_button, plan_box,

create_plan_button, view_plans_button, stats_box],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

# ...

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

在上述示例中,我们添加了create_plan()方法来创建健身计划,并将计划名称和描述保存到数据库中。我们还添加了view_plans()方法来查看已创建的健身计划,并在一个新的窗口中显示计划列表。

build_main_box()方法中,我们创建了输入计划名称和描述的文本框,以及"创建计划"和"查看计划"按钮。当用户点击"创建计划"按钮时,create_plan()方法会被调用,创建并保存健身计划。当用户点击"查看计划"按钮时,view_plans()方法会被调用,显示健身计划列表。

五、增加备份数据恢复数据功能

要为健身追踪应用添加备份和恢复数据功能,你可以使用文件操作来实现。下面是一个简单的示例代码,展示如何实现数据的备份和恢复功能:


import shutil

class FitnessApp(toga.App):

# ...

def backup_data(self, widget):

# 关闭数据库连接

self.db_conn.close()

# 备份数据库文件

shutil.copy2('fitness_tracker.db', 'backup/fitness_tracker_backup.db')

# 重新打开数据库连接

self.db_conn = sqlite3.connect('fitness_tracker.db')

# 提示备份成功

toga.dialog.info('备份成功', '数据已成功备份至 backup 文件夹。')

def restore_data(self, widget):

# 关闭数据库连接

self.db_conn.close()

# 恢复数据库文件

shutil.copy2('backup/fitness_tracker_backup.db', 'fitness_tracker.db')

# 重新打开数据库连接

self.db_conn = sqlite3.connect('fitness_tracker.db')

# 提示恢复成功

toga.dialog.info('恢复成功', '数据已成功恢复。')

def build_main_box(self):

# ...

backup_button = toga.Button('备份数据', on_press=self.backup_data, style=Pack(padding=5))

restore_button = toga.Button('恢复数据', on_press=self.restore_data, style=Pack(padding=5))

main_box = toga.Box(

children=[activity_box, time_box, distance_box, calories_box, add_button, plan_box,

create_plan_button, view_plans_button, stats_box, backup_button, restore_button],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

# ...

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

在上述示例中,我们添加了backup_data()方法来备份数据库文件。该方法关闭数据库连接,将数据库文件复制到指定的备份文件夹中,然后重新打开数据库连接。

我们还添加了restore_data()方法来恢复数据库文件。该方法关闭数据库连接,将备份文件复制回原始的数据库文件位置,然后重新打开数据库连接。

build_main_box()方法中,我们创建了"备份数据"和"恢复数据"按钮,并将其添加到主界面的布局中。当用户点击"备份数据"按钮时,backup_data()方法会被调用,执行数据备份操作。当用户点击"恢复数据"按钮时,restore_data()方法会被调用,执行数据恢复操作。

请确保在进行数据备份和恢复操作时,谨慎处理用户数据,以免丢失或覆盖重要数据。

六、初步整合代码示例


import toga

from toga.style import Pack

from toga.style.pack import COLUMN, ROW

import sqlite3

import datetime

import calendar

import pandas as pd

import matplotlib.pyplot as plt

import shutil

class FitnessApp(toga.App):

def startup(self):

self.db_conn = sqlite3.connect('fitness_tracker.db')

self.create_table()

self.main_window = toga.MainWindow(title=self.name)

self.main_window.content = self.build_main_box()

self.main_window.show()

def create_table(self):

cursor = self.db_conn.cursor()

cursor.execute('''

CREATE TABLE IF NOT EXISTS activities (

id INTEGER PRIMARY KEY AUTOINCREMENT,

activity_type TEXT,

time TEXT,

distance REAL,

calories REAL

)

''')

cursor.execute('''

CREATE TABLE IF NOT EXISTS plans (

id INTEGER PRIMARY KEY AUTOINCREMENT,

name TEXT,

description TEXT

)

''')

self.db_conn.commit()

def add_activity(self, widget):

activity_type = self.activity_type.value

time = self.time.value

distance = float(self.distance.value)

calories = float(self.calories.value)

cursor = self.db_conn.cursor()

cursor.execute('''

INSERT INTO activities (activity_type, time, distance, calories)

VALUES (?, ?, ?, ?)

''', (activity_type, time, distance, calories))

self.db_conn.commit()

self.activity_type.value = ''

self.time.value = ''

self.distance.value = ''

self.calories.value = ''

def calculate_weekly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE time >= ? AND time <= ?

''', (self.get_start_of_week(), self.get_end_of_week()))

result = cursor.fetchone()

return result[0], result[1]

def calculate_monthly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE time >= ? AND time <= ?

''', (self.get_start_of_month(), self.get_end_of_month()))

result = cursor.fetchone()

return result[0], result[1]

def calculate_yearly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE time >= ? AND time <= ?

''', (self.get_start_of_year(), self.get_end_of_year()))

result = cursor.fetchone()

return result[0], result[1]

def get_start_of_week(self):

today = datetime.date.today()

start_of_week = today - datetime.timedelta(days=today.weekday())

return start_of_week.isoformat()

def get_end_of_week(self):

today = datetime.date.today()

end_of_week = today + datetime.timedelta(days=6 - today.weekday())

return end_of_week.isoformat()

def get_start_of_month(self):

today = datetime.date.today()

start_of_month = today.replace(day=1)

return start_of_month.isoformat()

def get_end_of_month(self):

today = datetime.date.today()

_, last_day = calendar.monthrange(today.year, today.month)

end_of_month = today.replace(day=last_day)

return end_of_month.isoformat()

def get_start_of_year(self):

today = datetime.date.today()

start_of_year = today.replace(month=1, day=1)

return start_of_year.isoformat()

def get_end_of_year(self):

today = datetime.date.today()

end_of_year = today.replace(month=12, day=31)

return end_of_year.isoformat()

def analyze_data(self, widget):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT activity_type, SUM(time) as total_time, SUM(calories) as total_calories

FROM activities

GROUP BY activity_type

''')

result = cursor.fetchall()

data = pd.DataFrame(result, columns=['Activity Type', 'Total Time', 'Total Calories'])



# 绘制柱状图

data.plot(x='Activity Type', y='Total Time', kind='bar', legend=False)

plt.title('Total Time Spent on Each Activity')

plt.xlabel('Activity Type')

plt.ylabel('Total Time (hours)')

plt.show()

# 绘制饼图

data.plot(x='Activity Type', y='Total Calories', kind='pie', labels=data['Activity Type'], autopct='%1.1f%%')

plt.title('Total Calories Burned for Each Activity')

plt.ylabel('')

plt.show()

def create_plan(self, widget):

plan_name = self.plan_name.value

plan_description = self.plan_description.value

cursor = self.db_conn.cursor()

cursor.execute('''

INSERT INTO plans (name, description)

VALUES (?, ?)

''', (plan_name, plan_description))

self.db_conn.commit()

self.plan_name.value = ''

self.plan_description.value = ''

def view_plans(self, widget):

cursor = self.db_conn.cursor()

cursor.execute('SELECT name, description FROM plans')

plans = cursor.fetchall()

plan_list = toga.Table(

headings=['计划名称', '计划描述'],

data=plans,

style=Pack(flex=1)

)

self.plan_window = toga.Window(title='健身计划列表')

self.plan_window.content = plan_list

self.plan_window.show()

def backup_data(self, widget):

self.db_conn.close()

shutil.copy2('fitness_tracker.db', 'backup/fitness_tracker_backup.db')

self.db_conn = sqlite3.connect('fitness_tracker.db')

toga.dialog.info('备份成功', '数据已成功备份至 backup 文件夹。')

def restore_data(self, widget):

self.db_conn.close()

shutil.copy2('backup/fitness_tracker_backup.db', 'fitness_tracker.db')

self.db_conn = sqlite3.connect('fitness_tracker.db')

toga.dialog.info('恢复成功', '数据已成功恢复。')

def build_main_box(self):

activity_label = toga.Label('运动类型:', style=Pack(padding=(0, 5)))

self.activity_type = toga.TextInput(style=Pack(flex=1))

time_label = toga.Label('时间:', style=Pack(padding=(0, 5)))

self.time = toga.TextInput(style=Pack(flex=1))

distance_label = toga.Label('距离:', style=Pack(padding=(0, 5)))

self.distance = toga.TextInput(style=Pack(flex=1))

calories_label = toga.Label('消耗卡路里:', style=Pack(padding=(0, 5)))

self.calories = toga.TextInput(style=Pack(flex=1))

add_button = toga.Button('添加运动', on_press=self.add_activity, style=Pack(padding=5))

analyze_button = toga.Button('数据分析', on_press=self.analyze_data, style=Pack(padding=5))

plan_name_label = toga.Label('计划名称:', style=Pack(padding=(0, 5)))

self.plan_name = toga.TextInput(style=Pack(flex=1))

plan_description_label = toga.Label('计划描述:', style=Pack(padding=(0, 5)))

self.plan_description = toga.TextInput(style=Pack(flex=1))

create_plan_button = toga.Button('创建计划', on_press=self.create_plan, style=Pack(padding=5))

view_plans_button = toga.Button('查看计划', on_press=self.view_plans, style=Pack(padding=5))

main_box = toga.Box(

children=[

activity_label, self.activity_type, time_label, self.time,

distance_label, self.distance, calories_label, self.calories,

add_button, analyze_button,

plan_name_label, self.plan_name, plan_description_label, self.plan_description,

create_plan_button, view_plans_button

],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

上述代码是一个比较完整的健身追踪应用示例,包括记录运动数据、统计分析、健身计划管理以及数据备份和恢复功能。你可以根据需要进行修改和扩展,以满足实际需求。

七、增加登录验证功能

要为健身追踪应用添加登录验证功能,你可以使用用户名和密码进行身份验证。下面是一个示例代码,展示如何实现登录验证功能:


import toga

from toga.style import Pack

from toga.style.pack import COLUMN, ROW

import sqlite3

class FitnessApp(toga.App):

def startup(self):

self.db_conn = sqlite3.connect('fitness_tracker.db')

self.create_table()

self.login_window = toga.MainWindow(title='登录')

self.login_window.content = self.build_login_box()

self.login_window.show()

def create_table(self):

cursor = self.db_conn.cursor()

cursor.execute('''

CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

username TEXT UNIQUE,

password TEXT

)

''')

self.db_conn.commit()

def build_login_box(self):

username_label = toga.Label('用户名:', style=Pack(padding=(0, 5)))

self.username_input = toga.TextInput(style=Pack(flex=1))

password_label = toga.Label('密码:', style=Pack(padding=(0, 5)))

self.password_input = toga.PasswordInput(style=Pack(flex=1))

login_button = toga.Button('登录', on_press=self.login, style=Pack(padding=5))

login_box = toga.Box(

children=[

username_label, self.username_input,

password_label, self.password_input,

login_button

],

style=Pack(direction=COLUMN, padding=10)

)

return login_box

def login(self, widget):

username = self.username_input.value

password = self.password_input.value

cursor = self.db_conn.cursor()

cursor.execute('SELECT * FROM users WHERE username=? AND password=?', (username, password))

user = cursor.fetchone()

if user is not None:

self.username_input.value = ''

self.password_input.value = ''

self.login_window.close()

self.show_main_window()

else:

toga.dialog.info('登录失败', '用户名或密码错误。')

def show_main_window(self):

self.main_window = toga.MainWindow(title=self.name)

self.main_window.content = self.build_main_box()

self.main_window.show()

def build_main_box(self):

# ... 剩余的代码和界面元素

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()

在上述代码中,我们添加了一个users表来存储用户的用户名和密码。在build_login_box()方法中,我们创建了用户名和密码输入框以及登录按钮,并在login()方法中实现了登录验证逻辑。当用户点击登录按钮时,会检查输入的用户名和密码是否与数据库中的用户匹配。如果匹配成功,就关闭登录窗口并显示主窗口;如果匹配失败,则显示登录失败的提示。

startup()方法中,我们首先创建了用户表,并显示登录窗口。只有在成功登录后,才会显示主窗口。

请注意,这只是一个简单的示例,你可能需要根据实际需求进一步优化代码和添加更多的安全性措施,例如使用哈希算法对密码进行加密存储。同时,建议在生产环境中使用专业的身份验证解决方案,确保应用的安全性。

八、完成最终整合的小项目示例代码


import toga

from toga.style import Pack

from toga.style.pack import COLUMN, ROW

import sqlite3

import datetime

import calendar

import pandas as pd

import matplotlib.pyplot as plt

import shutil

class FitnessApp(toga.App):

def startup(self):

self.db_conn = sqlite3.connect('fitness_tracker.db')

self.create_table()

self.login_window = toga.MainWindow(title='登录')

self.login_window.content = self.build_login_box()

self.login_window.show()

def create_table(self):

cursor = self.db_conn.cursor()

cursor.execute('''

CREATE TABLE IF NOT EXISTS users (

id INTEGER PRIMARY KEY AUTOINCREMENT,

username TEXT UNIQUE,

password TEXT

)

''')

cursor.execute('''

CREATE TABLE IF NOT EXISTS activities (

id INTEGER PRIMARY KEY AUTOINCREMENT,

user_id INTEGER,

activity_type TEXT,

time TEXT,

distance REAL,

calories REAL

)

''')

cursor.execute('''

CREATE TABLE IF NOT EXISTS plans (

id INTEGER PRIMARY KEY AUTOINCREMENT,

user_id INTEGER,

name TEXT,

description TEXT

)

''')

self.db_conn.commit()

def build_login_box(self):

username_label = toga.Label('用户名:', style=Pack(padding=(0, 5)))

self.username_input = toga.TextInput(style=Pack(flex=1))

password_label = toga.Label('密码:', style=Pack(padding=(0, 5)))

self.password_input = toga.PasswordInput(style=Pack(flex=1))

login_button = toga.Button('登录', on_press=self.login, style=Pack(padding=5))

login_box = toga.Box(

children=[

username_label, self.username_input,

password_label, self.password_input,

login_button

],

style=Pack(direction=COLUMN, padding=10)

)

return login_box

def login(self, widget):

username = self.username_input.value

password = self.password_input.value

cursor = self.db_conn.cursor()

cursor.execute('SELECT * FROM users WHERE username=? AND password=?', (username, password))

user = cursor.fetchone()

if user is not None:

self.username_input.value = ''

self.password_input.value = ''

self.login_window.close()

self.show_main_window(user[0]) # 传递用户ID

else:

toga.dialog.info('登录失败', '用户名或密码错误。')

def show_main_window(self, user_id):

self.user_id = user_id

self.main_window = toga.MainWindow(title=self.name)

self.main_window.content = self.build_main_box()

self.main_window.show()

def add_activity(self, widget):

activity_type = self.activity_type.value

time = self.time.value

distance = float(self.distance.value)

calories = float(self.calories.value)

cursor = self.db_conn.cursor()

cursor.execute('''

INSERT INTO activities (user_id, activity_type, time, distance, calories)

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

''', (self.user_id, activity_type, time, distance, calories))

self.db_conn.commit()

self.activity_type.value = ''

self.time.value = ''

self.distance.value = ''

self.calories.value = ''

def calculate_weekly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE user_id=? AND time >= ? AND time <= ?

''', (self.user_id, self.get_start_of_week(), self.get_end_of_week()))

result = cursor.fetchone()

return result[0], result[1]

def calculate_monthly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE user_id=? AND time >= ? AND time <= ?

''', (self.user_id, self.get_start_of_month(), self.get_end_of_month()))

result = cursor.fetchone()

return result[0], result[1]

def calculate_yearly_stats(self):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT SUM(time), SUM(calories)

FROM activities

WHERE user_id=? AND time >= ? AND time <= ?

''', (self.user_id, self.get_start_of_year(), self.get_end_of_year()))

result = cursor.fetchone()

return result[0], result[1]

def get_start_of_week(self):

today = datetime.date.today()

start_of_week = today - datetime.timedelta(days=today.weekday())

return start_of_week.isoformat()

def get_end_of_week(self):

today = datetime.date.today()

end_of_week = today + datetime.timedelta(days=6 - today.weekday())

return end_of_week.isoformat()

def get_start_of_month(self):

today = datetime.date.today()

start_of_month = today.replace(day=1)

return start_of_month.isoformat()

def get_end_of_month(self):

today = datetime.date.today()

_, last_day = calendar.monthrange(today.year, today.month)

end_of_month = today.replace(day=last_day)

return end_of_month.isoformat()

def get_start_of_year(self):

today = datetime.date.today()

start_of_year = today.replace(month=1, day=1)

return start_of_year.isoformat()

def get_end_of_year(self):

today = datetime.date.today()

end_of_year = today.replace(month=12, day=31)

return end_of_year.isoformat()

def analyze_data(self, widget):

cursor = self.db_conn.cursor()

cursor.execute('''

SELECT activity_type, SUM(time) as total_time, SUM(calories) as total_calories

FROM activities

WHERE user_id=?

GROUP BY activity_type

''', (self.user_id,))

result = cursor.fetchall()

data = pd.DataFrame(result, columns=['Activity Type', 'Total Time', 'Total Calories'])



# 绘制柱状图

data.plot(x='Activity Type', y='Total Time', kind='bar', legend=False)

plt.title('Total Time Spent on Each Activity')

plt.xlabel('Activity Type')

plt.ylabel('Total Time (hours)')

plt.show()

# 绘制饼图

data.plot(x='Activity Type', y='Total Calories', kind='pie', labels=data['Activity Type'], autopct='%1.1f%%')

plt.title('Total Calories Burned for Each Activity')

plt.ylabel('')

plt.show()

def create_plan(self, widget):

plan_name = self.plan_name.value

plan_description = self.plan_description.value

cursor = self.db_conn.cursor()

cursor.execute('''

INSERT INTO plans (user_id, name, description)

VALUES (?, ?, ?)

''', (self.user_id, plan_name, plan_description))

self.db_conn.commit()

self.plan_name.value = ''

self.plan_description.value = ''

def view_plans(self, widget):

cursor = self.db_conn.cursor()

cursor.execute('SELECT name, description FROM plans WHERE user_id=?', (self.user_id,))

plans = cursor.fetchall()

plan_list = toga.Table(

headings=['计划名称', '计划描述'],

data=plans,

style=Pack(flex=1)

)

self.plan_window = toga.Window(title='健身计划列表')

self.plan_window.content = plan_list

self.plan_window.show()

def backup_data(self, widget):

self.db_conn.close()

shutil.copy2('fitness_tracker.db', 'backup/fitness_tracker_backup.db')

self.db_conn = sqlite3.connect('fitness_tracker.db')

toga.dialog.info('备份成功', '数据已成功备份至 backup 文件夹。')

def restore_data(self, widget):

self.db_conn.close()

shutil.copy2('backup/fitness_tracker_backup.db', 'fitness_tracker.db')

self.db_conn = sqlite3.connect('fitness_tracker.db')

toga.dialog.info('恢复成功', '数据已成功恢复。')

def build_main_box(self):

activity_label = toga.Label('运动类型:', style=Pack(padding=(0, 5)))

self.activity_type = toga.TextInput(style=Pack(flex=1))

time_label = toga.Label('时间:', style=Pack(padding=(0, 5)))

self.time = toga.TextInput(style=Pack(flex=1))

distance_label = toga.Label('距离:', style=Pack(padding=(0, 5)))

self.distance = toga.TextInput(style=Pack(flex=1))

calories_label = toga.Label('消耗卡路里:', style=Pack(padding=(0, 5)))

self.calories = toga.TextInput(style=Pack(flex=1))

add_button = toga.Button('添加运动', on_press=self.add_activity, style=Pack(padding=5))

analyze_button = toga.Button('数据分析', on_press=self.analyze_data, style=Pack(padding=5))

plan_name_label = toga.Label('计划名称:', style=Pack(padding=(0, 5)))

self.plan_name = toga.TextInput(style=Pack(flex=1))

plan_description_label = toga.Label('计划描述:', style=Pack(padding=(0, 5)))

self.plan_description = toga.TextInput(style=Pack(flex=1))

create_plan_button = toga.Button('创建计划', on_press=self.create_plan, style=Pack(padding=5))

view_plans_button = toga.Button('查看计划', on_press=self.view_plans, style=Pack(padding=5))

backup_button = toga.Button('备份数据', on_press=self.backup_data, style=Pack(padding=5))

restore_button = toga.Button('恢复数据', on_press=self.restore_data, style=Pack(padding=5))

main_box = toga.Box(

children=[

activity_label, self.activity_type, time_label, self.time,

distance_label, self.distance, calories_label, self.calories,

add_button, analyze_button,

plan_name_label, self.plan_name, plan_description_label, self.plan_description,

create_plan_button, view_plans_button,

backup_button, restore_button

],

style=Pack(direction=COLUMN, padding=10)

)

return main_box

def main():

return FitnessApp('健身追踪应用', 'com.example.fitnessapp')

if __name__ == '__main__':

main().main_loop()


上述代码是一个完整的健身追踪应用示例,包括登录验证、记录运动数据、统计分析、健身计划管理以及数据备份和恢复功能。你可以根据需要进行修改和扩展,以满足实际需求。请注意,在实际应用中,你可能需要进一步优化代码和界面设计,以提供更好的用户体验和功能。同时,建议在生产环境中使用专业的身份验证解决方案,确保应用的安全性。


阅读量:733

点赞量:0

收藏量:0