8、计算机

8、QLineEdit用于接受用户输入,QLineEdit能够获取用户输入的字符串,是功能性组件,需要父组件作为容器,能够在父组件中进行定位。

Qwidget w; //生成QWidget对象,顶级组件

QLineEdit le(&w);     //生成QLineEdit对象,其父组件为QWidget

le.setAlignment(QT::AlignRight);     //设置显示的字符串向右边对齐  

le.move(10,10);      //移动到坐标(10,10)

le.resize(240,30);     //设置大小width=240,height=30

界面设计:定义组件间的间隔:Space=10px

定义按钮组件的大小:Width=40px,Height=40px

定义文本框组件的大小:Width=5*40px+4*10px,Height=30px

#include <QtGui/QApplication>
#include "Qwidget"
#include <QLineEdit>
#include <QPushButton>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget* w=new QWidget(NULL,Qt::WindowCloseButtonHint);//第一个问题
    QLineEdit* le=new QLineEdit(w);
    QPushButton* button[20]={0};
    const char*  btnText[20]=
    {
        "7","8","9","+","(",
        "4","5","6","-",")",
        "1","2","3","*","<-",
        "0",".","=","/","C",
    };
    int ret=0;
    le->move(10,10);
    le->resize(240,30);
    le->setReadOnly(true);//不能从键盘输入
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<5;j++)
        {
            button[i*5+j]=new QPushButton(w);
            button[i*5+j]->resize(40,40);
            button[i*5+j]->move(10+(10+40)*j,50+(10+40)*i);
            button[i*5+j]->setText(btnText[i*5+j]);
        }
    }
    w->show();
    w->setFixedSize(w->width(),w->height());//固定长宽
    ret=a.exec();
    delete w;
    return ret;
}

//存在的问题,最大化有问题,拖动有问题,文本框只是显示结果,不能从键盘输入

小结:GUI应用程序开发前应该必须先进行界面设计,

GUI应用程序界面需要考虑各个细节:界面决定最终用户的体验,界面细节是GUI应用程序品质的重要体现。

Qt库有能力实现各种GUI应用程序需求

Qt帮助文档的使用对于开发是非常重要的。

9、计算机界面重构

重构:以改善代码质量为目地的代码重写:使其软件的设计和构架更加合理,提高软件的扩展性和维护性。

代码实现与代码重构不同:

代码实现:按照设计编程实现,重心在于功能实现。

代码重构:以提高代码质量为目地的软件架构优化。

区别:代码实现时不考虑架构的好坏,只考虑功能的实现。

代码重构时不能影响已实现的功能,只考虑架构的改善。

软件开发过程:从工程的角度对软件开发中的活动进行定义和管理。

需求分析-》功能分析-功能实现-功能测试(重构)-系统测试-最终发布

什么样的代码需要重构:当发现项目中重复的代码越来越多时,当发现项目中代码功能越来越不清晰时,当发现项目中代码离设计越来越来远时。

重构是维持代码质量在可接受范围内的重要方式。

#include <QtGui/QApplication>
#include "QCalculatorUI.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QCalculatorUI* cal=QCalculatorUI::NewInstance();
    int ret=-1;
    if(cal !=NULL)
    {
    cal->show();
    ret=a.exec();
    delete cal;
    }
    return ret;

}

#ifndef _QCALCULATORUI_H_
#define _QCALCULATORUI_H_
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
class QCalculatorUI : public QWidget
{
private:
    QLineEdit* m_edit;
    QPushButton* m_buttons[20];
    QCalculatorUI();
    bool construct();
public:
    static QCalculatorUI* NewInstance();
    void show();
    ~QCalculatorUI();
};

#endif 

#include "QCalculatorUI.h"
QCalculatorUI::QCalculatorUI():QWidget(NULL,Qt::WindowCloseButtonHint)//顶层窗口 没有父类
{
}
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);//不能从键盘输入
    }
    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]);
            }
            else
            {
                ret=false;
            }
        }
    }
    return ret;
}
QCalculatorUI* QCalculatorUI::NewInstance()
{
    QCalculatorUI* ret=new QCalculatorUI();
    if(!(ret&&ret->construct()))//((ret==NULL)||!ret->connect())
    {
        delete ret;
        ret=NULL;
    }
    return ret;
}
void QCalculatorUI::show()
{
    QWidget::show();


    setFixedSize(width(),height());//固定长宽
}
QCalculatorUI::~QCalculatorUI()
{
}

//存在的问题,最大化有问题,拖动有问题,文本框只是显示结果,不能从键盘输入

重构是软件开发中的重要概念,重构是以提高代码质量为目地的软件开发活动,重构不能影响已有的软件功能,当软件功能的实现进行到了一定阶段时就需要考虑重构,重构可简单的理解为对软件系统进行重新构架。

