(七)计算器实例

MATLAB·gui设计简单计算器应用实例 MATLAB 程序设计基础之gui设计 简单计算器应用实例 一、实验目的 掌握Matlab图形用户界面的设计流程 二、实验内容 用matlab设计有图形界面的计算器程序,其中清空和退出功能使用菜单栏实现(例子:calculator1) 三、实验过程记录和运行结果分析 先打开matlab新建gui用户界面,构思好自己的计算机界面后右键单击查看回调函数,补充相应功能 1.相应功能:基本加减乘除操作,使... 阅读详情

开发一个支持四则运算且能识别错误计算式的计算器

 

计算器示例界面设计:

以QWidget对象作为窗口,子组件为QLineEdit对象与QPushButton对象

组件间间隔10px,按钮宽40px、高40px,文本框组件宽5 * 40px + 4 *10px、高30px

去除窗口的最小、大化按钮

固定窗口大小

禁止文本框直接输入


界面元素架构设计:

使用面向对象的继承、组合关系架构计算器

 

核心算法设计:

为了使计算器程序支持四则运算使用了三个算法:

一、将中缀表达式进行数字与运算符的分离

二、将中缀表达式转换为后缀表达式

三、计算后缀表达式得到最终结果

 

分离:
/******************************************************************************************
分离算法分析:
目的:将一串混合数字与符号的字符串分离成多个子串,每一个子串是一个数字或 运算符
 
分辨数字、正负号、运算符:
字符的值满足'0'~'9' 或 '.'时字符必然是一个数字
当一个符号(字符为'+' '-' '*' '/' '(' ')'时为符号)满足三个条件时,该符号为正负号:
(1)、符号为首字符
(2)符号前一个字符是左括号'('
(3)、符号前一个字符是字符'+' '-''*' '/'
否则符号(字符为'+' '-' '*' '/' '(' ')'时为符号)为运算符
 
具体实现分析:
遍历待分离字符串的每一个元素,
如果当前字符为数字则纳入字符串对象存储
如果当前字符是符号,则:
(1)、判断一次存储数字的对象是否为空,不为空时则说明对象已经存储了一个完整的数字,则将对象插入队列保存
(2)、判断当前的符号是正负号还是运算符,是正负号则纳入存储数字的对象,否则是运算符,则直接插入队列
将存储数字的对象插入队列(对象中可能存有最后一个数字)
*******************************************************************************************/
代码:
QQueue<QString> QCalculatorDec::split(constQString& exp)
{
   QQueue<QString> ret;             
   QString num = "";                       //保存分离出来的数字,数字可以是整数、浮点数、负数、整数
   QString pre = "";                         //当前字符的前一个字符,需要通过前一个字符的情况判断当前字符是正负号还是运算符
        
   for(int i=0; i<exp.length(); i++)         //遍历字符串exp的每一个字符
    {
       if( isDigitOrDot(exp[i]) )            //当前字符是数字或小数点
       {
           num += exp[i];                             //当前字符是数字或者小数点就放入对象num保存
           pre = exp[i];                                  //将当前字符(数字或小数点)存入变量pre,以便遍历到下一个字符的时候通过此字符判断
       }
       else if( isSymbol(exp[i]) )           //如果当前字符是符号
       {//当前是符号时,前一个符号要么为空(当前符号为正负号时),要么是一个完整的数字(当前符号为运算符时)
           if( !num.isEmpty() )          
           {
                ret.enqueue(num);           //将存有数字的对象num存入队列
 
                num.clear();                        //清空用于保存字符串的num,以便下一次存储数字
           }
                            //必须定义一个字符串对象pre去保存前一个字符,而不是[i-1]因为[i-1]可能发生前越界
           if( isSign(exp[i]) && ((pre == "") || (pre =="(") || isOperator(pre)) )
           {                 //如果当前是‘+’或‘-’并且不存在前一个字符或前一个字符为"("或操作符时,当前'+'或'-'为正负号,纳入num保存
                num += exp[i];
           }
           else  //当前的符号为运算符,单独插入队列保存
           {
                ret.enqueue(exp[i]);
           }
 
           pre = exp[i];               //将当前字符(符号)存入对象pre,便于遍历到下一个字符的时候通过此字符判断
       }
    }
 
   if( !num.isEmpty() ) //遍历完成之后num中可能存在内容(数字),需判断
    {
       ret.enqueue(num);  //对象num不为空时,将num中的内容插入队列
    }
 
   return ret;
}


