软件工程结对作业
四则运算器界面设计
康鑫 PB16060203
娄雨禛 PB16060356
项目内容链接:http://www.cnblogs.com/silent-zlv/p/8684979.html
一、项目介绍
本次作业的设计比较有意思。每组随机选择“计算核心”和“用户界面”中的一个,然后进行拼接整合。
对面将要完成的“用户界面设计”,我们两个都是完全的初学者。经过初步了解,我们采用了在C++下的备受好评的集成UI软件:Qt。
“用户界面设计”的作用是充当一个数据传输渠道,实现“用户数据”和“计算核心”数据的交互。这个交互的关键点和难点就在于交互接口的设计。如何获取数据,又如何发送数据,将是我们将要面临的最大难题。此外,由于我们都是初次接触UI设计,还要大量了解C++中涉及的图形界面接口在Qt中的使用。
二、进度规划与完成情况
进度规划 | 计划 | 实际 | 说明 |
初步确立软件布局 【合作】 |
20 min | 20 min | 我们的软件布局分为以下主界面引导下的五个模块:参数设定、答题窗口、错题记录、历史记录、成绩单。 |
主界面设计 【康鑫】 |
180 min | 150 min | 我们的主界面很简单,引导用户做出五种选择:开始答题、查看错题、查看历史记录、查看成绩、退出答题系统。 |
参数设定 界面设计 【康鑫】 |
180 min | 180 min | 这是一个较为复杂的界面。在这里,用户可以自由地选择生成的问题数、每个运算表达式的运算符数目、操作数的范围、操作数的精度、运算表达式涉及的运算类型,然后进入答题界面。 |
答题界面设计 【康鑫】 |
180 min | 180 min | 在答题界面中,用户被要求在一定的时间内答完每一道题。用户每答完一题,就能得知本题自己是否答对。用户还能知道自己的答题进度,对自己的答题情况有一个把握。答完指定数量的问题后,返回主界面。 |
错题记录 界面设计 【合作】 |
120 min | 60 min | 错题记录界面展示了用户所有做错的题目。 |
历史记录 界面设计 【合作】 |
120 min | 60 min | 历史记录界面展示了用户所有做过的题目。 |
成绩单 界面设计 【合作】 |
240 min | 60 min | 成绩单界面将根据用户的做题情况,给出一个答题的正确率,并将用户在各个运算符中出错的频率做一个统计,让用户了解自己在哪个运算符出错的频率较高,从而在下一个阶段进行更有针对性的训练。 |
利用DLL 与CORE组对接 【康鑫】 |
180 min | 180 min | 这是本次作业的一个重点。调用过程并不复杂,但在完全陌生的情况下,了解DLL调用并进行使用花费了一番时间。我们采用了DLL的隐式调用。 |
界面优化调整软件漏洞修复 【合作】 |
360 min | 1800 min | 这是一个永无止境的过程。软件界面的优化不仅仅在于让界面更加美观合理,还在于让界面之间的跳转方式更加人性化,使用户更便于操作。而漏洞修复则涉及到反复地粗暴尝试。通过今早地将我们的软件推送给用户让他们以自己的方式随意调试,能帮助我们发现更多的漏洞。 |
三、UI界面展示与分析
第一代UI:实现基本功能,没有考虑任何的界面美化
主界面
参数设定界面
答题界面
错题记录界面
历史记录界面
成绩单界面
第一代UI的不足之处:
1. 按钮的布局位置不够合理,如主界面的布局、参数设定界面的布局等等。
2. 只采用了最原始的字体,界面无美感可言。
第二代UI:完善功能,修复BUG,进行界面的布局与美化
主界面
参数设定界面
答题界面
历史记录界面
成绩单界面
在第一代UI的基础上,我们进行了较多的BUG修复与界面优化。它们具体包括以下内容。
BUG修复部分
1.修复了多次做题,成绩高于100的问题
2.修复了未答题时成绩出现负数的问题
3.修复了退出做题系统,却仍然弹出“做题时间到”窗口的问题
4.修复了用户答案输入比正确答案还要精确,却被判错的问题
5.修复了用户不输入答案,正确答案为0,仍然被判对的问题
6.修复了用户在提交问题答案后马上退出答题系统,改题目没有被统计的问题
界面美化部分
1.各个窗口的按钮、文本框布局
2.加入Logo,使主界面焕然一新
3.合并“错题界面”和“历史记录界面”,并采用表格形式展示,更为清晰美观.
4.为适应低分辨率电脑做了界面优化
5.增添了各个子窗口的窗口标签
四、项目开发的困惑与心得
1.由于对Qt完全陌生,上手研究花了好一番功夫。这其中包括C++相关语法的学习和Qt软件本身语法的学习。其实对软件本身的学习也是实际使用过程中很重要的部分,这个过程不容小视,但我们也需要尽可能压缩这一部分的实践,从而把精力更有效地投入到实际编程创作上来。在实际开发过程中,要采取“敏捷”原则,学一点做一点,这样才能尽可能不在软件本身上化过多的工夫,从而耽搁了工程的实际进行。
2.在对接过程中,我们用的是DLL隐式调用。DLL对我们来说是完全陌生的,也是从头学起。在Qt添加DLL文件进行编译时,有时会碰到许多莫名其妙的错误一直存在,比如“找不到core.lib”,而我们的确吧这个文件加入进来了。这个时候,唯一可行的解决方案是,将DEBUG文件夹整个删除,然后重新编译生成文件夹,再添加DLL文件。网上也有很多人碰到这样的问题,我们只是用这个看似很玄乎的做法,却并不知道背后的原因,有待以后继续探究。
3.在结对编程过程中,我们先是分开来各自编程,而在中后期进入“驾驶员+领航员”的合作编程模式。这是因为,一开始我们对Qt开发环境都不熟悉,即使两个人一起编程,效率也不会很高。而在中后期,两个人都对这个环境有了一些了解,这样,转而进入合作编程模式,就能互相弥补对方想法的不足之处,进行更高质量代码的编写。
4.本次结对编程,我们得到了一个人编程体会不到的“优势互补”的感觉。也就是说,当我们面对一个程序问题的实现方式时,两个人会分别说出自己对这个问题的看法,然后进行比较,分析两种方法孰优孰劣。如果其中一个人对某一些语句的书写很熟练而另一者不是很熟练,那么熟练者主动书写代码,另一人在旁边积极提出有益的建议。这样,就较少出现个人编程过程中常有的“阻塞”情形,从而提升了编程的效率。
五、Qt学习心得
Qt初学——我的第一个UI——康鑫
第一次打开Qt的时候,我是一脸懵逼的。没学过c++,里面的程序都看不懂。按照套路,我开始看教程,上手实践。连着搞了3天之后,我开始渐渐明白怎么写UI。
我现在的理解是:UI = 界面设计 + 信号槽响应机制 。下面我通过实例来展示编写一个UI的大致过程(注意:这不是教程!最后贴的有专业教程!):
Step1:界面设计
首先,要创建一个项目。
.pro文件是项目的工程文件,点击此处看详细解释。
.h文件是主窗口MainWindow的头文件,可以在.h文件里声明变量、函数、信号、信号槽。
main.cpp就是主函数了,程序从这里开始。
mainwindow.cpp是主窗口的程序,在里面可以设置主窗口的布局,信号槽等。
.ui文件,我现在还是不知道这个文件的机制,不过我知道可以在里面拖放控件,就像拼积木一样设计UI,很简单,点击此处看有关内容。
一开始我用了一下.ui文件,但是由于不知道怎样对控件属性作更细的设置,所以干脆放弃,选择写代码实现。
创建好项目之后,开始做整个过程的前半部分,界面设计。
下面,在界面中添加一个按钮。
上网百度一下,常用的按钮是QPushButton,查了一下相关用法之后,就可以尝试使用了。
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 #include <QPushButton>
6
7 namespace Ui {
8 class MainWindow;
9 }
10
11 class MainWindow : public QMainWindow
12 {
13 Q_OBJECT
14
15 public:
16 explicit MainWindow(QWidget *parent = 0);
17 ~MainWindow();
18
19 private:
20 Ui::MainWindow *ui;
21 QPushButton *button;
22 };
23
24 #endif // MAINWINDOW_H
在.h文件里添加QPushButton的头文件#include <QPushButton> ,在private里面声明button变量,QPushButton *button;
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
button = new QPushButton(this);
button->setText("Button");
button->setParent(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
button = new QPushButton(this);//定义button变量
button->setText("Button"); //设置button属性,这里设置button的文本,其他属性百度一下就可以
button->setParent(this); //将button控件的父窗口设置为当前窗口,这句用来显示button按钮
运行效果:
到此为止,UI编写的一半——界面设计就OK了。当然要是想做更好的UI,需要添加更多的控件,各种控件百度一下基本都能找到用法。
Step2:信号槽响应机制
添加了一个按钮,一定很着急,点完之后没卵用啊!为了能够点完按钮之后给点反应,我们要用到信号与信号槽机制。按我的理解就是,你做了一件事(往往是点击按钮),之后执行相应动作(函数)。不过我的描述还是太粗浅,这里给出相对权威一点的参考。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
button = new QPushButton(this);
button->setText("Button");
button->setParent(this);
QObject::connect(button,&QPushButton::clicked,this,&MainWindow::close);
}
MainWindow::~MainWindow()
{
delete ui;
}
QObject::connect(button,&QPushButton::clicked,this,&MainWindow::close);
这句话的作用就是将点击按钮与关闭窗口“绑定”在一起。这样,点完按钮之后,窗口就会关闭。详解见上面信号槽的参考。
但是这种“自带”的信号与信号槽根本满足不了需求啊,那么就需要自定义信号和自定义信号槽来实现一个自由度相对大很多的响应。
大致过程是这样的:
1 #ifndef MAINWINDOW_H
2 #define MAINWINDOW_H
3
4 #include <QMainWindow>
5 #include <QPushButton>
6
7 namespace Ui {
8 class MainWindow;
9 }
10
11 class MainWindow : public QMainWindow
12 {
13 Q_OBJECT
14
15 public:
16 explicit MainWindow(QWidget *parent = 0);
17 ~MainWindow();
18
19 signals:
20 void signal();
21
22 private slots:
23 void on_button_clicked();
24 void receive_signal();
25
26 private:
27 Ui::MainWindow *ui;
28 QPushButton *button;
29 };
30
31 #endif // MAINWINDOW_H
信号声明在signals:后,信号槽声明在private slots:后。
1 #include "mainwindow.h"
2 #include "ui_mainwindow.h"
3
4 MainWindow::MainWindow(QWidget *parent) :
5 QMainWindow(parent),
6 ui(new Ui::MainWindow)
7 {
8 ui->setupUi(this);
9
10 button = new QPushButton(this);
11 button->setText("Button");
12 button->setParent(this);
13
14 QObject::connect(button,&QPushButton::clicked,this,&MainWindow::on_button_clicked);
15 QObject::connect(this,&MainWindow::signal,this,&MainWindow::receive_signal);
16 }
17
18 MainWindow::~MainWindow()
19 {
20 delete ui;
21 }
22
23 void MainWindow::on_button_clicked()
24 {
25 emit signal();
26 }
27
28 void MainWindow::receive_signal()
29 {
30 this->close();
31 }
QObject::connect(button,&QPushButton::clicked,this,&MainWindow::on_button_clicked);
QObject::connect(this,&MainWindow::signal,this,&MainWindow::receive_signal);
点击按钮和函数on_button_clicked();“绑定”在一起,点完按钮就会执行函数内容。
函数里面执行emit signal();发出自定义的信号signal();
发出signal();后,receive_signal();函数就会执行,因为前面将它俩“绑定”了。
receive_signal();函数里面执行了close();函数,效果是关闭当前界面。
有了上面两步,就可以尝试着构建功能更多的UI了,可以再添加窗口,添加其他控件,不同界面之间也可以把信号和信号槽“绑定”(不过记得要把槽设置成public的)……整个过程像堆积木一样,还挺有趣。
这里推荐两个教程,非常友好!强推!
最后,一周的时间从不会到大致明白,真的很开心——虽然其他作业都没写。