10、消息处理

Qt封装了具体操作系统的消息机制,Qt遵循经典的GUI消息驱动事件模型。

用户事件-》操作系统-》应用系统消息(应用程序,消息处理函数)

Qt中定义了与系统消息相关的概念:

信号(signal):由操作系统产生的消息。

槽(slot):程序中的消息处理函数。

连接(connect):将系统消息绑定到消息处理函数。

QObject_1(发送信号)->connect<-- QObject_2(消息处理函数)

信号到槽的连接必须发生在两个qt类对象之间。

Qt的核心-QObject::connect函数

bool connect(const QObject* sender, //发送对象

const char* signal,   //消息名

const QObject* receiver, //接收对象

const char* method,   //接受对象的成员函数

Qt::ConnectionType type=Qt::AutoConnection);

Node:在qt中,消息用字符串进行描述,connect函数在消息名和处理函数之间建立映射

qt中的“新”关键字:

SIGNAL:用于指定消息名。

SLOT:用于指定消息处理函数名。

Q_OBJECT:所有自定义槽的类必须在类声明的开始处加上Q_OBJECT。

slots:用于在类中声明消息处理函数。

#include <QtGui/QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton b;
    b.setText("Click me to quit!");
    b.show();
    QObject::connect(&b, SIGNAL(clicked()), &a, SLOT(quit()));//按钮对象点击发送消息映射的a的quit函数
    return a.exec();

}

自定义槽:只有QObject的子类才能自定义槽

定义槽的类必须在声明的最开始处使用Q_OBJECT,类中声明槽时需要使用slots关键字,槽与所处理的信号在函数签名上必须一致,SIGNAL和SLOT所指定的名称中可以包含参数类型,不能包含具体的参数名。

为计算机添加信号处理函数:

connect( m_buttons[i*5+j],SIGNAL(clicked()),this,SLOT(onButtonClicked()));

void QCalculatorUI::onButtonClicked()//消息处理函数
{
    QPushButton* btn=(QPushButton*)sender();
    qDebug()<<" void onButtonClicked();";
    qDebug()<<btn->text();
}

小贴士:问题Object:: connect: No such slot ...

1、检查类是否继承与QObject

2、检查类声明的开始处是否添加Q_OBJECT.

3、检查是否使用slots关键字进行槽声明。

4.检查槽的名称是否拼音错误

5、重新执行qmake.

小结:信号与槽是qt中的核心机制,不同的qt对象可以通过信号和槽进行通信,只有QObject的子类才能自定义信号和槽,使用信号和槽的类必须在声明的最开始处使用Q_OBJECT,信号与处理函数在函数签名上必须一致。

11、字符串类

Qt vs STL

STL的具体实现依赖于编译器生成厂商,

STL的标准只是其接口是标准的:相同的全局函数,相同的算法类和数据结构类,相同的类成员函数。

不同厂商的编译器所带的STL存在差异:依赖于STL开发的c++程序在不同平台上的行为可能出现差异。

项目是否需要使用现有库的支持?STL?QT?MFC?私有库?

项目是否需要在不同平台间移植? Linux?Windows? Android?

项目是否需要图形用户界面?GUI应用程序?命令行应用程序?后台服务程序?

Qt中的字符串类:

采用Unicode编码(支持中文,韩文),使用隐式共享技术来节省内存和不必要的数据拷贝,扩平台使用,不必考虑字符串的平台兼容性。

QString直接支持字符串和数字的相互转换,支持字符串的大小比较,支持不同字符编码间的相互转换,支持std::string和std::wstring的相互转换。支持正则表达式的应用。


#include <QDebug>
void Sample_1()
{
    QString s = "add";
    s.append(" ");    // "add "
    s.append("Qt");   // "add Qt"
    s.prepend(" ");   // " add Qt"
    s.prepend("C++"); // "C++ add Qt"
    qDebug() << s;
    s.replace("add", "&"); // "C++ & Qt"
    qDebug() << s;
}

void Sample_2()
{
    QString s = "";
    int index = 0;
    s.sprintf("%d. I'm %s, thank you!", 1, "Delphi Tang"); // "1. I'm Delphi Tang, thank you!"
    qDebug() << s;
    index = s.indexOf(",");
    s = s.mid(0, index);   // "1. I'm Delphi Tang" 取子串
    qDebug() << s;
    index = s.indexOf(".");
    s = s.mid(index + 1, s.length()); // " I'm Delphi Tang"
    s = s.trimmed();                  // "I'm Delphi Tang" 去掉前后空格
    qDebug() << s;
    index = s.indexOf(" ");
    s = s.mid(index + 1, s.length()); // "Delphi Tang"
    qDebug() << s;
}