中缀转后缀:
中缀转后缀的前提是中缀表达式中的括号应该匹配
/***********************************************************************************
匹配算法分析:
目的:判断包含数字与运算符的队列对象中的左右括号是否匹配
 
判断匹配依据:
匹配:左括号应该先于右括号出现,且左括号数量与右括号数量相等
不匹配:(1)右括号先于左括号出现、(2)左括号与右括号的数量不相等
 
具体实现分析:
如果左右括号匹配,必然的,左括号先于右括号出现、且一个左括号会对应一个右括号,使用栈与队列来判断括号的匹配性
遍历队列中每个元素,如果遍历到左括号则入栈,由于算式中的右括号必然出现在左括号之后,因此当遍历到右括号时,栈顶应该存在左括号,否则说明右括号先于左括号出现,不匹配情况一
如果遍历到右括号且栈顶元素是左括号时,弹出栈顶的左括号,当遍历完成时,如果左右括号匹配,那么栈应该为空,否则说明左括号数量多于右括号,不匹配情况二
 
 
转换算法分析:
目的:在队列对象中左右括号匹配的情况下将中缀表达式转化为后缀表达式
 
中缀转后缀的关键:
去除括号的情况下保留运算顺序
转换后可以顺序计算出最终结果
转换前后数字出现次序不变
运算符出现次序依赖于实际运算顺序
 
具体实现分析:
利用栈先入后出的特性控制运算顺序,使用栈与队列来完成中缀到后缀的转换
循环弹出中缀表达式队列中的每一个元素直到队列为空;
(1)、如果当前弹出元素为数字,为保证转换前后数字出现次序不变,直接输出数字;
(2)、如果当前弹出元素为运算符(运算符('+' '-''*' '/')有优先级,要保证优先级高的运算符先输出,但需要比较才能知道优先级),需要将当前弹出运算符入栈以便于与此后弹出的运算符比较优先级,当栈中有运算符时,当前弹出运算符应该与栈中的运算符做优先级的比较,为保证优先级高的运算符先输出,应该循环输出比当前弹出运算符优先级高的栈顶运算符直到低于当前弹出运算符,此时将当前弹出运算符入栈,即便当前弹出的所有运算符优先级都高于栈顶运算符,由于栈的特定,优先级高的运算符也会始终在栈顶,即优先级高的运算符始终会先输出
(3)、如果当前弹出元素为左括号,则入栈
(4)、如果当前弹出元素为右括号,则循环输出栈中运算符直到左括号(以左右括号为标志输出栈顶元素是为了区分括号作用部分与括号未作用部分),此时弹出左括号(丢弃)
(5)、如果弹出元素不属于数字或者运算符,则说明出现了其他符号,应该提示错误,并保证输出为空(错误之后无需计算)
输出栈中所有剩余运算符(由于输出的条件的原因,栈中可能还存在运算符)
 
***********************************************************************************/
 
