第六次C++实训报告
第六次实训工作报告
设计题目
华南理工大学:植此青绿
本周工作小结:
本周我主要进行了以下工作:
- 设计了登录界面和登录页面的整体逻辑。
- 创建并设置了玩家排行榜页面,包括基本布局和样式的设计。
- 实现了从文件中读取排行榜数据并根据关卡进行排序和显示。
- 添加了动态更新排行榜的功能,根据不同关卡展示相应的排行榜。
- 进行了部分代码优化和调试工作,确保程序功能的正常实现。
环境与工具:
- 开发环境:Qt Creator 13.0.0
- 操作系统:Windows 11
前置工作
- 准备了一个txt文件进行登录用户的读入。
- 设计了登录页面和相应逻辑。
- 设计了排行榜页面的基本布局和样式,包括按钮、标签等UI元素。
- 准备了用于存储排行榜数据的文本文件。
- 思考排行榜具体滑动的设计和读取逻辑,能否实现实时更新
- 完善关卡类的提交按钮
后期预备开启功能:
登录页面登录后可以显示用户的游玩记录(暂时有想法,自认为也不难实现)
程序功能说明
设计登录页面类
1 | //+------------------------------------------------------------+ |
基本功能:实现了基础的页面和逻辑。
1. 创建了整体的按钮和原先的工作一样,也添加了图标,就不过多赘述了。
2. 各大槽函数的书写
void LoginDialog::attemptRegister()
:先检查用户名和密码是否为空,然后以只读if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
的方式打开数据文件,该文件是程序一运行就会创建的,只要该游戏在你的电脑里面那一刻,这个文件就存在,直到将该游戏彻底删除为止,因此数据会一直保留。接下来在文件中查找是否用户名出现过,一旦没有出现过,就以追加的方式打开模式if(!file.open(QIODevice::Append | QIODevice::Text))
,并写入新用户信息。void LoginDialog::attemptlogin()
:登录逻辑也一样,就查找密码和用户名,匹配上用户名就查看密码是否正确,不然就提示用户不存在。
3. 获取用户名和密码:
1
2QString username = usernameEdit->text();
QString password = passwordEdit->text();
这两行代码从用户名输入框和密码输入框中获取用户输入的用户名和密码。
4. 打开文件:
1
2
3
4
5
6QFile file("./vvv.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
// showError("无法打开用户数据文件。");
return;
}
这里尝试以写入模式打开文件vvv.txt
。
5. 读取文件内容并检查用户名和密码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33QTextStream in(&file);
bool isRegistered = false;
while (!in.atEnd())
{
QString line = in.readLine();
QStringList parts = line.split(' ');
if (parts.size() == 2 && parts[0] == username)
{
isRegistered = true;
if (parts[1] == password)
{
QString loginTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
emit loggedIn(username, loginTime);
_username = username;
_password = password;
showSuccess("登录成功。");
usernameEdit->clear();
passwordEdit->clear();
file.close();
return;
}
else
{
showError("密码错误,请重试。");
usernameEdit->clear();
passwordEdit->clear();
file.close();
return;
}
}
}
file.close();
QTextStream in(&file);
:创建一个文本流以读取文件内容。bool isRegistered = false;
:初始化一个布尔变量以跟踪用户是否注册。while (!in.atEnd())
:循环读取文件的每一行,直到文件结束。QStringList parts = line.split(' ');
:将每行按空格分割成两部分:用户名和密码。```cpp if (parts.size() == 2 && parts[0] == username)
1
2
3
4
5
6
7
:检查行的格式是否正确并且用户名是否匹配。
- `isRegistered = true;`:如果用户名匹配,标记为已注册。
- ```cpp
if (parts[1] == password):检查密码是否匹配。
- 如果匹配,记录当前时间并触发
loggedIn
信号,同时显示登录成功消息,清除输入框并关闭文件。 - 如果不匹配,显示密码错误消息,清除输入框并关闭文件。
- 如果匹配,记录当前时间并触发
6. 处理未注册用户:
1
2
3
4
5
6if (!isRegistered)
{
showError("用户名未注册,请先注册。");
}
usernameEdit->clear();
passwordEdit->clear();
如果文件读取完毕后没有找到匹配的用户名,则显示“用户名未注册,请先注册”的错误消息,并清除输入框。
void LoginDialog::forgotPassword()
:用于实现找回密码的功能。主要逻辑
- 获取用户名:使用
QInputDialog::getText
弹出一个输入框,提示用户输入用户名。如果用户点击了“确定”,且输入的用户名非空,则继续执行下一步。 - 获取新密码:再次弹出一个输入框,提示用户输入新密码。如果用户点击了“确定”,且输入的新密码非空,则继续执行下一步。
- 读取文件:打开名为
vvv.txt
的文件,该文件存储了用户名和密码。如果文件无法打开,则函数直接返回。 - 查找用户名并修改密码:逐行读取文件内容,检查每一行的用户名是否与输入的用户名匹配。如果匹配,将该行的密码更新为新密码;否则,保持原样。用一个
QStringList
存储所有的文件内容,并记录是否找到匹配的用户名。 - 写回文件:如果找到了匹配的用户名,则重新打开文件,以截断模式写入更新后的内容。写入更新后的所有行,并关闭文件。更新内部的
_password
变量,并显示成功消息。如果未找到匹配的用户名,显示错误消息。
- 获取用户名:使用
特色:错误处理
- 文件无法打开时,直接返回。
- 用户名未注册时,显示错误消息。
- 文件写入失败时,显示错误消息。
同时处理了鼠标事件,重写了键盘处理函数,来实现回车注册功能,也算是优化了一点点用户的体验吧。
1 | void LoginDialog::keyPressEvent(QKeyEvent *event) |
void LoginDialog::uploadAvatar()
:通过打开文件对话框选择图片:检查是否选择了图片,加载图片并截取
1 | void LoginDialog::uploadAvatar() |
- 系统托盘的创建
- 创建图标
- 创建托盘菜单
- 连接QAction对象,用于最小化,还原和退出,并设置为托盘菜单,显示托盘图标。
1 | void LoginDialog::createTrayIcon() |
设计了用户结构体,和排行榜类。
前置要求,在关卡用户提交部分更改逻辑,直接提交用户头像,用户名和时间到文件,方便排行榜更新,这里不多赘述。
可能会好奇用户名,状态,图片路径从何而来,从登录那一刻就开始通过设计的一系列接口传到关卡一。
1 | // 重置所有格子数值为初始状态 |
public函数接口:
1 | // 更新信息 |
1. PlayerRankingPage 类
1 | // +-------------------------------------+ |
2. UserRankItem 类
1 | // | UserRankItem | |
具体功能和逻辑
- 创建关卡一,关卡二,关卡三,返回按钮,与标题栏
1 | QPushButton *level1Button = new QPushButton("关卡一", this); |
- 创建滚动区域和排行榜布局器
1 | QScrollArea *scrollArea = new QScrollArea(this); |
- 一些槽函数的设计:这里主要是用来识别关卡一,关卡二,关卡三各自的信息
1 | //分别用于显示关卡一、关卡二和关卡三的排行榜 |
- 排行榜的更新策略
1. 清空排行榜
1 | QLayoutItem *item; |
2. 读取并排序新的排行榜数据
1 | std::vector<UserRankItem> userRankList = readRankingFromFile(level); |
3. 放入列表
1 | for (const auto &rankItem : userRankList) |
具体效果展示:
寄语
感觉可以来一点花哨的设计,因为大体的游戏逻辑和界面已经做完了,比如联网和音乐,正在逐步考虑中,同时也要进行页面的进一步美化。
春风得意马蹄疾,一日看尽长安花!