Qt實現的計算器
寫在前邊:這篇文章只是來帶著大家一起實現一個基於Qt的計算器。中間會出現很多概念,我們不做拓展介紹,大家只要知道怎麼用就好,如果有需要我們後續再詳細的對每個模組解析。
1.首先介紹一下Qt,儘管大家再明白不過了。Qt是一個1991年由Qt Company開發的跨平臺C++圖形使用者介面應用程式開發框架。它既可以開發GUI程式,也可用於開發非GUI程式,比如控制檯工具和伺服器。是一個面向物件的框架。由於其良好的跨平臺性以及適當的封裝,使得它成為很多C++程式設計師(當然,QT發展到現在已經是一個很完備的IDE,支援java以及安卓等)寫介面的首選。
2.signal&slot機制。也就是Qt獨創的訊號和槽的機制。這種機制其實在現在是很常用的,但是現在很多用來完成介面的語言已經把這一機制封裝的十分簡潔,用起來就十分的方便。至於這個機制的作用我們就不再詳解,這個機制的作用我們就不再繼續的深入討論了,現在我們只需要知道的就是他是用來給按鈕新增事件的。什麼?什麼叫做給按鈕新增時間?給按鈕新增時間值得是點選按鈕要做的事情,比如說我們點選刪除按鈕,就會刪除檔案,就是這個意思。
3.訊號的槽的實現原理:connect函式/直接轉到槽函式。很多同學上來就是無法理解什麼叫做槽什麼叫做訊號。槽其實很簡單,槽就是函式。而且是一類很特殊的函式,之所以說它特殊,是因為它的很多東西都是固定的:它的功能就是為了處理對應的訊號,它的返回型別就是void,它只能被這樣宣告:public slots/private slots/protected/slots。訊號就是按鈕的想要說的話,例如,我們假如有一個按鈕被點選,他就會發射一個我被點選了的訊號,這個訊號被槽接收,槽也就是這個函式做出處理,例如,如果這個槽接收到被點選的訊號他可能會說一句話:哪個膽子大的敢點選你,老子去安排他。然而,這個槽該如何接收訊號呢?訊號發射出去但是槽接收不到啊,這個時候connect就出現了。connect函式是將訊號和槽連結起來的一個重要的中間支援。connect有四個引數我們給出這個函式呼叫時的一般形式:connect(a,b,c,d)。這四個引數的意義也是很好記的,第一個是訊號發射的物件,第二個是訊號的型別,第三個是當前接收訊號的物件,第四個是物件的槽函式,也就是槽。沒看懂?OK我們來個栗子解釋一下:
connect(ui->first,SIGNAL(clicked(bool)),this,SLOT(button_1_clicked()));對於這個connect我們來詳細的解釋一下。
首先是第一個引數,說明我們的UI檔案裡面有一個叫做first的按鈕,第二個引數說明這個按鈕發射出來的訊號是被點選(注意:這裡的訊號是系統的內建訊號,就是說不用你自己定義,直接抄上去就可以用的。當然也可以自定義按鈕的訊號,這裡我們就不在深入的探討了,這裡用不到)。第三個引數我們也不用管,直接寫上this就好,它表示當前物件接收訊號,第四個就是我們的槽函數了。這個函式是由我們自己定義的一個函式。這樣就可以完成了按鈕和它對應的處理函式的連結了。當然了,這看起來可能有點複雜,也有一種簡單的方法,就是在視覺化佈局的時候佈局按鈕的時候我們可以直接找到這個按鈕的屬性,然後轉到槽,這樣即使不使用connect也是可以的。
有了上面的知識我們就來實現一下計算器。我們首先分析一下這個問題:我們需要在輸入框中獲取當前使用者輸入的字串,然後再設計函式實現對這個字串的計算之後再輸出到文字顯示框。那麼其實我們程式的模組已經很清楚了:資料獲取&資料處理。 4.資料獲取的實現:這個模組要求我們實時的將按鈕點選對應的字元加到原字串上並顯示出來,那麼我們首先需要一個字串,這個字串被所有的函式共享,所以我們把它定義為類的一個私有的成員變數。我們來具體分析一個:如果我點選代表數字1的按鈕,那麼當前字串就需要加上1,也就是執行s+="1",之後再顯示到文字框內。也就是set這個文字框內的值。然後對每個按鈕做這樣的對映,就可以完成表示式的顯示。
5.獲取完字串之後,我們需要定義相應的處理函式計算表示式的值。這是一個經典的演算法問題,中綴表示式的計算,常用的方法就是首先轉為字尾表示式然後再計算字尾表示式,這會使用一種資料結構:棧。這個演算法的實現我就不再詳細的說了,現在VS裡面把演算法弄好再移植到Qt,因為VS除錯功能十分強大,要是在QT裡面直接寫,會出現很多難受的錯誤,又不好除錯。
6.ui檔案的設計,大佬們都是不需要視覺化的操作的,他們都是直接寫程式碼來完成介面的設計,而我還是需要來回的拖控制元件,佈局介面。ui檔案的設計是一個很重要的模組,建議給每一個控制元件一個名字,這個名字可以反映它的功能,並且具有相同的命名規則,例如首字母大寫啊什麼的,這會在寫後臺的處理函式,也就是槽函式的時候帶來很大的幫助,因為你不用一直去翻UI來看這個控制元件的名稱。我的UI就不附上了,大家可以在connect函式中看到每個控制元件的名稱,我會把這個介面的XML檔案附上。
7.具體程式碼:
.h:
#ifndef CAL_H
#define CAL_H
#include<QString>
#include <QMainWindow>
#include<QStringList>
namespace Ui {
class cal;
}
class cal : public QMainWindow
{
Q_OBJECT
public:
explicit cal(QWidget *parent = 0);
~cal();
private:
QString s;
Ui::cal *ui;
private slots:
void button_0_clicked();
void button_1_clicked();
void button_2_clicked();
void button_3_clicked();
void button_4_clicked();
void button_5_clicked();
void button_6_clicked();
void button_7_clicked();
void button_8_clicked();
void button_9_clicked();
void button_ac_clicked();
void button_result_clicked();
void button_mul_clicked();
void button_devide_clicked();
void button_add_clicked();
void button_sub_clicked();
void button_sin_clicked();
void button_cos_clicked();
void button_tan_clicked();
void button_sqrt_clicked();
void button_pow_clicked();
void button_ln_clicked();
void button_log_clicked();
void button_point_clicked();
void button_mod_clicked();
void button_AC_clicked();
void button_left_clicked();
void button_right_clicked();
void Cal5();
private:
QByteArray Cal2();
double Cal3(double a,char op,double b);
double Cal4(char op,double a);
QStringList stackChange;
QStringList calculateProcess;
bool flag;
bool buttonFlag;
int pri[256];
bool one[256];
};
#endif // CAL_H
.cpp:
#include "cal.h"
#include "ui_cal.h"
#include<QString>
#include<QStack>
#include<QDebug>
#include<QColor>
#include<QMap>
#include<QByteArray>
#include<qmath.h>
cal::cal(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::cal)
{
ui->setupUi(this);
connect(ui->first,SIGNAL(clicked(bool)),this,SLOT(button_1_clicked()));
connect(ui->zero,SIGNAL(clicked(bool)),this,SLOT(button_0_clicked()));
connect(ui->second,SIGNAL(clicked(bool)),this,SLOT(button_2_clicked()));
connect(ui->third,SIGNAL(clicked(bool)),this,SLOT(button_3_clicked()));
connect(ui->four,SIGNAL(clicked(bool)),this,SLOT(button_4_clicked()));
connect(ui->five,SIGNAL(clicked(bool)),this,SLOT(button_5_clicked()));
connect(ui->six,SIGNAL(clicked(bool)),this,SLOT(button_6_clicked()));
connect(ui->seven,SIGNAL(clicked(bool)),this,SLOT(button_7_clicked()));
connect(ui->eight,SIGNAL(clicked(bool)),this,SLOT(button_8_clicked()));
connect(ui->nine,SIGNAL(clicked(bool)),this,SLOT(button_9_clicked()));
connect(ui->add,SIGNAL(clicked(bool)),this,SLOT(button_add_clicked()));
connect(ui->sub,SIGNAL(clicked(bool)),this,SLOT(button_sub_clicked()));
connect(ui->mul,SIGNAL(clicked(bool)),this,SLOT(button_mul_clicked()));
connect(ui->Divide,SIGNAL(clicked(bool)),this,SLOT(button_devide_clicked()));
connect(ui->Delete,SIGNAL(clicked(bool)),this,SLOT(button_ac_clicked()));
// connect(ui->Cal,SIGNAL(clicked(bool)),this,SLOT(button_result_clicked()));
connect(ui->sin,SIGNAL(clicked(bool)),this,SLOT(button_sin_clicked()));
connect(ui->cos,SIGNAL(clicked(bool)),this,SLOT(button_cos_clicked()));
connect(ui->tan,SIGNAL(clicked(bool)),this,SLOT(button_tan_clicked()));
// connect(ui->ln,SIGNAL(clicked(bool)),this,SLOT(button_ln_clicked()));
connect(ui->log,SIGNAL(clicked(bool)),this,SLOT(button_log_clicked()));
connect(ui->pow,SIGNAL(clicked(bool)),this,SLOT(button_pow_clicked()));
//connect(ui->Cal,SIGNAL(clicked(bool)),this,SLOT(Cal()));
connect(ui->point,SIGNAL(clicked(bool)),this,SLOT(button_point_clicked()));
connect(ui->AC,SIGNAL(clicked(bool)),this,SLOT(button_AC_clicked()));
connect(ui->left,SIGNAL(clicked(bool)),this,SLOT(button_left_clicked()));
connect(ui->right,SIGNAL(clicked(bool)),this,SLOT(button_right_clicked()));
connect(ui->Cal,SIGNAL(clicked(bool)),this,SLOT(Cal5()));
connect(ui->sqrt,SIGNAL(clicked(bool)),this,SLOT(button_sqrt_clicked()));
connect(ui->mod,SIGNAL(clicked(bool)),this,SLOT(button_mod_clicked()));
connect(ui->ln,SIGNAL(clicked(bool)),this,SLOT(button_ln_clicked()));
QPalette pal = this->palette();
pal.setColor(QPalette::Window,QColor(120,120,120));
this->setPalette(pal);
ui->lineEdit->setPalette(pal);
ui->lineEdit->setStyleSheet("font-size:40px;border-width:0;");
ui->lineEdit->setAlignment(Qt::AlignRight);
}
cal::~cal()
{
delete ui;
}
void cal::button_0_clicked()
{
s+="0";
ui->lineEdit->setText(s);
}
void cal::button_1_clicked()
{
s+="1";
ui->lineEdit->setText(s);
}
void cal::button_2_clicked()
{
s+="2";
ui->lineEdit->setText(s);
}
void cal::button_3_clicked()
{
s+="3";
ui->lineEdit->setText(s);
}
void cal::button_4_clicked()
{
s+="4";
ui->lineEdit->setText(s);
}
void cal::button_5_clicked()
{
s+="5";
ui->lineEdit->setText(s);
}
void cal::button_6_clicked()
{
s+="6";
ui->lineEdit->setText(s);
}
void cal::button_7_clicked()
{
s+="7";
ui->lineEdit->setText(s);
}
void cal::button_8_clicked()
{
s+="8";
ui->lineEdit->setText(s);
}
void cal::button_9_clicked()
{
s+="9";
ui->lineEdit->setText(s);
}
void cal::button_add_clicked()
{
s+="+";
ui->lineEdit->setText(s);
}
void cal::button_sub_clicked()
{
s+="-";
ui->lineEdit->setText(s);
}
void cal::button_mul_clicked()
{
s+="*";
ui->lineEdit->setText(s);
}
void cal::button_devide_clicked()
{
s+="/";
ui->lineEdit->setText(s);
}
void cal::button_result_clicked()
{
ui->lineEdit->setText(s);
}
void cal::button_ac_clicked()
{
s="";
ui->lineEdit->setText(s);
}
void cal::button_sin_clicked()
{
s+="sin";
ui->lineEdit->setText(s);
}
void cal::button_cos_clicked()
{
s+="cos";
ui->lineEdit->setText(s);
}
void cal::button_tan_clicked()
{
s="tan";
ui->lineEdit->setText(s);
}
void cal::button_sqrt_clicked()
{
s+="Sqrt";
ui->lineEdit->setText(s);
}
void cal::button_pow_clicked()
{
s+="^";
ui->lineEdit->setText(s);
}
void cal::button_log_clicked()
{
s+="log";
ui->lineEdit->setText(s);
}
void cal::button_ln_clicked()
{
s+="ln";
ui->lineEdit->setText(s);
}
void cal::button_point_clicked()
{
s+=".";
ui->lineEdit->setText(s);
}
void cal::button_left_clicked()
{
s+="(";
ui->lineEdit->setText(s);
}
void cal::button_right_clicked()
{
s+=")";
ui->lineEdit->setText(s);
}
void cal::button_mod_clicked()
{
s+="%";
ui->lineEdit->setText(s);
}
void cal::button_AC_clicked()
{
ui->lineEdit->backspace();
}
QByteArray cal::Cal2()
{
pri['+']=1;one['+']=false;
pri['-']=1;one['-']=false;
pri['*']=2;one['*']=false;
pri['/']=2;one['/']=false;
pri['%']=2;one['%']=false;
pri['^']=3;one['^']=false;
pri['@']=3;one['@']=true;
pri['s']=3;one['s']=true;
pri['c']=3;one['c']=true;
pri['t']=3;one['t']=true;
pri['l']=3;one['l']=true;
pri['p']=3;one['p']=true;
pri['S']=3;one['S']=true;
pri['L']=3;one['L']=true;
QString in2=this->s;
QByteArray in=in2.toLocal8Bit();
QByteArray out;
QStack<char>op;
for(int i=0;i<in.size();i++)
{
if(in[i]>='0'&&in[i]<='9')out.push_back(in[i]);
else if(in[i]=='(')op.push(in[i]);
else if(in[i]==')')
{
while(op.top()!='(')
{
out.push_back(op.top());
op.pop();
}
op.pop();
}
else if(one[in[i]]||(in[i]=='-'&&(i==0||!isdigit(in[i-1]))))
{
if(in[i]=='-')
{
op.push('@');
}
else if(in[i]=='s')
{
op.push('s');
i+=2;
}
else if(in[i]=='c')
{
op.push('c');
i+=2;
}
else if(in[i]=='t')
{
op.push('t');
i+=2;
}
else if(in[i]=='l')
{
op.push('l');
i++;
}
else if(in[i]=='S')
{
op.push('S');
i+=3;
}
else if(in[i]=='L')
{
op.push('L');
i+=2;
}
else op.push(in[i]);
}
else
{
while((!op.empty())&&pri[op.top()]>=pri[in[i]])
{
//操作符棧內優先順序高
out.push_back(op.top());
op.pop();
}
op.push(in[i]);
}
}
while(!op.empty())
{
out.push_back(op.top());
op.pop();
}
return out;
}
double cal::Cal3(double a, char op, double b)
{
switch (op){
case '+':return a+b;
case '-':return a-b;
case '*':return a*b;
case '/':return a/b;
case '%':return (int)a%(int)b;
case '^':return qPow(a,b);
}
}
double cal::Cal4(char op, double a)
{
if(op=='@')return -a;
else if(op=='s')return qSin(a);
else if(op=='c')return qCos(a);
else if(op=='t')return qTan(a);
else if(op=='S')return qSqrt(a);
else if(op=='l')return qLn(a);
else if(op=='L') return (qLn(a)/qLn(10));
}
void cal::Cal5()
{
QByteArray in=this->Cal2();
QStack<double>num;
for(int i=0;i<in.size();i++){
if(in[i]>='0'&&in[i]<='9')num.push(in[i]-'0');
else if(one[in[i]]){
double a=num.top();num.pop();
num.push(Cal4(in[i],a));
}else{
double a=num.top();num.pop();
double b=num.top();num.pop();
num.push(Cal3(b,in[i],a));
}
}
double a=num.top();
QString tem=QString::number(a,10,5);
ui->lineEdit->setText(tem);
}
main函式:
#include "cal.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
cal w;
w.show();
return a.exec();
}
XML檔案:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>cal</class>
<widget class="QMainWindow" name="cal">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<height>464</height>
</rect>
</property>
<property name="windowTitle">
<string>cal</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>10</x>
<y>0</y>
<width>321</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>0.00</string>
</property>
</widget>
<widget class="QPushButton" name="mod">
<property name="geometry">
<rect>
<x>11</x>
<y>46</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>%</string>
</property>
</widget>
<widget class="QPushButton" name="sqrt">
<property name="geometry">
<rect>
<x>96</x>
<y>46</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Sqrt</string>
</property>
</widget>
<widget class="QPushButton" name="left">
<property name="geometry">
<rect>
<x>266</x>
<y>46</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>(</string>
</property>
</widget>
<widget class="QPushButton" name="pow">
<property name="geometry">
<rect>
<x>181</x>
<y>46</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>^</string>
</property>
</widget>
<widget class="QPushButton" name="right">
<property name="geometry">
<rect>
<x>11</x>
<y>99</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>)</string>
</property>
</widget>
<widget class="QPushButton" name="AC">
<property name="geometry">
<rect>
<x>96</x>
<y>99</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>AC</string>
</property>
</widget>
<widget class="QPushButton" name="Delete">
<property name="geometry">
<rect>
<x>181</x>
<y>99</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>CLEAR</string>
</property>
</widget>
<widget class="QPushButton" name="Divide">
<property name="geometry">
<rect>
<x>266</x>
<y>99</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>/</string>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
<property name="autoRepeatInterval">
<number>200</number>
</property>
</widget>
<widget class="QPushButton" name="second">
<property name="geometry">
<rect>
<x>96</x>
<y>152</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>2</string>
</property>
</widget>
<widget class="QPushButton" name="first">
<property name="geometry">
<rect>
<x>11</x>
<y>152</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>1</string>
</property>
</widget>
<widget class="QPushButton" name="mul">
<property name="geometry">
<rect>
<x>266</x>
<y>152</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>*</string>
</property>
</widget>
<widget class="QPushButton" name="third">
<property name="geometry">
<rect>
<x>181</x>
<y>152</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>3</string>
</property>
</widget>
<widget class="QPushButton" name="six">
<property name="geometry">
<rect>
<x>181</x>
<y>205</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>6</string>
</property>
</widget>
<widget class="QPushButton" name="four">
<property name="geometry">
<rect>
<x>11</x>
<y>205</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>4</string>
</property>
</widget>
<widget class="QPushButton" name="five">
<property name="geometry">
<rect>
<x>96</x>
<y>205</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>5</string>
</property>
</widget>
<widget class="QPushButton" name="sub">
<property name="geometry">
<rect>
<x>266</x>
<y>205</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
<widget class="QPushButton" name="seven">
<property name="geometry">
<rect>
<x>11</x>
<y>258</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>7</string>
</property>
</widget>
<widget class="QPushButton" name="add">
<property name="geometry">
<rect>
<x>266</x>
<y>258</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>+</string>
</property>
</widget>
<widget class="QPushButton" name="eight">
<property name="geometry">
<rect>
<x>96</x>
<y>258</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>8</string>
</property>
</widget>
<widget class="QPushButton" name="nine">
<property name="geometry">
<rect>
<x>181</x>
<y>258</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>9</string>
</property>
</widget>
<widget class="QPushButton" name="cos">
<property name="geometry">
<rect>
<x>96</x>
<y>311</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>cos</string>
</property>
</widget>
<widget class="QPushButton" name="sin">
<property name="geometry">
<rect>
<x>11</x>
<y>311</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>sin</string>
</property>
</widget>
<widget class="QPushButton" name="tan">
<property name="geometry">
<rect>
<x>181</x>
<y>311</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>tan</string>
</property>
</widget>
<widget class="QPushButton" name="Cal">
<property name="geometry">
<rect>
<x>266</x>
<y>311</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>=</string>
</property>
</widget>
<widget class="QPushButton" name="point">
<property name="geometry">
<rect>
<x>181</x>
<y>364</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>.</string>
</property>
</widget>
<widget class="QPushButton" name="ln">
<property name="geometry">
<rect>
<x>11</x>
<y>364</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>ln</string>
</property>
</widget>
<widget class="QPushButton" name="log">
<property name="geometry">
<rect>
<x>96</x>
<y>364</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>log</string>
</property>
</widget>
<widget class="QPushButton" name="zero">
<property name="geometry">
<rect>
<x>266</x>
<y>364</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>352</width>
<height>23</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>