代码:
boolQCalculatorDec::match(QQueue<QString>& exp) 
{
   bool ret = true;
   int len = exp.length();
   QStack<QString> stack;            //栈用于存储左括号
 
   for(int i=0; i<len; i++)                                    //遍历队列中的每个QString
    {
       if( isLeft(exp[i]) )      
       {
           stack.push(exp[i]);   //当前元素是左括号入栈        }
       else if( isRight(exp[i]) )                                 //当前元素是右括号时
       {
           if( !stack.isEmpty() && isLeft(stack.top()) )    //栈顶是左括号时
           {
                stack.pop();                        //将栈顶的左括号弹出,发现一次右括号就应该弹一次栈中的左括号
           }
           else
           {
                ret = false;                          //当前元素是右括号,栈顶却不是左括号(栈为空),右括号先于左括号出现,括号不匹配
                break;                                            //已经发现不匹配,无需继续循环
           }
       }
    }
 
   return ret && stack.isEmpty();                 //返回时栈必须为空,否则说明括号不匹配,左括号多于右括号
}
 
bool QCalculatorDec::transform(QQueue<QString>&exp, QQueue<QString>& output)
{
   bool ret = match(exp);                        //首先检查括号是否匹配
   QStack<QString> stack;                     //栈用于存储运算符与括号
 
   output.clear();
 
   while( ret && !exp.isEmpty() )
    {
        QString e = exp.dequeue();     
 
       if( isNumber(e) )
       {
           output.enqueue(e);          //取出的头元素是数字,将元素入队到输出队列
       }
       else if( isOperator(e) )               //取出的头元素是符号则需要对比优先级
       {        //当前元素优先级小于栈顶时循环弹出栈中比当前元素优先级高的符号到输出队列中
 
           while( !stack.isEmpty() && (priority(e) <=priority(stack.top())) )  
           {       
                output.enqueue(stack.pop());
           }
 
           stack.push(e);                             //将头元素入栈以便下次比较
       }
       else if( isLeft(e) )                         //头元素是左括号
       {
           stack.push(e);                             //将头元素入栈
       }
       else if( isRight(e) )                      //头元素是右括号
       {        //栈顶元素不是左括号时循环将栈顶元素弹出到输出队列中
           while( !stack.isEmpty() && !isLeft(stack.top()) )
           {
                output.enqueue(stack.pop());
           }
 
           if( !stack.isEmpty() )                  //操作栈时栈需不为空
           {
                stack.pop();               //弹出栈顶的左括号
           }
       }
       else                             
       {                
           ret = false;                          //出现其他符号,错误
       }
    }
 
   while( !stack.isEmpty() ) //因为决定出栈的判断方式,所以栈内可能存有运算符
    {
       output.enqueue(stack.pop());
    }
 
   if( !ret )                       //遇到错误时应该将输出队列清空
    {
       output.clear();
    }
 
   return ret;
}

 


 

计算:
/********************************************************************************************************
计算算法分析:
目的:计算后缀表达式的值,得出的结果以浮点的形式显示
 
计算的关键:
左右操作数的顺序,这一顺序对减法与除法尤其重要
计算完毕时,栈中只能存在一个元素,且唯一元素数字
计算时,如果运算符是除号,应该考虑除0的情况,0不能为除数
由于浮点数在内存中的表示是不精确的,不能直接拿数字与0作比较
 
具体实现分析:
使用栈与队列完成对后缀表达式值的计算
循环弹出后缀表达式队列中的每一个元素直到队列为空;
(1)、如果弹出的元素是数字,将数字直接入栈;
(2)、如果弹出的是运算符且栈不为空则将栈顶的元素弹出作为右操作数,若栈仍不为空则再一次弹出栈顶元素作为左操作数,并根据左右操作数与运算符计算结果,如果计算结果有效则将结果入栈,否则无需继续循环,并返回错误
(3)、如果弹出的元素既不是数字也不是运算符则说明混入了其他字符,跳出循环并返回错误
后缀表达式在计算完成后栈中应该只有唯一的一个元素,且元素应该为数字,满足条件则返回值应该为计算结果,否则返回值为错误
********************************************************************************************************/
 
代码:
QStringQCalculatorDec::calculate(QQueue<QString>& exp)
{
   QString ret = "Error";
   QStack<QString> stack;                     //存储操作数的栈
//队列不为空时循环取出队列头元素
   while( !exp.isEmpty() )
    {
       QString e = exp.dequeue();
 
       if( isNumber(e) )
       {
           stack.push(e);           //头元素是数字直接入栈
       }
       else if( isOperator(e) )               //头元素是操作符
       {
           QString rp = !stack.isEmpty() ? stack.pop() : "";//弹出栈顶元素作右操作数      
           QString lp = !stack.isEmpty() ? stack.pop() : "";//再次弹出栈顶元素作左操作数
           QString result = calculate(lp, e, rp);                  //调用实际计算函数
 
           if( result != "Error" )
           {
                stack.push(result);                     //计算结果正确则将结果入栈
           }
           else
           {
                break;                         //计算结果错误则跳出循环
           }
       }
       else                                              //含有其他字符
       {
           break;               
       }
    }
         //当后缀表达式队列元素全部被处理且栈中唯一的元素为数字时,栈中的结果为有效的运算结果
   if( exp.isEmpty() && (stack.size() == 1) &&isNumber(stack.top()) )
    {
       ret = stack.pop();
    }
 
   return ret;       
}
实际计算函数:
QString QCalculatorDec::calculate(QStringl, QString op, QString r)
{
   QString ret = "Error";
 
   if( isNumber(l) && isNumber(r) )              //左右操作数有效时进行运算
    {
       double lp = l.toDouble(); 
       double rp = r.toDouble();
 
       if( op == "+" )
       {
           ret.sprintf("%f", lp +rp);
       }
       else if( op == "-" )
       {
           ret.sprintf("%f", lp - rp);
       }
       else if( op == "*" )
       {
           ret.sprintf("%f", lp * rp);
       }
       else if( op == "/" )     //当操作数为除法时,需要注意右操作数不能为0 即除数不为0
       {
                            //浮点数在内存的表示是不精确的,所以需要定义一个足够小的比较变量
           const double P = 0.000000000000001;  
           if( (-P < rp) && (rp < P) )   //如果右操作数在一个足够小的比较变量的范围内,将右操作数视为0
           {
                ret = "Error";
           }
           else
           {
                ret.sprintf("%f", lp/ rp);
           }
 
       }
       else                                       //其他符号
       {
           ret = "Error";
       }
    }
 
   return ret;
}


 

程序整体架构设计:


用户界面模块(QCalculatorUI)与业务逻辑模块(QCalculatorDec)之间相互独立,仅仅通过接口(ICalculator)相互关联,用户界面模块(QCalculatorUI)使用接口(ICalculator),业务逻辑模块(QCalculatorDec)实现接口(ICalculator),QCalculator类封装用户界面模块与业务逻辑模块。

 

用户界面:

为避免半成品对象,使用二阶构造

实现:

QCalculatorUI::QCalculatorUI() :QWidget(NULL, Qt::WindowCloseButtonHint)
{
   m_cal = NULL;           //m_cal是指向接口类的指针
}
 
bool QCalculatorUI::construct()
{
   bool ret = true;
   const char* btnText[20] =
    {
       "7", "8", "9", "+","(",
       "4", "5", "6", "-",")",
       "1", "2", "3", "*","<-",
       "0", ".", "=", "/","C",
   };
 
   m_edit = new QLineEdit(this);
 
   if( m_edit != NULL )
    {
       m_edit->move(10, 10);
       m_edit->resize(240, 30);
       m_edit->setReadOnly(true);
       m_edit->setAlignment(Qt::AlignRight);
    }
   else
    {
       ret = false;
    }
 
   for(int i=0; (i<4) && ret; i++)
    {
       for(int j=0; (j<5) && ret; j++)
       {
           m_buttons[i*5 + j] = new QPushButton(this);
 
           if( m_buttons[i*5 + j] != NULL )
           {
                m_buttons[i*5 +j]->resize(40, 40);
                m_buttons[i*5 + j]->move(10+ (10 + 40)*j, 50 + (10 + 40)*i);
               m_buttons[i*5 +j]->setText(btnText[i*5 + j]);
 
                connect(m_buttons[i*5 + j],SIGNAL(clicked()), this, SLOT(onButtonClicked()));
           }
           else
           {
                ret = false;
           }
       }
    }
 
    return ret;
}
 
QCalculatorUI* QCalculatorUI::NewInstance()
{
   QCalculatorUI* ret = new QCalculatorUI();
 
   if( (ret == NULL) || !ret->construct() )
    {
       delete ret;
       ret = NULL;
    }
 
   return ret;
}
 
void QCalculatorUI::show()
{
   QWidget::show();
 
   setFixedSize(width(), height());
}
 
void QCalculatorUI::onButtonClicked()
{
   QPushButton* btn = dynamic_cast<QPushButton*>(sender());
 
   if( btn != NULL )
    {
       QString clickText = btn->text();
 
       if( clickText == "<-" )
       {
           QString text = m_edit->text();
 
           if( text.length() > 0 )
           {
                text.remove(text.length()-1,1);
 
                m_edit->setText(text);
           }
       }
       else if( clickText == "C" )
       {
           m_edit->setText("");
       }
       else if( clickText == "=" )
       {
           if( m_cal != NULL ) //绑定好借口的情况下才调用业务逻辑模块计算
           {
               m_cal->expression(m_edit->text());        //多态发生(m_cal->expression()),将调用m_cal实际指向的类对象的虚函数
               m_edit->setText(m_cal->result());  //多态发生(m_cal->result()),将调用m_cal实际指向的类对象的虚函数
           }
       }
       else
       {
           m_edit->setText(m_edit->text() + clickText);
       }
    }
}
 
voidQCalculatorUI::setCalculator(ICalculator* cal)
{
   m_cal = cal;                //指定接口指针指向对象
}
 
ICalculator* QCalculatorUI::getCalculator()
{
   return m_cal;               //返回使用的接口(即返回实际指向对象的地址)
}
 
QCalculatorUI::~QCalculatorUI()
{
 
}


头文件:

#ifndef _QCALCULATORUI_H_
#define _QCALCULATORUI_H_
 
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
 
#include "ICalculator.h"
 
class QCalculatorUI : public QWidget
{
   Q_OBJECT
private:
   QLineEdit* m_edit;
   QPushButton* m_buttons[20];
   ICalculator* m_cal;           //指向接口类(纯虚类不能定义对象,但能定义指向纯虚类对象的指针)的指针
 
   QCalculatorUI();
   bool construct();
private slots:
   void onButtonClicked();
public:
   static QCalculatorUI* NewInstance();
   void show();
   void setCalculator(ICalculator* cal);
   ICalculator* getCalculator();
   ~QCalculatorUI();
};
 
#endif


 

业务逻辑:

实现:

#include "QCalculatorDec.h"
 
QCalculatorDec::QCalculatorDec()
{
   m_exp = "";
   m_result = "";
}
 
QCalculatorDec::~QCalculatorDec()
{
 
}
 
bool QCalculatorDec::isDigitOrDot(QChar c)
{
   return (('0' <= c) && (c <= '9')) || (c == '.');
}
 
bool QCalculatorDec::isSymbol(QChar c)
{
   return isOperator(c) || (c == '(') || (c == ')');
}
 
bool QCalculatorDec::isSign(QChar c)
{
   return (c == '+') || (c == '-');
}
 
bool QCalculatorDec::isNumber(QString s)
{
   bool ret = false;
 
   s.toDouble(&ret);
 
   return ret;
}
 
bool QCalculatorDec::isOperator(QString s)
{
   return (s == "+") || (s == "-") || (s =="*") || (s == "/");
}
 
bool QCalculatorDec::isLeft(QString s)
{
   return (s == "(");
}
 
bool QCalculatorDec::isRight(QString s)
{
   return (s == ")");
}
 
int QCalculatorDec::priority(QString s)
{
   int ret = 0;
 
   if( (s == "+") || (s == "-") )
    {
       ret = 1;
    }
 
   if( (s == "*") || (s == "/") )
    {
       ret = 2;
    }
 
   return ret;
}
 
bool QCalculatorDec::expression(constQString& exp)
{
   bool ret = false;
   QQueue<QString> spExp = split(exp);
   QQueue<QString> postExp;
 
   m_exp = exp;
 
   if( transform(spExp, postExp) )
    {
       m_result = calculate(postExp);
 
       ret = (m_result != "Error");
    }
   else
    {
       m_result = "Error";
    }
 
 
   return ret;
}
 
QString QCalculatorDec::result()
{
   return m_result;
}
 
QQueue<QString>QCalculatorDec::split(const QString& exp)
{
   QQueue<QString> ret;
   QString num = "";
   QString pre = "";
 
   for(int i=0; i<exp.length(); i++)
    {
       if( isDigitOrDot(exp[i]) )
       {
           num += exp[i];
           pre = exp[i];
       }
       else if( isSymbol(exp[i]) )
       {
           if( !num.isEmpty() )
           {
                ret.enqueue(num);
 
                num.clear();
           }
 
           if( isSign(exp[i]) && ((pre == "") || (pre =="(") || isOperator(pre)) )
           {
                num += exp[i];
           }
           else
           {
                ret.enqueue(exp[i]);
           }
 
           pre = exp[i];
       }
    }
 
   if( !num.isEmpty() )
    {
       ret.enqueue(num);
    }
 
   return ret;
}
 
boolQCalculatorDec::match(QQueue<QString>& exp)
{
   bool ret = true;
   int len = exp.length();
   QStack<QString> stack;
 
   for(int i=0; i<len; i++)
    {
       if( isLeft(exp[i]) )
       {
           stack.push(exp[i]);
       }
       else if( isRight(exp[i]) )
       {
           if( !stack.isEmpty() && isLeft(stack.top()) )
           {
                stack.pop();
           }
           else
           {
                ret = false;
                break;
           }
       }
    }
 
   return ret && stack.isEmpty();
}
 
boolQCalculatorDec::transform(QQueue<QString>& exp,QQueue<QString>& output)
{
   bool ret = match(exp);
   QStack<QString> stack;
 
   output.clear();
 
   while( ret && !exp.isEmpty() )
    {
       QString e = exp.dequeue();
 
       if( isNumber(e) )
       {
           output.enqueue(e);
       }
       else if( isOperator(e) )
       {
           while( !stack.isEmpty() && (priority(e) <=priority(stack.top())) )
           {
                output.enqueue(stack.pop());
           }
 
           stack.push(e);
       }
       else if( isLeft(e) )
       {
           stack.push(e);
       }
       else if( isRight(e) )
       {
           while( !stack.isEmpty() && !isLeft(stack.top()) )
           {
                output.enqueue(stack.pop());
           }
 
           if( !stack.isEmpty() )
           {
                stack.pop();
            }
       }
       else
       {
           ret = false;
       }
    }
 
   while( !stack.isEmpty() )
    {
       output.enqueue(stack.pop());
    }
 
   if( !ret )
    {
       output.clear();
    }
 
   return ret;
}
 
QString QCalculatorDec::calculate(QStringl, QString op, QString r)
{
   QString ret = "Error";
 
   if( isNumber(l) && isNumber(r) )
    {
       double lp = l.toDouble();
       double rp = r.toDouble();
 
       if( op == "+" )
       {
           ret.sprintf("%f", lp + rp);
       }
       else if( op == "-" )
       {
           ret.sprintf("%f", lp - rp);
       }
       else if( op == "*" )
       {
           ret.sprintf("%f", lp * rp);
       }
       else if( op == "/" )
       {
           const double P = 0.000000000000001;
 
           if( (-P < rp) && (rp < P) )
           {
                ret = "Error";
           }
           else
           {
                ret.sprintf("%f", lp/ rp);
           }
 
       }
       else
       {
           ret = "Error";
       }
    }
 
   return ret;
}
 
QStringQCalculatorDec::calculate(QQueue<QString>& exp)
{
   QString ret = "Error";
   QStack<QString> stack;
 
   while( !exp.isEmpty() )
    {
       QString e = exp.dequeue();
 
       if( isNumber(e) )
       {
           stack.push(e);
       }
       else if( isOperator(e) )
       {
           QString rp = !stack.isEmpty() ? stack.pop() : "";
           QString lp = !stack.isEmpty() ? stack.pop() : "";
           QString result = calculate(lp, e, rp);
 
           if( result != "Error" )
           {
                stack.push(result);
           }
           else
           {
                break;
           }
       }
       else
       {
           break;
       }
    }
 
   if( exp.isEmpty() && (stack.size() == 1) &&isNumber(stack.top()) )
    {
       ret = stack.pop();
    }
 
   return ret;
}
 
头文件:
#ifndef _CALCULATORCORE_H_
#define _CALCULATORCORE_H_
 
#include <QString>
#include <QStack>
#include <QQueue>
 
#include "ICalculator.h"
 
class QCalculatorDec : publicICalculator       //ICalculator为接口类(纯虚类)
{
protected:
   QString m_exp;
   QString m_result;
 
   bool isDigitOrDot(QChar c);
   bool isSymbol(QChar c);
   bool isSign(QChar c);
   bool isNumber(QString s);
   bool isOperator(QString s);
   bool isLeft(QString s);
   bool isRight(QString s);
   int priority(QString s);
   bool match(QQueue<QString>& exp);
   QString calculate(QQueue<QString>& exp);
   QString calculate(QString l, QString op, QString r);
   bool transform(QQueue<QString>& exp,QQueue<QString>& output);
   QQueue<QString> split(const QString& exp);
public:
   QCalculatorDec();
   ~QCalculatorDec();
   bool expression(const QString& exp); //重写接口类中继承的纯虚函数,满足多态条件之一
   QString result();                  //重写接口类中继承的纯虚函数,满足多态条件之一
};
 
#endif
 
接口:
#ifndef _ICALCULATOR_H_
#define _ICALCULATOR_H_
 
#include <QString>
 
//接口类:类中没有声明任何成员变量,所有成员函数都是公有的,所有成员函数都是纯虚函数,接口类用于实现多态
class ICalculator      
{
public:
         //被子类重写的成员函数expression将会变成虚函数,使用指向接口类(ICalculator)的指针指向接口类子对象且调用虚函数时发生多态,即实际调用的成员函数由接口类指针指向的对象而定
   virtual bool expression(const QString& exp) = 0;   
   virtual QString result() = 0;
};
 
#endif
 
封装类:
实现:
#include "QCalculator.h"
 
QCalculator::QCalculator()
{
}
 
bool QCalculator::construct()
{
   m_ui = QCalculatorUI::NewInstance(); 
 
   if( m_ui != NULL )  
    {
       m_ui->setCalculator(&m_cal); //使用接口,此时指向接口类的指针指向了接口类的子类,通过接口类指针调用虚函数时,将发生多态
    }
 
   return (m_ui != NULL);
}
 
QCalculator* QCalculator::NewInstance()
{
   QCalculator* ret = new QCalculator();
 
   if( (ret == NULL) || !ret->construct() )
    {
       delete ret;
       ret = NULL;
    }
 
   return ret;
}
 
 
void QCalculator::show()
{
   m_ui->show();
}
 
QCalculator::~QCalculator()
{
   delete m_ui;
}
 
头文件:
#ifndef _QCALCULATOR_H_
#define _QCALCULATOR_H_
 
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"
 
class QCalculator     //封装类,封装界面与核心算法
{
protected:
   QCalculatorUI* m_ui;            //成员指向UI对象的指针
   QCalculatorDec m_cal;           //成员业务逻辑(QCalculatorDec)对象,QCalculatorDec继承自接口类
 
   QCalculator();
   bool construct();
public:
   static QCalculator* NewInstance();
   void show();
   ~QCalculator();
};
 
#endif // QCALCULATOR_H
 
主函数:
#include <QtGui/QApplication>
 
#include "QCalculator.h" //包含封装类,类中封装了用户界面模块与业务逻辑模块
 
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QCalculator* cal = QCalculator::NewInstance();
   int ret = -1;
 
   if( cal != NULL )
    {
       cal->show();
 
       ret = a.exec();
 
       delete cal;
    }
 
   return ret;
}



 声明:

