传奇开心果博文系列
- 系列博文目录
- beeware的Toga开发移动应用示例系列
- 博文目录
- 前言
- 一、记录存储运动活动数据
- 二、添加添加统计显示功能
- 三、添加图表显示数据分析功能
- 四、增加健身计划管理
- 五、增加备份数据恢复数据功能
- 六、初步整合代码示例
- 七、增加登录验证功能
- 八、完成最终整合的小项目示例代码
系列博文目录
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()
上述代码是一个完整的健身追踪应用示例,包括登录验证、记录运动数据、统计分析、健身计划管理以及数据备份和恢复功能。你可以根据需要进行修改和扩展,以满足实际需求。请注意,在实际应用中,你可能需要进一步优化代码和界面设计,以提供更好的用户体验和功能。同时,建议在生产环境中使用专业的身份验证解决方案,确保应用的安全性。