void Sample_3(QString* a, int len)
{
    for(int i=0; i<len; i++)  //选择排序字符串
    {
        for(int j=i+1; j<len; j++)
        {
            if( a[j] < a[i] )
            {
                QString tmp = a[i];
                a[i] = a[j];
                a[j] = tmp;
            }
        }
    }
}

int main()
{
    qDebug() << "Sample_1:"; //输出字符串
    Sample_1();
    qDebug() << endl;
    qDebug() << "Sample_2:";
    Sample_2();
    qDebug() << endl;
    qDebug() << "Sample_3:";
    QString company[5] =
    {
        QString("Oracle"),
        QString("Borland"),
        QString("Microsoft"),
        QString("IBM"),
        QString("D.T.Software")
    };

    Sample_3(company, 5);
    for(int i=0; i<5; i++)
    {
        qDebug() << company[i];
    }
    return 0;

}

QString在Qt库中几乎无所不在的,所有的qt图形用户组件都依赖于QString。

应用开发中大多数的情况都在进行字符串处理,Qt比STL更适合于扩平台开发的场景,Qt中的QString比STL中string更强大易用,Qt图形用户组件都依赖于QSstring,项目开发时需要综合各种选择需要使用的库。

m_edit->setAlignment(Qt::AlignRight);//输入右对齐

void QCalculatorUI::onButtonClicked()//消息处理函数
{
    QPushButton* btn=(QPushButton*)sender();
    QString clickTest=btn->text();
    if(clickTest=="<-")
    {
        QString text=m_edit->text();
        if(text.length()>0)
        {
            text.remove(text.length()-1,1);
            m_edit->setText(text);
        }
    }
    else if(clickTest=="C")
    {
        m_edit->setText("");
    }
    else if(clickTest=="=")
    {
    }
    else
    {
        m_edit->setText(m_edit->text()+clickTest);
    }

}

12、实现

后缀表达式:

人类习惯的数学表达式叫做中缀表达式,另外,还有一种将运算符放在数字后面的后缀表达式。

5+3->53+

后缀表达式符合计算机的运算方式:消除了中缀表达式中的括号,同时保留中缀表达式中的运算优先级。

解决方案:

1、将中缀表达式进行数字和运算符的分离。

2、将中缀表达式转换为后缀表达式。

3、通过后缀表达式计算最终结果。

所要计算的中缀表达式中包含:

数字和小数点(0-9或.)

符号位(+ -)

运算符(+,-,*,/)

括号()

思想:以符号作为标志对表达式中的字逐个访问

定义累计变量num(字符串)

当前字符exp[i]为数字或小数点时:累计:num+=exp[i]

当前字符exp[i]为符号时:分离num

num为运算数,分离并保存,

若exp[i]为正负号:累计符号位+和-:num+=exp[i]。若exp[i]为运算符:分离并保存。

难点:如何区分正负号与加号和减号?

正负号:

+和-在表达式的第一个位置

括号后的+和-(左括号)

运算符后的+和-

#ifndef _CALCULATORCORE_H_
#define _CALCULATORCORE_H_
#include <QString>
#include <QStack>
#include <QQueue>
class QCalculatorDec
{
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);
    QQueue<QString> split(const QString& exp);//分离算法
public:
    QCalculatorDec();
    ~QCalculatorDec();
    bool expression(const QString& exp);
    QString expression();
    QString result();
};

#endif



#include "QCalculatorDec.h"
#include <QDebug>
QCalculatorDec::QCalculatorDec()
{
    m_exp = "";
    m_result = "";
    QQueue<QString> r = split("+9.11 + ( -3 - 1 ) * -5 ");
    for(int i=0; i<r.length(); i++)
    {
        qDebug() << r[i];
    }
}
QCalculatorDec::~QCalculatorDec()
{
}
bool QCalculatorDec::isDigitOrDot(QChar c)//Qchar unicode字符
{
    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);//成功ret为true 否则false
    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(const QString& exp)
{
    bool ret = false;
    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;
}

小结:QString中的每个字符为QChar,QT中提供了开发中不可或缺的数据结构类,四则运算表达式的计算分三个步骤:

数字和符号分离,中缀表达式转后缀表达式,根据后缀表达式计算结果。

13、中缀表达式转后缀表达式的过程类似编译过程:

四则运算表达式中的括号必须匹配,根据运算符优先级进行转换,转换后的表达式中没有括号,转换后的表达式中没有括号,转换后可以顺序的计算出最终结果。

转换过程:当前元素e为数字:输出

当前元素e为运算符:1、与栈顶运算符进行优先级比较。2、小于等于:将栈顶元素输出,转1。3、大于:将当前元素e入栈。

当前元素e为左括号:入栈

当前元素e为右括号:1、弹出栈顶元素并输出,直至栈顶元素为左括号。2、将栈顶的左括号从栈中弹出。

bool QCalculatorDec::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;
}
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;
}