此文根据 狄泰学院唐老师的《QT实验分析教程》创作


[JavaScript实例解析]js计算器 本实例来自菜鸟教程 实例代码 HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> &lt 阅读详情

相关推荐

c++实例-实现一个简单的计算器

C++ 实例 - 实现一个简单的计算器 使用 C++ 创建一个简单的计算器,可以实现 +, -, *, / 。 实例 #include <iostream> using namespace std; int main() { char op; float num1, num2; cout << "输入运算符:+、-、*、/ : "; ...

被一个OIER遗弃的一堆烂代码 3765

QQueue的用法

1、首先必须加上头文件: #include <QQueue> 然后就是基本用法: 在头文件中声明: QQueue<QString> q; q.isEmpty(); //返回队列是否为空 q.size();//返回队列元素个数 q.clear();...

Littlehero_121的博客 1万+

C#实例 —— 设计一个科学计算器 (WPF界面实现)

C#实例 —— 设计一个科学计算器 (WPF界面实现)

weixin_45525142的博客 2609

Qt QQueue使用详解与实践

QQueue是Qt框架中基于模板的队列容器类,遵循**先进先出(FIFO)**原则。它提供高效的元素入队和出队操作,适用于需要顺序处理数据的场景。

BMN李的博客 1079

antlr入门实例——计算器

