The Link Your Class | http://t.csdnimg.cn/xdDRg |
---|---|
The Link of Requirement of This Assignment | https://bbs.csdn.net/topics/617378696 |
The Aim of This Assignment | Back-end separation calculator programming |
MU STU ID and FZU STU ID | 21124671_832101213 |
Link to the finished project code and coding standard(codestyle): code address
CONTENTS
I. PSP form
Personal Software Process Stages | Estimated Time(minutes) | Actual Time(minutes) |
---|---|---|
Planning | ||
• Estimate | 30 | 40 |
Development | ||
• Analysis | 30 | 30 |
• Design Spec | 30 | 30 |
• Design Review | 10 | 10 |
• Coding Standard | 20 | 30 |
• Design | 40 | 30 |
• Coding | 360 | 420 |
• Code Review | 60 | 90 |
• Test | 30 | 30 |
Reporting | ||
• Test Report | 60 | 60 |
• Size Measurement | 10 | 10 |
• Postmortem & Process Improvement Plan | 10 | 10 |
Sum | 690 | 790 |
II. Problem-solving ideas
In order to implement the calculator, I firstly searched for a variety of methods on Internet. After a simple search, I chose to use qt to complete the calculator. For convenience, I chose to use visual studio to assist.
QT is very easy and convenient to construct a visual interface. Then it is possible to write the logic of the individual buttons through visual studio.
I can have a basic understanding of QT through the project. I learnt how to construct the basic visual interface as well.
III. Design and implementation process
1. Front-end
I use QT designer to design the surface. I create 2 windows, which are the calculator and history. Style sheet is used to make the interface more beautiful.
In the calculator, perform different functions according to different click events. For example, digits and dot are different from operators. There are also other function buttons.
Qvector is used to access expressions and results during operations and perform different functions depending on eace case of bit of the Qvector.
2. Back-end
I used to use mysql to connect the database directly but failed many times. So to be replaced I use ODBC to connect the database.
The table is manipulated bt executing sql statements.
Next is the process.
When calculator is open, clear the table “history” in the database “calculator”.
When users push “=”, expression is sented to the table “history” in the database"calculator".
When users push “ANS”, read the latest field in the table and display it in the lineEdit.
When users push “history”, the window of history is shown and showEvent is triggered. In the showEvent, database is connected and the latest 10 fields of the table are read in turn and then displayed in the lineEdits in the window one by one.
3. Flowchart
IV. Code Explanation
1. Front-end
basic interface of calculator
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>calculatorClass</class>
<widget class="QWidget" name="calculatorClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>500</height>
</size>
</property>
<property name="windowTitle">
<string>calculator</string>
</property>
<property name="styleSheet">
<string notr="true">*
{
border:none;
background-color:rgb(238, 236, 236);
}
Push button of calculator
QPushButton
{
background-color:rgb(243, 243, 243);
}
QPushButton:hover
{
border:1px solid rgb(193, 193, 193);
background-color:rgb(220, 220, 220);
}
QPushButton#btn_0,#btn_1,#btn_2,#btn_3,#btn_4,#btn_5,#btn_6,#btn_7,#btn_8,#btn_9
{
font:bold 12pt'微软雅黑';
background-color:rgb(252, 252, 252);
}
QPushButton#btn_0:hover,#btn_1:hover,#btn_2:hover,#btn_3:hover,#btn_4:hover,#btn_5:hover,#btn_6:hover,#btn_7:hover,#btn_8:hover,#btn_9:hover
{
border:1px solid rgb(193, 193, 193);
background-color:rgb(220, 220, 220);
}
basic interface of history
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>HistoryClass</class>
<widget class="QWidget" name="HistoryClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>200</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>400</height>
</size>
</property>
<property name="windowTitle">
<string>History</string>
</property>
<property name="styleSheet">
<string notr="true">*
{
border:none;
background-color:rgb(238, 236, 236);
}
lineEdit of history
QLineEdit
{
background-color:rgb(252, 252, 252);
}
String of calculator and history is too long so it won’t be put here
Main program
calculator
Head file
#pragma once
#include <QtWidgets/QWidget>
#include "ui_calculator.h"
#include "History.h"
QT_BEGIN_NAMESPACE
namespace Ui { class calculatorClass; };
QT_END_NAMESPACE
class calculator : public QWidget
{
Q_OBJECT
public:
calculator(QWidget *parent = nullptr);
~calculator();
void iniUI();
bool isInteger(double n);
void lineEditClear();//clear the lineEdit and lineEdit_exp, initial
History ht;
public slots:
void onButtonGroupClicked(QAbstractButton* btn);
void showHistory();//show the window of history
private:
Ui::calculatorClass *ui;
QVector<QVariant> vec;//save the expressions and results
QString prevBtn;//save the previous button
bool start;//judge if start of a expression
};
library
#include "calculator.h"
#include "database.h"
#include <qbuttongroup.h>
#include <qdebug.h>
#include <qvector.h>
#include <iomanip>
#include <iostream>
#include <math.h>
calculator
calculator::calculator(QWidget *parent)
: QWidget(parent)
, ui(new Ui::calculatorClass())
{
ui->setupUi(this);
iniUI();
if (!createConnection()) qInfo() <<"fail"; //create connection to the database
else qInfo() << "success";
connect(ui->pushButton_history, SIGNAL(clicked()), this, SLOT(showHistory()));//connect the window of history the the pushBotton of history
}
iniUI
void calculator::iniUI()
{
auto buttonGroup = new QButtonGroup(this);//to save buttons
auto btnlist = findChildren<QPushButton*>();
QSqlDatabase db2 = QSqlDatabase::database("connection1"); //connect the database
QSqlQuery query2(db2);
for (auto btn : btnlist)
{
buttonGroup->addButton(btn);
}//find all buttons
connect(buttonGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &calculator::onButtonGroupClicked);
vec.resize(5);
query2.exec("delete from history");//initial the table history
}
showHistory
void calculator::showHistory()//show the window of history
{
ht.show();
}
detect integer
bool calculator::isInteger(double n)
{
if (n - int(n) == 0)
{
return true;
}
else return false;
}
clear all
void calculator::lineEditClear()//clear the lineEdit and lineEdit_exp, initial
{
ui->lineEdit->clear();
ui->lineEdit->insert("0");
ui->lineEdit_exp->clear();
vec.clear();
vec.resize(5);
}
click events
void calculator::onButtonGroupClicked(QAbstractButton* btn)
start
QString expression;
bool equal = false; //if push the "=", equal is true
qreal val = ui->lineEdit->text().toDouble();
qInfo() << btn->text();
QString name = btn->text();
QSqlDatabase db2 = QSqlDatabase::database("connection1"); //connect the database
QSqlQuery query2(db2);
if push digits or dot
if (name>="0" && name<="9" ||name ==".")
{
if (start&&vec[1].isNull()) //if user push the digit, cover the previous result, if push the operator, the previous result is regarded as x in the expression
{
lineEditClear();
start = false;
}
if (name != "."&& ui->lineEdit->text()=="0") ui->lineEdit->clear();
if (prevBtn == "+"|| prevBtn == "-" || prevBtn == "*" || prevBtn == "/" || prevBtn == "%")
{
ui->lineEdit->clear();
}
if (name == "." && !isInteger(val));
else ui->lineEdit->insert(name);
}//for digit or dot
if push operators
else if (name == "+")
{
if (vec[2].isNull())
{
vec[0] = val;
vec[1] = "+";
}
}
else if (name == "-")
{
if (vec[2].isNull())
{
vec[0] = val;
vec[1] = "-";
}
}
else if (name == "*")
{
if (vec[2].isNull())
{
vec[0] = val;
vec[1] = "*";
}
}
else if (name == "/")
{
if (vec[2].isNull())
{
vec[0] = val;
vec[1] = "/";
}
}
else if (name == "%")
{
if (vec[2].isNull())
{
vec[0] = val;
vec[1] = "%";
}
}
//for operators
if push “=” to end the expression
else if (name == "=")
{
start = true;
equal = true;
vec[2] = val;
vec[3] = "=";
expression = vec[0].toString() + vec[1].toString() + vec[2].toString() + "=";
if (vec[1] == "+")
{
vec[4] = vec[0].toDouble() + vec[2].toDouble();
}
if (vec[1] == "-")
{
vec[4] = vec[0].toDouble() - vec[2].toDouble();
}
if (vec[1] == "*")
{
vec[4] = vec[0].toDouble() * vec[2].toDouble();
}
if (vec[1] == "/")
{
vec[4] = vec[0].toDouble() / vec[2].toDouble();
}
if (vec[1] == "%")
{
vec[4] = vec[0].toInt() % vec[2].toInt();
}
vec[4] = round(vec[4].toDouble()*100)/100;
ui->lineEdit->setText(vec[4].toString());
//insert the expression into the table
query2.clear();
query2.prepare("insert into history (x, operator, y, result) values (?, ?, ?, ?)");
query2.addBindValue(vec[0]);
query2.addBindValue(vec[1]);
query2.addBindValue(vec[2]);
query2.addBindValue(vec[4]);
query2.exec();
QVariant temp = vec[4];
vec.clear();
vec.resize(5);
vec[0] = temp;
}
clear, clear enter, delete
//clear
else if (name=="C")
{
lineEditClear();
}
//clear error
else if (name == "CE")
{
ui->lineEdit->clear();
ui->lineEdit->insert("0");
}
//delete
else if (name == "Del")
{
if (vec[1].isNull())
{
ui->lineEdit->setCursorPosition(ui->lineEdit->cursorPosition() - 1);
ui->lineEdit->del();
}
else vec[1] = NULL;
}
1/x and +/-
//upside down
else if (name == "+/-")
{
QString temp = ui->lineEdit->text();
if (val >= 0) ui->lineEdit->setText("-" + temp);
else ui->lineEdit->setText(temp.mid(1, temp.length() - 1));
}
else if (name == "l/x")
{
QVariant val_ = 1 / val;
ui->lineEdit->setText(val_.toString());
}
if push “ANS”
else if (name == "ANS")
{
QSqlQuery expressions = db2.exec(" select * from history");//all field in the history
if (expressions.last())//the last field
{
//ui->lineEdit_exp->setText(expressions.value("x").toString()+ expressions.value("operator").toString()+ expressions.value("y").toString()+"=");
ui->lineEdit->setText(expressions.value("result").toString());
}
}
end
ui->lineEdit_exp->clear();
if (!equal)//lineEdit_exp display the current expression which is incomplete
{
for (auto var : vec) ui->lineEdit_exp->insert(var.toString());
}
else //lineEdit_exp display the expression of the current result
{
ui->lineEdit_exp->setText(expression);
equal = false;
}
prevBtn = name;
2. Back-end
head file of database
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QMessageBox>
#include <QVariantList>
#include <QDebug>
#include <QString>
static bool createConnection() {
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC","connection1");
db.setHostName("127.0.0.1");
db.setPort(3306);
db.setDatabaseName("calculator"); //data source name in ODBC, which is the same as the database name
db.setUserName("root");
db.setPassword("968574123Sjz"); //password
// open the database
if (!db.open()) { // if fail
return false;
}
else {
return true;
}
}
head file of the history window
#pragma once
#include <QWidget>
#include "ui_History.h"
class History : public QWidget
{
Q_OBJECT
public:
History(QWidget *parent = nullptr);
~History();
private:
Ui::HistoryClass ui;
protected:
virtual void showEvent(QShowEvent* event) override;//execute when the window of history is displayed
};
main program of history window
History
History::History(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
if (!createConnection()) qInfo() << "fail"; //create connection to the database
else qInfo() << "success";
}
showEvent
void History::showEvent(QShowEvent* event)
{
QSqlDatabase db2 = QSqlDatabase::database("connection1"); //connect the database
QSqlQuery query2(db2);
QVector<QLineEdit*> lineEdits;
lineEdits.resize(11);
lineEdits = { ui.lineEdit_1, ui.lineEdit_2, ui.lineEdit_3, ui.lineEdit_4, ui.lineEdit_5, ui.lineEdit_6, ui.lineEdit_7, ui.lineEdit_8, ui.lineEdit_9, ui.lineEdit_10 };//store lineEdits for traversal
int i = 0;
//display past 10 or less expressions in the lineEdits of window
QSqlQuery expressions = db2.exec(" select * from history");
if (expressions.last())
ui.lineEdit_1->setText(expressions.value("x").toString() + expressions.value("operator").toString() + expressions.value("y").toString() + " = " + expressions.value("result").toString());
while (expressions.previous() && ++i < 10) //the last 10 fields
lineEdits[i]->setText(expressions.value("x").toString() + expressions.value("operator").toString() + expressions.value("y").toString() + " = " + expressions.value("result").toString());
}
V. Presentation
zoom in and out of the application
basic function(add, substract, multiply, divide and remainder)
1/x
+/-(upside down)
CE(clear enter) and C(clear)
delete
ANS
History
VI. Personal Journey and Learnings
The calculator remains to be perfected. The calculator can work with only 2 numbers and complex calculations with multiple numbers are impossible.
There is some coupling between the front-end and the back-end.
It connects the local database not the cloud server.
Through the project, I have a preliminary understanding of the project process. I learn how to build a simple visual interface by qt, code with visual studio and connect both of them.
I learn how to connect database by ODBC and how to manipulate tables in the database by sql statements.
I have a relatively simple understanding of the front-end and back-end.
VII. Reference
https://blog.csdn.net/cpp_learner/article/details/109769505
https://blog.csdn.net/joey_ro/article/details/105411135