目录
1.需求分析
这个任务是使用按钮和标签创建一个小的界面。这个界面将允许使用按钮对三个整数值进行递增和递减,如下所示。每个整数显示旁边应该放置两个按钮,一个用于增加值,另一个用于减少值。 第一个整数值应该保持在 0 到 23 的范围内。其余整数应保持在 0 ~ 59 的范围内。还应提供“OK”、 “取消”和“应用”按钮。按下“OK”或“取消”按钮应该简单地关闭界面。在这种情况下,按下“Apply”按钮应该没有任何作用。(请注意,一般情况下,按下“应用”按钮的操作与“OK”按钮的 操作相同,只是它不会关闭窗口。在这种特殊的情况下,由于“OK”按钮除了关闭窗口外实际上不执行 任何操作,”Apply”按钮的正确操作是什么都不做。)确保“OK”按钮是界面的默认按钮和初始焦点, 将“取消”按钮设置为取消按钮,并实现“应用”显示的快捷键。
所给示意图如下:
所理解的需求:
- 三个可增减的有范围的分别代表小时,分钟,秒的组件。
- 点击应用会将目前的时间存储到数据库中,下次打开项目就会读取这个时间(虽然题干说应用没有任何操作但是我觉得应该给应用加上保存数据的属性)。
- 点击OK,Cancel会关闭窗口,OK会保存到数据库中,Cancel不会保存到数据库中。
- 设计一个可以让时间自增或自减。
2.概要设计
1.首先确定开发工具:
还是依照习惯,采用了Qt 5.12.1开发,语言是C++。
2.数据结构定义:
实验比较简单,没有采取特别的抽象的数据结构,仅仅是使用了Qt自带的组件,组件如下:
另外,定义了小时,分钟,秒整型变量,两个实现自增和自减的计时器,一个数据库指针,以及数组,该数组的作用是在点击应用后,将当前的时间数据存入该数组中。
3.具体功能的概要设计:
- 打开程序会显示上一次保存的时间。
- 秒数增加,将当前的内容赋给second变量,如果为60则分钟增加1,秒数显示为0,同理减少时如果为-1则分钟减少1,秒数显示为59。分钟和小时同理。
-
点击自增按钮,调用tim->start,相对应的会调用链接好的函数,作用是设置秒数spinbox值为当前spinbox值加一,自减同理,暂停则调用tim->stop。
- 点击应用按钮,将当前的时间数据存入t数组中。
- 点击ok,将t数组中的数据存入到数据库中。
3.详细设计(分模块介绍)
1.spinbox的增加或减少:
以分钟spinbox为例:
void Widget::on_spinBox_2_valueChanged(const QString &arg1)
{
//分钟
min=arg1.toInt();
qDebug()<<"min is:"<<min<<endl;
if (arg1.compare("60")==0){
ui->spinBox_2->setValue(0);
min=0;
qDebug()<<"2"<<endl;
ui->spinBox->setValue(hour+1);
}else if (arg1.compare("-1")==0){
ui->spinBox_2->setValue(59);
min=59;
ui->spinBox->setValue(hour-1);
}
}
这里值得注意的一点是,当分钟为60时,应该使hour数加一,此时调用的应该是ui->spinBox->setValue(hour+1);这是因为setvalue(hour+1)就会调用on_spinBox_2_valueChanged()这个槽函数
2.自增,自减功能:
tim=new QTimer(this);
tim2=new QTimer(this);
connect(tim,SIGNAL(timeout()), this,SLOT(secondAdd()));
connect(tim2,SIGNAL(timeout()), this,SLOT(secondDec()));
void Widget::secondAdd()
{
ui->spinBox_3->setValue(second+1);
}
3.OK与Cancel
点击OK之后,将t数组数据存到数据库中去并关闭页面。点击Cancel不存储。
4.调试分析
主要的问题出现在了重复发送信号。
原本的程序在第75行调用的函数是on_spinBox_valueChanged(QString::number(hour+1));
但是这样的话产生的第一个问题是,spinbox的值根本不会改变,所以需要在spinbox内部加入一个函数setvalue(hour+1),形如当前程序的第70行。然而在加入这个函数之后,因为setvalue会使spinbox的值改变,所以也会调用valueChanged这个函数,相当于被调用了两次,所以会产生两次赋值。
修改的办法是将第75行直接改为setvalue,这样可以让setvalue自己去调用valuechanged这个函数,另外第70行也可以删去。
5.用户使用说明
- 打开程序会显示上一次保存的时间。
- 秒数增加,将当前的内容赋给second变量,如果为60则分钟增加1,秒数显示为0,同理减少时如果为-1则分钟减少1,秒数显示为59。分钟和小时同理。
-
点击自增按钮,调用tim->start,相对应的会调用链接好的函数,作用是设置秒数spinbox值为当前spinbox值加一,自减同理,暂停则调用tim->stop。
- 点击应用按钮,将当前的时间数据存入t数组中。
- 点击ok,将t数组中的数据存入到数据库中。
6.测试结果(只展示部分)
1.打开程序显示上一次存储的时间数据:
2.改变时间并点击应用和OK
3.再次打开程序发现数据已经改变
7.附录
dao.h:
#ifndef DAO_H
#define DAO_H
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QDebug>
#include <QVector>
class dao
{
public:
dao();
// 打开数据库
bool openDb(void);
// 判断数据表是否存在
bool isTableExist(QString& tableName);
// 查询最后一条数据
void queryTable(int t[]);
// 插入数据
void singleInsertData(int hour,int min,int second); // 插入单条数据
//void moreInsertData(PCB &moreData); // 插入多条数据
// 删除数据
void deleteData(QString pname);
// 关闭数据库
void closeDb(void);
private:
QSqlDatabase database;
};
#endif // DAO_H
dao.cpp:
#include "dao.h"
dao::dao()
{
if (QSqlDatabase::contains("tim"))
{
database = QSqlDatabase::database("tim");
qDebug()<<"构造函数,连接成功!";
}
else
{
//连接是伴随程序运行而产生,终止而死亡
database = QSqlDatabase::addDatabase("QSQLITE","tim");
database.setDatabaseName("TIM.db");
qDebug()<<"构造函数,重新连接!";
}
qDebug()<<QSqlDatabase::contains("tim");
}
bool dao::openDb()
{
if (!database.open())
{
qDebug() << "Error: Failed to connect database." << database.lastError();
}
else
{
// do something
qDebug()<<"打开数据库成功!";
}
return true;
}
bool dao::isTableExist(QString &tableName)
{
if(database.tables().contains(tableName))
{
qDebug()<<"数据表存在!";
return true;
}
return false;
}
void dao::queryTable(int t[])
{
QSqlQuery sqlQuery(database);
sqlQuery.exec("select * from timeList");
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to query table. " << sqlQuery.lastError();
}
else
{
while(sqlQuery.next())
{
qDebug()<<"查询到1条数据"<<endl;
t[0]=sqlQuery.value(1).toInt();
t[1]=sqlQuery.value(2).toInt();
t[2]=sqlQuery.value(3).toInt();
}
}
}
void dao::singleInsertData(int hour, int min, int second)
{
qDebug()<<"开插"<<endl;
QSqlQuery sqlQuery(database);
sqlQuery.prepare("INSERT INTO timeList(hour,min,second) VALUES(:hour,:min,:second)");
sqlQuery.bindValue(":hour", hour);
sqlQuery.bindValue(":min", min);
sqlQuery.bindValue(":second", second);
if(!sqlQuery.exec())
{
qDebug() << "Error: Fail to insert data. " << sqlQuery.lastError();
}
else
{
// do something
qDebug() << "插入成功";
}
}
void dao::closeDb()
{
database.close();
}
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTimer>
#include"dao.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_spinBox_3_valueChanged(const QString &arg1);
void on_spinBox_2_valueChanged(const QString &arg1);
void on_spinBox_valueChanged(const QString &arg1);
void secondAdd();
void secondDec();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_pushButton_6_clicked();
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
private:
Ui::Widget *ui;
int second=0;
int min=0;
int hour=0;
QTimer *tim;
QTimer *tim2;
dao *timDao;//数据库指针
int t[3]={0};
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->spinBox->setMinimum(-1);
ui->spinBox->setMaximum(24);
ui->spinBox_2->setMinimum(-1);
ui->spinBox_2->setMaximum(60);
ui->spinBox_3->setMinimum(-1);
ui->spinBox_3->setMaximum(60);
tim=new QTimer(this);
tim2=new QTimer(this);
connect(tim,SIGNAL(timeout()), this,SLOT(secondAdd()));
connect(tim2,SIGNAL(timeout()), this,SLOT(secondDec()));
//创建并打开数据库
timDao=new dao();
timDao->openDb();
//判断数据表是否存在
QString str1 = QString("timeList");
qDebug() << "isTabelExist:" <<timDao->isTableExist(str1);
//初始化数据
timDao->queryTable(t);
for(int i=0;i<3;i++){
qDebug()<<t[i]<<endl;
}
ui->spinBox_3->setValue(t[2]);
ui->spinBox_2->setValue(t[1]);
ui->spinBox->setValue(t[0]);
qDebug()<<"second:"<<second<<endl;
qDebug()<<"min:"<<min<<endl;
qDebug()<<"hour:"<<hour<<endl;
ui->pushButton->setFocus();
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_spinBox_3_valueChanged(const QString &arg1)
{
//秒
second=arg1.toInt();
if (arg1.compare("60")==0){
ui->spinBox_3->setValue(0);
second=0;
qDebug()<<"1"<<endl;
ui->spinBox_2->setValue(min+1);
}else if (arg1.compare("-1")==0){
ui->spinBox_3->setValue(59);
second=59;
ui->spinBox_2->setValue(min-1);
}
}
void Widget::on_spinBox_2_valueChanged(const QString &arg1)
{
//分钟
min=arg1.toInt();
qDebug()<<"min is:"<<min<<endl;
//ui->spinBox_2->setValue(arg1.toInt());
if (arg1.compare("60")==0){
ui->spinBox_2->setValue(0);
min=0;
qDebug()<<"2"<<endl;
ui->spinBox->setValue(hour+1);
//on_spinBox_valueChanged(QString::number(hour+1));
}else if (arg1.compare("-1")==0){
ui->spinBox_2->setValue(59);
min=59;
ui->spinBox->setValue(hour-1);
}
}
void Widget::on_spinBox_valueChanged(const QString &arg1)
{
//小时
hour=arg1.toInt();
qDebug()<<"hour is:"<<hour<<endl;
//ui->spinBox->setValue(arg1.toInt());
if (arg1.compare("24")==0){
ui->spinBox->setValue(0);
hour=0;
}else if (arg1.compare("-1")==0){
ui->spinBox->setValue(23);
hour=59;
}
}
void Widget::secondAdd()
{
ui->spinBox_3->setValue(second+1);
}
void Widget::secondDec()
{
ui->spinBox_3->setValue(second-1);
}
void Widget::on_pushButton_4_clicked()
{
tim2->stop();
tim->start(1000);
}
void Widget::on_pushButton_5_clicked()
{
tim->stop();
tim2->stop();
}
void Widget::on_pushButton_6_clicked()
{
tim->stop();
tim2->start(1000);
}
void Widget::on_pushButton_clicked()
{
timDao->singleInsertData(t[0],t[1],t[2]);
this->close();
}
void Widget::on_pushButton_2_clicked()
{
this->close();
}
void Widget::on_pushButton_3_clicked()
{
t[0]=hour;
t[1]=min;
t[2]=second;
}
main.cpp:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
内容仅供参考