一个简单的antlr应用——简单计算器的实现,帮助大家快速上手antlr。

一只小汤米 1万+

js实例1——JavaScript实现计算器

用html、css和js实现简单的计算器功能,根据菜鸟里的案例自己敲了一遍,菜鸟链接在这里:https://c.runoob.com/codedemo/3124 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>js计算器<...

Tangtaoyao123的博客 1307

查看QQueue队列中是否有数据

查看QQueue队列中是否有数据

xie__jin__cheng的博客 629

Qt入门教程:QQueue 队列

接下来,使用head()函数返回了队列头部的元素,但并没有将其从队列中移除。QQueue类还提供了其他一些有用的函数,如clear()函数用于清空队列中的所有元素,operator=()函数用于复制另一个队列的元素到当前队列,以及operator()函数用于方便地向队列中添加和移除元素。在上面的代码中,我们创建了一个QQueue对象,并使用enqueue()函数向队列中添加了三个字符串元素:“Apple”、“Banana"和"Orange”。

UhxzCombined的博客 732

python 消息队列 分发_Python38 RabbitMQ 消息队列

title: Python38 RabbitMQtags: Python学习grammar_cjkRuby: trueRabbitMQ 消息队列介绍RabbitMQ是一种消息队列,与线程queue和进程QUEUE作用是一样的。RabbitMQ是一个中间程序,可以实现不同进程之间的通信(比如python和Java之间,QQ和Word之间等);普通情况下A进程与B进程之间通信,两者之间需要建立很多连接...