小结:后缀表达式是程序计算复杂表达式的基础,中缀到后缀的转换时基于栈数据结构的,转换过程能够发现表达式中的语法错误。

14、遍历后缀表达式中的数字和运算符

当前元素为数字:进栈

当前元素为运算符:

1、从栈中弹出右操作数

2、从栈中弹出做操作数

3、根据符号进行运算

4、将运算结果压入栈中

遍历结束:栈中唯一的数字为运算结果。

注意:与数学计算相关的算法都需要考虑除0的情况,若是浮点运算,避免代码中直接与0做相等比较

QString QCalculatorDec::calculate(QString l,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.00001;
            if((-p<rp)&&(rp<p))
            {
                ret="Error";
            }
            ret.sprintf("%f",lp/rp);
        }
    }
    else
    {
        ret="Error";
    }
    return ret;
}


QString QCalculatorDec::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;

}

bool QCalculatorDec::expression(const QString& 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;

}

测试:

    QCalculatorDec c;
    c.expression("(5-8)*(5-6)");
    qDebug()<<c.result();

    return 0;

小结:计算方法由3个不同的子算法构成,Qt项目在整体上采用面向对象分析与设计,局部的算法设计依旧采用面向过程的方法完成,qt开发是各种开发技术的综合运用。

15、用户界面与业务逻辑的分离

基本程序架构一般包含:

用户界面模块(UI):接收用户输入及呈现数据。

业务逻辑模块(business logic):根据用户需求处理数据。

基本设计原则:

功能模块之间需要进行解耦

核心思想:强内聚,弱耦合:

每个模块应该只实现单一的功能,模块内部的子模块只为整体的单一功能而存在,模块之间通过约定好的接口进行交互。

接口:

广义:一种契约(协议,语法,格式)

狭义:面向过程:接口是一组预定义的函数原型。

面向对象:接口是纯虚类(java直接支持接口)

用户界面与业务逻辑的交互:

业务接口 <--用户界面(使用接口)  <--业务逻辑(实现接口)

模块之间仅通过接口进行关联:必然存在模块会使用接口,必然存在模块实现对应的接口。

模块间的关系是单项依赖的:避免模块间存在循环依赖的情况,循环依赖是糟糕设计标准之一。

计算机整体架构:Icalculator<---QCalculatorUI,QCalculatorDec-->QCalculator

#ifndef _ICALCULATOCH_H_//接口
#define _ICALCULATOCH_H_
#include <QString>
class ICalculator
{
public:
    virtual bool expression(const QString& exp)=0;
    virtual QString result() = 0;
};

#endif

#ifndef _QCALCULATOR_H_
#define _QCALCULATOR_H_
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"
class QCalculator
{
protected:
    QCalculatorUI* m_ui;//因为ui类是二阶构造构造的,如果成员变量是二阶构造构造的,使用的类也用二阶构造
    QCalculatorDec m_cal;
    QCalculator();
    bool construct();
public:
    static QCalculator* NewInstance();
    void show();
    ~QCalculator();
};

#endif 

#include "QCalculator.h"
QCalculator::QCalculator()
{
}
bool QCalculator::construct()
{
    m_ui=QCalculatorUI::NewInstance();
    if(m_ui !=NULL)
    {
        m_ui->setCalculator(&m_cal);//将ui跟核心算法关联
    }
    return (m_ui!=NULL);
}
QCalculator* QCalculator::NewInstance()
{
    QCalculator* ret=new QCalculator();
    if(!(ret&&ret->construct()))//if((ret==NULL)||!ret->construct())
    {
        delete ret;
        ret=NULL;
    }
    return ret;
}
void QCalculator::show()
{
    m_ui->show();
}
QCalculator::~QCalculator()
{
    delete m_ui;

}

#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;

}

void QCalculatorUI::onButtonClicked()//消息处理函数
{
    QPushButton* btn=dynamic_cast<QPushButton*>(sender());
    if(btn !=NULL)
    {
    QString clickTest=btn->text();
    if(clickTest=="<-")
    {
        QString text=m_edit->text();
        if(text.length()>0)
        {
            text.remove(text.length()-1,1);
            m_edit->setText(text);
        }
    }
    else if(clickTest=="C")
    {
        m_edit->setText("");
    }
    else if(clickTest=="=")
    {
        if(m_cal !=NULL)
        {
            m_cal->expression(m_edit->text());
            m_edit->setText(m_cal->result());
        }
    }
    else
    {
        m_edit->setText(m_edit->text()+clickTest);
    }
    }

小结:模块之间的交互需要通过接口完成,接口是开发中模块之间的一种契约,模块之间不能出现循环依赖,基本设计原则,强内聚,弱耦合。

猜你喜欢

转载自blog.csdn.net/ws857707645/article/details/80503327
今日推荐