weixin_39616565的博客 324

单片机c51编程实例

第一章 AT89S51单片机实验及实践系统板简介┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅1 第二章 Keil C软件使用┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅14 第三章 AT89S51单片机下载器软件使用┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅25 第四章 实验及实践课题┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅28 1. 闪烁灯┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅28 2. 模拟开关灯┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅31 3. 多路开关状态指示┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅33 4. 广告灯的左移右移┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅37 5. 广告灯(利用取表方式)┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅40 6. 报警产生器┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅43 7. I/O并行口直接驱动LED显示┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅46 8. 按键识别方法之一┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅49 9. 一键多功能按键识别技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅53 10. 00-99计数器┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅57 11. 00-59秒计时器(利用软件延时)┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅60 12. 可预置可逆4位计数器┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅63 13. 动态数码显示技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅67 14. 4×4矩阵式键盘识别技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅70 15. 定时计数器T0作定时应用技术(一)┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅79 16. 定时计数器T0作定时应用技术(二)┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅84 17. 99秒马表设计┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅89 18. “嘀、嘀、……”报警声┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅95 19. “叮咚”门铃┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅99 20. 数字钟(★)┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅105 21. 拉幕式数码显示技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅114 22. 电子琴┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅121 23. 模拟计算器数字输入及显示┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅134 24. 8×8LED点阵显示技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅141 25. 点阵LED“0-9”数字显示技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅146 26. 点阵式LED简单图形显示技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅153 27. ADC0809 A/D转换器基本应用技术┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅157 28. 数字电压表┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅163 29. 两点间温度控制┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅167 30. 四位数数字温度计┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅172 31. 6位数显频率计数器┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅177 32. 电子密码锁设计┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅180 33. 4×4键盘及8位数码管显示构成的电子密码锁┅┅┅┅┅┅┅┅┅┅┅186 34. 带有存储器功能的数字温度计-DS1624技术应用┅┅┅┅┅┅┅┅┅┅199 35. DS18B20数字温度计使用┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅211

Qt中使用QQueue模拟消息队列

使用QQueue, QThread,QMutex,QWaitCondition模拟消息队列的任务处理,实现任务的同步处理

数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器

文章目录前言一、栈1.1 栈的介绍1.2 栈的应用实例【重点】1.3 栈的应用场景二、数据模拟栈三、单链表模拟栈四、栈实现综合计算器 前言 一、栈 1.1 栈的介绍 栈的英文为(stack) 栈是一个 先入后出 (FILO-First In Last Out)的有序列表。 栈(stack)是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,...

冯安晨 533

如何制作微信小程序的在线购物商城应用

首先,你需要规划好商城的整体框架,确定好你的目标用户群体,思考他们的需求是什么。接下来,使用微信开发者工具创建一个新的小程序项目,输入你的AppID,选择好保存路径,点击“创建”,一个新的商城雏形就诞生了。你可以把这里当作自己的家,无论是工作之余的小憩,还是寻找灵感的驿站,我都希望你能在这里找到属于你的那份快乐和满足。数据是现代商业的灵魂,通过数据分析,你可以更准确地把握用户的行为模式,从而做出更明智的决策。

master_chenchen的博客 2427

高效学 C++|编程实例之计算器

本节将实现一个能进行实数间加、减、乘、除运算的简易计算器。

不断学习,不断进步,提高自己 2874

RIGOL DS1102E示波器新手必看:从开机到捕获第一个波形的5分钟指南

本文为RIGOL DS1102E示波器新手提供了一份快速上手指南。内容涵盖从开机、探头校准到捕获第一个波形的完整流程,重点解析了触发设置、自动测量等核心操作,并指出了探头衰减比设置等常见误区,帮助用户快速掌握这款经典数字示波器的基本使用方法。

dream的博客 740

【01】VisionMaster入门到精通——VisionMaster V4.0.0 试用版安装教程(安装试用补丁与试用授权)

本文详细介绍了海康VisionMaster 4.0.0试用版的安装步骤:首先从官网下载基础安装包、软加密试用版和示例程序(可选);安装时需按顺序完成主程序安装(选择软加密)、试用补丁安装和30天试用授权安装;最后提供了两种启动方式。文章还列出了试用版的7项功能限制,包括最多支持2个流程、2个全局相机等,并特别提醒试用版不维护、不提供补丁,建议用户转为正式版本。安装过程中若出现蓝屏需重启覆盖安装,授权失败时可参考指定解决方案。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 8920

Java---计算器(标准计算器,科学计算器)的实现

Java-计算器(标准计算器和科学计算器)的实现 可以先建两个类,一个是Biaozhun 用来实现标准计算器,另一个是Kexue 用来实现科学计算器 通过功能菜单实现科学计算器和标准计算器的转换 具体代码中,在Biaozhun类 和 Kexue类 各自定义相对应的事件来实现转换 menuItem_1.addActionListener(new ActionListener() menuItem....

via CHEng的博客 2万+

小程序结合Three.js与gsap:打造流畅3D动画的完整指南

本文详细介绍了如何在小程序中整合Three.js与GSAP动画库,打造流畅的3D动画效果。通过从环境搭建、基础场景创建到模型加载与复杂动画编排的完整指南,帮助开发者克服小程序性能限制,实现如商品360度展示等沉浸式交互体验,提升产品视觉吸引力。

python9snake的博客 548

实例2--C# 简易计算器

在开发简易计算器应用时,C#的事件处理、数据转换和异常处理是关键技术点。通过使用Windows Forms,我们能够快速设计出用户友好的图形界面,同时利用C#语言的强大功能来处理运算逻辑和用户输入。 项目开发过程中,界面设计和事件逻辑处理是两大重要任务,异常处理确保了程序的稳定性,用户输入的验证保证了系统的可靠性。完成该项目后,可以加深对C#编程、GUI设计以及运算逻辑实现的理解和应用。

weixin_40978412的博客 2199

OsgEarth —— 笔记6 - 开发阶段加入漫游飞行(附源码)

效果      视频地址   源码 源码下载请私信   代码      代码相关内容:           OSG —— 笔记1 - 指令调用模型           OsgEarth —— 笔记1 - 创建地球的earth文件           OsgEarth —— 笔记2 - Qt窗口加载earth地球(附源码)           OsgEarth —— 笔记3 - 为地

1896

基于MATLAB的最大重叠离散小波变换(MODWT)算法详解

最大重叠离散小波变换(Maximal Overlap Discrete Wavelet Transform, MODWT)是DWT的重要改进形式,由Percival和Walden等人在20世纪90年代系统提出并完善。MODWT通过消除下采样操作,采用样本平移不变的分解方式,解决了DWT的多个固有缺陷。MODWT的核心创新在于取消下采样环节。与DWT每级分解后对滤波输出进行二分下采样不同,MODWT在每一级都使用相同的滤波器,但通过插入零值的方式调整滤波器系数,保持每级系数数量与原始信号相同。

qq_42212808的博客 115

简单计算器——JavaScript小实例

简单计算器——JavaScript小实例

qq_62858590的博客 3664

GEE:基于MODIS数据计算NDVI时间序列,并使用Savatsky-Golay(SG)滤波器对其进行平滑处理

优快云@_养乐多_本文将介绍如何在 Google Earth Engine (GEE) 平台中,使用 MODIS 数据计算 NDVI 时间序列,并对该数据集应用 Savitzky-Golay 滤波器,得到了一个新的平滑后的数据集。Savitzky-Golay 滤波器可以有效地去除信号中的噪声,并平滑信号的变化。该方法可以扩展到基于 MODIS 数据计算的任何指数或者波段。

养乐多的博客 1426

Android计算器开发实例

Android计算器开发实例  最近迷上了安卓开发, 自己做了个web浏览器,很好用,现在想做一个简单的计算器程序员,熟悉安卓的编程基础。下面我们来一起看一下吧。let`s go!     main.xml代码   http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"

山鹰的专栏 1764

C# 与欧姆龙 PLC 实战:通过 Ethernet/IP 协议进行设备控制与监控

本文介绍了如何通过C#和Ethernet/IP协议实现与欧姆龙PLC的通信。Ethernet/IP是基于以太网的工业协议,适用于工业设备间的实时数据交换。文章详细讲解了使用EthernetIPSharp库建立连接、读写数据的步骤,并提供了示例代码。此外,还探讨了实时监控、报警系统等高级功能,为工业自动化控制系统开发提供了实用指导。该方法简化了PLC通信开发,提高了系统可靠性和智能化程度。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 811

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

div与表格应用实例——计算器布局

div与表格应用实例——计算器布局

零小唬的博客 1927

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

上一篇: (六)Qt内存管理
下一篇: (八)对话框
早起的虫儿灬
博客等级 码龄10年 54粉丝 114原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值