欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

從0開始自制計(jì)算器!-創(chuàng)新互聯(lián)

先看看效果吧:

成都創(chuàng)新互聯(lián)公司從2013年開始,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元屏南做網(wǎng)站,已為上家服務(wù),為屏南各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18980820575

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

很炫酷吧?

想不想要?

想要吧.

當(dāng)然作者知道你們肯定想.

不然也不會(huì)點(diǎn)進(jìn)來(lái)對(duì)不對(duì).

好.進(jìn)入正題.

1.概述

這個(gè)是仿照win10自帶的計(jì)算器制作的簡(jiǎn)化版本.是用Qt做的,直接把整個(gè)表達(dá)式輸入然后得出計(jì)算結(jié)果.
主要分為三部分.界面部分,事件處理部分與表達(dá)式處理部分.

  • 界面部分就是看到的計(jì)算器,包括標(biāo)題欄,中間的輸出框,還有各個(gè)按鍵.
  • 事件處理就是處理對(duì)應(yīng)的鼠標(biāo)與鍵盤事件.
  • 表達(dá)式處理部分就是處理整個(gè)輸入的字符串,返回計(jì)算的結(jié)果,當(dāng)然這個(gè)還支持錯(cuò)誤判斷功能.

2.新建工程

選擇Widgets Application.
從0開始自制計(jì)算器!
起名字.
從0開始自制計(jì)算器!
一般只需MinGW.
從0開始自制計(jì)算器!
這里默認(rèn)即可,名字可以隨便改
從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

2.界面

(1) 按鍵

按鍵的話,基本上按著改就可以了.改布局,改顏色,改字體,主要就是這三個(gè).
首先先打開.ui文件:
從0開始自制計(jì)算器!

a.添加一個(gè)Grid Layout,調(diào)整好大小.

從0開始自制計(jì)算器!

b.拖入Push Button作為按鍵,sizePolicy屬性那里水平和垂直屬性都選擇Expanding.

從0開始自制計(jì)算器!

c.調(diào)整好顏色,設(shè)置styleSheet與字體

從0開始自制計(jì)算器!
這里給出作者的參考style:

border:1px groove rgb(220,220,220);
background-color:rgb(243,243,243);

字體:
從0開始自制計(jì)算器!
這里按個(gè)人喜好調(diào)整即可.

d.復(fù)制制作好的button,布好局

從0開始自制計(jì)算器!

e.改內(nèi)容

這里不僅把里面的字符改變,還要把相應(yīng)的對(duì)象名也改變.
從0開始自制計(jì)算器!
從0開始自制計(jì)算器!

再細(xì)調(diào)每一個(gè)按鍵,包括大小,字體與顏色,使總體效果更好.
從0開始自制計(jì)算器!
數(shù)字要注意有"加粗"效果,符號(hào)的話盡量"精細(xì)"一點(diǎn).

f.整體修改大小,同時(shí)加上間隔

從0開始自制計(jì)算器!

調(diào)整好間隔.注意細(xì)節(jié).
下面是win10自帶的計(jì)算器:
從0開始自制計(jì)算器!
看到間隔了沒?
作者要的就是這種效果.
可以先運(yùn)行看看.
從0開始自制計(jì)算器!
兩邊的間隔的話一會(huì)配合widget的大小調(diào)整即可.

(2) 輸出框

輸出框很簡(jiǎn)單,就是一個(gè)QLineEdit.

a.添加QLineEdit

從0開始自制計(jì)算器!

b.調(diào)整好大小,設(shè)置好背景顏色

從0開始自制計(jì)算器!
作者的qss:

border:0px groove rgb(243,243,243);
background-color:rgb(245,245,245);

c.設(shè)置字體,只讀,對(duì)齊

從0開始自制計(jì)算器!
從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

(3) 標(biāo)題欄

標(biāo)題欄其實(shí)也很簡(jiǎn)單,一個(gè)QBoxLayout

a.新建Horizontal Layout

從0開始自制計(jì)算器!

b.添加細(xì)節(jié)

從0開始自制計(jì)算器!
QLabel輸入標(biāo)題,兩個(gè)QPushButton表示最小化與關(guān)閉,同時(shí)加入兩個(gè)Spacer,讓標(biāo)題與左邊空出一些距離.
其實(shí)就是模仿win10的標(biāo)題欄的效果
從0開始自制計(jì)算器!
這里就不做大化了.因?yàn)樯婕暗桨粹o的重新排布問題,這個(gè)可以自己選擇實(shí)現(xiàn).

(4)整體處理

a.標(biāo)題欄

把上一步做的標(biāo)題欄移到合適的位置,同時(shí)刪除自帶的QMenuBar,QToolBar,QStatusBar.
從0開始自制計(jì)算器!

b.調(diào)整整體大小,同時(shí)添加透明度

從0開始自制計(jì)算器!
調(diào)整好后大概就那樣,透明度這里選擇了0.9.

真是完美啊!

3.事件處理

(1)光標(biāo)事件

A.標(biāo)題欄

a.拖動(dòng)效果

首先把本來(lái)那個(gè)標(biāo)題欄去掉.
從0開始自制計(jì)算器!

setWindowFlags(windowFlags() | Qt::FramelessWindowHint);

再在protected中加入鼠標(biāo)監(jiān)聽函數(shù):
從0開始自制計(jì)算器!

void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);

私有成員中加入兩個(gè)QPoint.分別表示當(dāng)前窗口坐標(biāo)與光標(biāo)的坐標(biāo).
從0開始自制計(jì)算器!

QPoint mousePoint;
QPoint windowPoint;

從0開始自制計(jì)算器!
第一個(gè)函數(shù)是鼠標(biāo)按下時(shí)觸發(fā)的,根據(jù)event->button()判斷是否是左鍵,是的話獲取mouse坐標(biāo),在設(shè)置window坐標(biāo).

當(dāng)觸發(fā)第二個(gè)函數(shù)時(shí),即先判斷是否按住左鍵不放,使用MainWindow的move方法移動(dòng)窗口.

event->globalPos()獲取坐標(biāo)后減去原來(lái)光標(biāo)的坐標(biāo)得到window坐標(biāo)的變化量,再用原坐標(biāo)加上這個(gè)變化量.

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        mousePoint = event->globalPos();
       windowPoint = frameGeometry().topLeft();
    }
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton)
    {
        move(windowPoint + event->globalPos() - mousePoint);
    }
}
b.最小化與關(guān)閉

這里以最小化為例,關(guān)閉也一樣的,改一下函數(shù)調(diào)用即可.
在最小化按鈕中右鍵選擇Go to slot:
從0開始自制計(jì)算器!
選擇clicked()
從0開始自制計(jì)算器!
添加一個(gè)最小化函數(shù):
從0開始自制計(jì)算器!
下面是關(guān)閉的函數(shù):
從0開始自制計(jì)算器!

B.按鍵

按鍵的鼠標(biāo)事件包括兩個(gè):

  • 光標(biāo)移入與移出事件,為按鍵添加陰影,加深顏色等
  • 單擊事件,在輸出框中增減對(duì)應(yīng)的字符
a.移入與移出事件

這里的實(shí)現(xiàn)方式是通過事件過濾器實(shí)現(xiàn)的.增加一個(gè)eventFilter()函數(shù)
從0開始自制計(jì)算器!

 bool eventFilter(QObject *,QEvent *);

從0開始自制計(jì)算器!
首先通過event->type()判斷事件類型,如果是光標(biāo)懸停,再判斷對(duì)應(yīng)的各個(gè)對(duì)象增加陰影效果.
addNumButtonEffet():

void MainWindow::addNumButtonEffect(QPushButton *button,QGraphicsDropShadowEffect *shadow)
{
    shadow->setEnabled(true);
    button->setStyleSheet(
        "border:1px groove rgb(220,220,220);"
        "background-color:rgb(193,193,193);"
    );
}

這里QGraphicsDropShadowEffect *shadow事先初始化好了.
從0開始自制計(jì)算器!
從0開始自制計(jì)算器!
然后在添加事件過濾器:
從0開始自制計(jì)算器!
這里可以對(duì)比一下有沒有陰影的效果:

沒有陰影:
從0開始自制計(jì)算器!
加上陰影:
從0開始自制計(jì)算器!
呃....這里可能是截圖工具的問題,看不來(lái)多大的效果,但是直接在機(jī)器上看是有比較大的區(qū)別的,建議還是加上陰影.

b.單擊事件

單擊事件就是單擊了某個(gè)按鍵然后用戶可以在輸出框中看到對(duì)應(yīng)的反應(yīng).

依次選擇按鍵,右鍵Go to slot:
從0開始自制計(jì)算器!
選擇clicked()
從0開始自制計(jì)算器!
然后添加處理函數(shù),作者這里自己實(shí)現(xiàn)了一個(gè)添加文本與清除焦點(diǎn)的函數(shù),添加文本就是對(duì)應(yīng)按鍵被光標(biāo)單擊后添加到輸出框,至于為什么要清除焦點(diǎn)....

因?yàn)?..

因?yàn)榭崭?

因?yàn)樽髡叩?quot;良好"習(xí)慣,習(xí)慣在運(yùn)算符前后加上空格

單擊后會(huì)把焦點(diǎn)保留在這個(gè)按鈕上,鍵盤上敲空格默認(rèn)會(huì)幫你"按一次"這個(gè)按鈕,因此如果不清除焦點(diǎn)的話,在光標(biāo)單擊了某個(gè)按鈕,比如7,按空格就會(huì)在輸出框上輸出7,光標(biāo)單擊了8后,按空格就會(huì)在輸出框上輸出8.
從0開始自制計(jì)算器!
從0開始自制計(jì)算器!
這里添加文本時(shí)還要注意默認(rèn)的起提示作用的0.

void MainWindow::appendText(const QString &s)
{
    if(ui->box->text() == "0")
        ui->box->setText(s);
    else
        ui->box->setText(ui->box->text()+s);
}

void MainWindow::appendTextAndClearFocus(QPushButton *button, const QString &s)
{
    appendText(s);
    button->clearFocus();
}

(2)鍵盤事件

鍵盤事件就是主要處理各個(gè)按鍵按下時(shí)的陰影與輸出框添加輸出.
鍵盤事件通過以下兩個(gè)函數(shù)處理:
從0開始自制計(jì)算器!

void keyPressEvent(QKeyEvent *);
void keyReleaseEvent(QKeyEvent *);

第一個(gè)是按鍵按下時(shí)觸發(fā)的,第二個(gè)是松開按鍵觸發(fā)的.

A.添加陰影

在按鍵按下時(shí)添加上陰影與顏色加深效果.
從0開始自制計(jì)算器!
通過event->key()依次判斷各個(gè)鍵.
鍵位可以看這里

然后添加在keyRealeseEvent()中把對(duì)應(yīng)的陰影去掉:

void MainWindow::keyReleaseEvent(QKeyEvent *event)
{
    switch (event->key())
    {
        case Qt::Key_0:
        case Qt::Key_1:
        case Qt::Key_2:
        case Qt::Key_3:
        case Qt::Key_4:
        case Qt::Key_5:
        case Qt::Key_6:
        case Qt::Key_7:
        case Qt::Key_8:
        case Qt::Key_9:
        case Qt::Key_Plus:
        case Qt::Key_Minus:
        case Qt::Key_Asterisk:
        case Qt::Key_Slash:
        case Qt::Key_AsciiCircum:
        case Qt::Key_Percent:
        case Qt::Key_ParenLeft:
        case Qt::Key_ParenRight:
        case Qt::Key_BraceLeft:
        case Qt::Key_BraceRight:
        case Qt::Key_BracketLeft:
        case Qt::Key_BracketRight:
        case Qt::Key_Backspace:
        case Qt::Key_Space:
        case Qt::Key_Period:
        case Qt::Key_Escape:
        case Qt::Key_Equal:
        case Qt::Key_Return:
            removeNumButtonEffect(ui->num0,num0_shadow);
            removeNumButtonEffect(ui->num1,num1_shadow);
            removeNumButtonEffect(ui->num2,num2_shadow);
            removeNumButtonEffect(ui->num3,num3_shadow);
            removeNumButtonEffect(ui->num4,num4_shadow);
            removeNumButtonEffect(ui->num5,num5_shadow);
            removeNumButtonEffect(ui->num6,num6_shadow);
            removeNumButtonEffect(ui->num7,num7_shadow);
            removeNumButtonEffect(ui->num8,num8_shadow);
            removeNumButtonEffect(ui->num9,num9_shadow);
            removeSignButtonEffect(ui->plus,plus_shadow);
            removeSignButtonEffect(ui->minus,minus_shadow);
            removeSignButtonEffect(ui->mutiply,mutiply_shadow);
            removeSignButtonEffect(ui->divide,divide_shadow);
            removeSignButtonEffect(ui->pow,pow_shadow);
            removeSignButtonEffect(ui->percent,percent_shadow);
            removeSignButtonEffect(ui->parentheses,parentheses_shadow);
            removeSignButtonEffect(ui->parentheses,parentheses_shadow);
            removeSignButtonEffect(ui->brace,brace_shadow);
            removeSignButtonEffect(ui->brace,brace_shadow);
            removeSignButtonEffect(ui->bracket,bracket_shadow);
            removeSignButtonEffect(ui->bracket,bracket_shadow);
            removeSignButtonEffect(ui->backspace,backspace_shadow);
            removeSignButtonEffect(ui->blank,space_shadow);
            removeSignButtonEffect(ui->dot,dot_shadow);
            removeSignButtonEffect(ui->C,c_shadow);
            removeSignButtonEffect(ui->equal,equal_shadow);
            break;
    }
}

這里之所以沒有一個(gè)個(gè)按鍵去判斷是因?yàn)橛锌赡芡瑫r(shí)多個(gè)按鍵按下,然后同時(shí)松開后發(fā)現(xiàn)某個(gè)按鍵還存在陰影,因此統(tǒng)一當(dāng)其中一個(gè)按鍵釋放時(shí)去除所有按鍵的陰影.

B.添加輸出

在輸出框中添加輸出,調(diào)用一個(gè)函數(shù)即可:
從0開始自制計(jì)算器!

4.整體細(xì)節(jié)再處理

(1)淡入效果

看看效果:
從0開始自制計(jì)算器!
這里實(shí)際使用了Qt的動(dòng)畫,針對(duì)透明度改變的動(dòng)畫.

從0開始自制計(jì)算器!

void MainWindow::fadeIn(void)
{
    QPropertyAnimation * changeOpacity = new QPropertyAnimation(this,"windowOpacity");
    changeOpacity->setStartValue(0);
    changeOpacity->setEndValue(0.91);
    changeOpacity->setDuration(2500);
    changeOpacity->start();
}

第一行表示改變的是透明度,第二三行設(shè)置起始值與結(jié)束值,接下來(lái)設(shè)置動(dòng)畫時(shí)間(單位ms),然后開始動(dòng)畫.

(2)設(shè)置固定尺寸

這里可以不設(shè)置大尺寸,但一定要設(shè)置最小尺寸.
從0開始自制計(jì)算器!
設(shè)置這個(gè)實(shí)際上禁止了拖拽去改變大小.

(3)淡出效果

淡出效果與淡入效果類似.
不同的時(shí)需要添加計(jì)時(shí)處理,不能直接在exit(0)前調(diào)用fadeOut()函數(shù),因?yàn)閯?dòng)畫會(huì)在另一個(gè)線程啟動(dòng),所以需要在主線程休眠指定秒數(shù),等待淡出效果完成后,主線程再調(diào)用exit(0);
從0開始自制計(jì)算器!

void MainWindow::fadeOut(void)
{
    QPropertyAnimation * changeOpacity = new QPropertyAnimation(this,"windowOpacity");
    changeOpacity->setStartValue(0.9);
    changeOpacity->setEndValue(0);
    changeOpacity->setDuration(2500);
    changeOpacity->start();

    QTime start = QTime::currentTime().addMSecs(2500);
   while(QTime::currentTime() < start)
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

其中addMSecs()表示要延遲的秒數(shù),while循環(huán)體中表示處理本線程的事件,其中100表示處理事件最多100ms就返回本語(yǔ)句.
從0開始自制計(jì)算器!
這里就不放淡出效果的圖片了.

5.表達(dá)式處理

由于這是整個(gè)字符串作為表達(dá)式進(jìn)行輸入,需要先進(jìn)行判斷再計(jì)算.所以分為判斷與計(jì)算兩部分.
這里使用了一個(gè)新開的控制臺(tái)工程,后面會(huì)把這個(gè)整合起來(lái).

(1)判斷

使用了一個(gè)check類判斷,由于只有10個(gè)數(shù)字按鍵,加減乘除,小數(shù)點(diǎn),求余,求次冪,大中小括號(hào),空格,所以可以分成這幾類進(jìn)行判斷.

a.去除所有空格

void removeAllBlank(void)
{
    size_t i = 0;
   while((i = s.find(' ',i)) != string::npos)
        s.erase(i,1);
}

首先把所有空格去除,避免之后的判斷.

b.分類判斷

把表達(dá)式中的所有字符分成5類:

  • 數(shù)字
  • 小數(shù)點(diǎn)
  • 運(yùn)算符號(hào) + - * / ^ %
  • 左括號(hào)類 ( [ {
  • 右括號(hào)類 ) ] }

然后就是針對(duì)每個(gè)類型判斷它的下一個(gè)字符是否是允許的類型,不是的話返回false.
比如碰上了一個(gè) ( 或 [ 或 {
則它的下一個(gè)不能是運(yùn)算符號(hào)或者小數(shù)點(diǎn),當(dāng)然允許-與+,因?yàn)橛?br/>(-7) (+234)
這種情況.
然后把這個(gè)符號(hào)保存下來(lái)判斷后面是否是對(duì)應(yīng)的右括號(hào).

if(isLeftBrace(i))
{
    if(isSignOrDot(i+1))
    {
        if(s[i+1] != '-' && s[i+1] != '+')
            return false;
    }
    braces.push(s[i]);
}

整個(gè)判斷函數(shù)如下:

bool valid(void)
{
    if(isSignOrDot(0) || isRightBrace(0))
        return false;
    len = s.size();
    stack<char> braces;
    for(size_t i=0;i<len;++i)
    {
        if(isLeftBrace(i))
        {
            if(isSignOrDot(i+1))
            {
                if(s[i+1] != '-' && s[i+1] != '+')
                    return false;
            }
            if(isRightBrace(i+1))
                return false;
            braces.push(s[i]);
        }
        else if(isRightBrace(i))
        {
            if(isDot(i+1) || isDigit(i+1) || isLeftBrace(i+1))
                return false;
            if(isRightBrace(i+1))
            {
                stack<char> braces_copy(braces);
                if(braces_copy.empty())
                    return false;
                braces_copy.pop();
                if(braces_copy.empty())
                    return false;
            }
            if(braces.empty())
                return false;
            char brace = braces.top();
            if((brace == '(' && s[i] != ')') || (brace == '[' && s[i] != ']') || (brace == '{' && s[i] != '}'))
                return false;
            braces.pop();
        }
        else if(isSign(i))
        {
            if(isSign(i+1) || isDot(i+1) || isRightBrace(i+1))
                return false;
        }
        else if(isDot(i))
        {
            if(isSignOrDot(i+1) || isBrace(i+1))
                return false;
        }
        else if(isDigit(i))
        {
            if(isRightBrace(i+1))
            {
                if(braces.empty())
                    return false;
                char brace = braces.top();
                if((brace == '(' && s[i+1] != ')') || (brace == '[' && s[i+1] != ']') || (brace == '{' && s[i+1] != '}'))
                    return false;
            }
        }
    }
    return braces.empty();
}

特別要注意下的就是碰到右括號(hào)的情況,除了要判斷是否是單獨(dú)存在的右括號(hào),還有判斷是否與前一個(gè)左括號(hào)匹配.

c.加0

這是針對(duì)單目運(yùn)算符-的情況,比如(-7),然后把它轉(zhuǎn)化為(0-7):

string getResult(void)
{
    size_t len = s.size();
    for(size_t i = 0;i<len;++i)
    {
        if(s[i] == '(' && (s[i+1] == '-' || s[i+1] == '+'))
            s.insert(i+1,"0");
    }
    return s;
}

在左小括號(hào)后判斷是否是-或+,是的話對(duì)應(yīng)位置插入0.

(2)計(jì)算

a.calc輔助類

calc輔助類中使用了兩個(gè)棧,運(yùn)算符棧與操作數(shù)棧.

private:
    stack<char> operators;
    stack<double> operands;

其中有兩個(gè)重要的方法:

bool canCalculate(char sign);
void calculate(void);

第一個(gè)方法將下一個(gè)準(zhǔn)備進(jìn)入的符號(hào)作為參數(shù),判斷是否可以計(jì)算操作數(shù)棧的前兩個(gè)數(shù),如果可以的話,使用第二個(gè)函數(shù)進(jìn)行計(jì)算.
calculate()會(huì)將出棧兩個(gè)操作數(shù)與一個(gè)運(yùn)算符,得出結(jié)果后在將其壓回操作數(shù)棧.

void calculate(void)
{
    double post = popAndGetNum();
    char sign = popAndGetSign();
    double pre = popAndGetNum();
    double result = 0.0;
    switch (sign)
    {
        case '+':
            result = pre+post;
        break;
        case '-':
            result = pre-post;
        break;
        case '*':
            result = pre*post;
        break;
        case '/':
            if(fabs(post) < 1e-6)
            {
                cout<<"Error.Divisor is 0.";
                exit(EXIT_FAILURE);
            }
            else
                result = pre / post;
        break;
        case '^':
            result = pow(pre,post);
        break;
        case '%':
            result = static_cast<int>(pre) % static_cast<int>(post);
        break;
    }
    push(result);
}

bool canCalculate(char sign)
{
    if(sign == '(' || sign == '[' || sign == '{' || operators.empty())
        return false;
    char t = getSign();
    if(t == '^')
        return true;
    switch (t)
    {
        case '+':
        case '-':
            return sign == '+' || sign == '-';
        case '*':
        case '/':
        case '%':
            return sign == '+' || sign == '-' || sign == '*' || sign == '/' || sign == '%';
    }
    return false;
}

下面是calc類:

class calc
{
private:
    stack<char> operators;
    stack<double> operands;

    char getSign(void)
    {
        return operators.top();
    }

    double getNum(void)
    {
        return operands.top();
    }

    void popSign(void)
    {
        operators.pop();
    }

    void popNum(void)
    {
        operands.pop();
    }

    double popAndGetNum(void)
    {
        double num = getNum();
        popNum();
        return num;
    }

    char popAndGetSign(void)
    {
        char sign = getSign();
        popSign();
        return sign;
    }
public:
    void push(double num)
    {
        operands.push(num);
    }

    void push(char sign)
    {
        operators.push(sign);
    }

    char get(void)
    {
        return getSign();
    }

    void pop(void)
    {
        popSign();
    }

    double result(void)
    {
        return getNum();
    }

    void calculate(void)
    {
        double post = popAndGetNum();
        char sign = popAndGetSign();
        double pre = popAndGetNum();
        double result = 0.0;
        switch (sign)
        {
            case '+':
                result = pre+post;
            break;
            case '-':
                result = pre-post;
            break;
            case '*':
                result = pre*post;
            break;
            case '/':
                if(fabs(post) < 1e-6)
                {
                    cout<<"Error.Divisor is 0.";
                    exit(EXIT_FAILURE);
                }
                else
                    result = pre / post;
            break;
            case '^':
                result = pow(pre,post);
            break;
            case '%':
                result = static_cast<int>(pre) % static_cast<int>(post);
            break;
        }
        push(result);
    }

    bool canCalculate(char sign)
    {
        if(sign == '(' || sign == '[' || sign == '{' || operators.empty())
            return false;
        char t = getSign();
        if(t == '^')
            return true;
        switch (t)
        {
            case '+':
            case '-':
                return sign == '+' || sign == '-';
            case '*':
            case '/':
            case '%':
                return sign == '+' || sign == '-' || sign == '*' || sign == '/' || sign == '%';
        }
        return false;
    }

    bool empty(void)
    {
        return operators.empty();
    }
};

private封裝了一些簡(jiǎn)單的對(duì)兩個(gè)棧進(jìn)行操作的工具方法,公有的pop()與get()是對(duì)運(yùn)算符棧進(jìn)行的操作.因?yàn)橥獠坎恍枰獙?duì)操作數(shù)棧進(jìn)行操作,由calculate()進(jìn)行操作,公有的push重載了,可以push到操作數(shù)棧或運(yùn)算符棧.

b.計(jì)算部分

計(jì)算部分在這里直接放在了main中:

int main(void)
{
    check chk;
   while(!chk.inputAndCheck())
        cout<<"Error!Please input again.\n";
    string s = chk.getResult();
    size_t len = s.size();
    calc c;
    for(size_t i=0;i<len;++i)
    {
        if(isdigit(s[i]))
        {
            double num;
            size_t i1 = i+1;
           while(i1 < len && (isdigit(s[i1]) || s[i1] == '.'))
                ++i1;
            istringstream input(s.substr(i,i1));
            input>>num;
            i = i1-1;
            c.push(num);
        }
        else if(s[i] == '}' || s[i] == ']' || s[i] == ')')
        {
            char sign;
            char start = (s[i] == '}' ? '{' : ( s[i] == ']' ? '[' : '('));
           while((sign = c.get()) != start)
                c.calculate();
            c.pop();
        }
        else                          //s[i]  is  [ ( {  + - * / ^ %
        {
           while(c.canCalculate(s[i]))
                c.calculate();
            c.push(s[i]);
        }
    }
   while(!c.empty())
        c.calculate();
    cout<<"result is "<<c.result()<<endl;
    return 0;
}

對(duì)表達(dá)式的每個(gè)字符逐個(gè)處理,若是數(shù)字,提取出來(lái)并壓棧.
若是右括號(hào)類,不斷從運(yùn)算符棧中提取直到把這段括號(hào)內(nèi)的表達(dá)式計(jì)算完成.

否則若是左括號(hào)或者是運(yùn)算符,當(dāng)可以計(jì)算的時(shí)候一直計(jì)算,提取兩個(gè)操作數(shù)運(yùn)算并壓棧,再把新的運(yùn)算符壓棧.
最后使用result()獲取結(jié)果.

c.測(cè)試

這里就顯示幾個(gè)很長(zhǎng)的例子算了

當(dāng)然作者測(cè)試了很多的例子

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

6.6/{2.3+34.3*2.22-5%2+22%4*[2+3.4/5-(4.3+3.2*33.3)]+34.3} + 7.8*{2.4-6/6+0-0*[23.4-3.4/6+4*(2.2+3)]}+0 - 0 + 0.0 
= 10.8569

3.4 - (+3.34) + 34.3 * (-2) / 3.34 + {[(-3.4)^2/3.4+3.4/3]-3.32+[3*(-3)]}
= -28.2656

9^5-34.4^2.3+5%6-34+66%78-78%4 + (-3)*3.4 / {3*(-7)+[3*(-8)+3*(3.4+4.34)/9.3-3.2 + 0.0 - 0]+0.0 - 0}+3.4^4/6.888 
= 55683.2

不信的話可以手工計(jì)算一下.

6.整合

這部分把界面部分與表達(dá)式處理部分整合起來(lái).

(1)設(shè)置界面的調(diào)用進(jìn)程,并獲取輸出結(jié)果

計(jì)算表達(dá)式的程序叫MyCalc.exe,注意把它放在對(duì)應(yīng)的工程文件夾下面,然后使用QProcess調(diào)用.

從0開始自制計(jì)算器!

使用execute執(zhí)行,表達(dá)式先去除所有的空格,然后作為命令行參數(shù)傳遞給計(jì)算程序,然后計(jì)算程序把計(jì)算結(jié)果寫入到result.txt文件,Qt讀取這個(gè)文件,如果讀到#表示表達(dá)式輸入錯(cuò)誤,否則,則是正確的計(jì)算結(jié)果.
對(duì)于結(jié)果因?yàn)樵谟?jì)算程序中設(shè)置了fixed格式,因此對(duì)于
1+2
也會(huì)返回
3.000000
這步把多余的0去掉,還要注意小數(shù)點(diǎn)的情況.

(2)修改一些細(xì)節(jié)地方

a.鼠標(biāo)鍵盤修改事件

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

修改setText的內(nèi)容,把結(jié)果傳遞過去.

b.exe中設(shè)置數(shù)字的格式

從0開始自制計(jì)算器!

設(shè)置fixed格式,否則的話顯示的是科學(xué)計(jì)數(shù)法,對(duì)小數(shù)位數(shù)有要求的話可以設(shè)置setprecision.

c.設(shè)置錯(cuò)誤提示

這里出現(xiàn)錯(cuò)誤時(shí),輸出"#",然后主程序讀取到就會(huì)提示"表達(dá)式錯(cuò)誤,請(qǐng)重新輸入."

從0開始自制計(jì)算器!

還有除數(shù)為0的錯(cuò)誤提示,這個(gè)要注意一下:

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

d.可以考慮把錯(cuò)誤處理整合過來(lái)

比如輸入了一個(gè)點(diǎn),不能繼續(xù)輸入點(diǎn),輸入了一個(gè)乘號(hào)或者除號(hào)不能再繼續(xù)輸入另一個(gè)符號(hào):

從0開始自制計(jì)算器!

7.打包發(fā)布

(1) 首先去下載Enigma Virtual Box

(2) 添加環(huán)境變量

從0開始自制計(jì)算器!

把Qt文件夾下的如圖所示的bin添加到Path環(huán)境變量,

(3) 打包庫(kù)文件

使用windeployqt打包,首先把程序調(diào)成release模式,運(yùn)行一次,生成release的exe,然后把exe復(fù)制到一個(gè)單獨(dú)的文件夾,再用命令行進(jìn)入到這個(gè)文件夾,運(yùn)行

windelpoyqt xxx.exe

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

這個(gè)命令把需要的dll復(fù)制到當(dāng)前所在文件夾.

(4) 生成單個(gè)exe

打開Enigma Virtual Box,選擇
從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

第一個(gè)選擇release的exe,第二個(gè)選擇打包之后的文件夾,然后選擇添加文件,選擇遞歸添加,添加上一步生成的所有文件(夾).

從0開始自制計(jì)算器!

這里選擇壓縮文件.
然后選擇壓縮等待完成即可.

(5) 測(cè)試

點(diǎn)擊運(yùn)行.

從0開始自制計(jì)算器!

大功告成!!

8.源碼

  • 1.github(里面包含完整可執(zhí)行的單個(gè)exe)
    注:由于使用了lfs上傳大文件,所以clone的時(shí)候請(qǐng)使用

    git lfs clone
  • 2.碼云

    9.參考鏈接

    1.Qt淡入

2.Qt按鍵

3.Qt標(biāo)題欄

4.事件過濾器

5.Qt鼠標(biāo)事件

6.Qt延時(shí)處理

7.Qt文件讀寫

8.Qt打包成單文件

10.最后

這個(gè)簡(jiǎn)單的計(jì)算器有很大的改進(jìn)空間,比如可以添加各種"數(shù)":
正弦函數(shù),余弦函數(shù),正切函數(shù),反正弦函數(shù),指數(shù)函數(shù),對(duì)數(shù)函數(shù),高階導(dǎo)數(shù),抽象函數(shù),復(fù)合函數(shù).心里沒數(shù)

等等.另外還可以改進(jìn)矩形的按鈕,可以改成圓角矩形或者橢圓形.
另外,對(duì)于陰影的處理可以添加淡入淡出效果.

最后就是磨砂.因?yàn)閣in10的是有磨砂效果的,這個(gè)作者還不會(huì)....
最后再上幾個(gè)圖,看看效果(由于動(dòng)圖大小的限制只是簡(jiǎn)單的表達(dá)式...):

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

從0開始自制計(jì)算器!

希望你們也有一個(gè)屬于自己的計(jì)算器!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

新聞名稱:從0開始自制計(jì)算器!-創(chuàng)新互聯(lián)
文章分享:http://aaarwkj.com/article38/hsopp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站網(wǎng)站設(shè)計(jì)公司建站公司、標(biāo)簽優(yōu)化、網(wǎng)站制作、品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
av剧情免费在线观看| 成人性生交大片免费看中文| 国产成人精品免费视频大| 精品国产91久久粉嫩懂色| 日韩在线视频这里只有精品| 国产精品一区二区av在线| 水牛av影视亚洲精品| 欧美日韩精品福利一区二区| 日韩精品一区二区三区中文| 久久久久亚洲av成人| 抱着操才爽的免费视频观看| 日韩不卡区免费在线观看| 99热这里只有精品免费播放| 欧美日韩一区二区三区四区在线观看| 欧美伊人久久大综合精品| 日韩精品中文字幕欧美乱| 人妻精品中文字幕一区二区在线| 色综合婷婷九月中文字幕 | 国产无遮挡又黄又爽网站 | 亚洲综合国产中文字幕| 高清不卡一区二区在线观看| 亚洲精品一区二区三区高潮| 欧美日韩精品人妻一区| 日日干天天日夜夜操| 色婷婷精品二区久久蜜臀av| 国产激情av网站在线观看| 午夜毛片免费在线播放| 欧美性大片一区二区三区| 日韩成人三级一区二区| 变态另类专区一区二区三区| 一区二区三区国产欧美日本| 日韩福利成人av在线| 四虎精品在线免费视频| 美女口爆吞精一区二区| 丰满肥臀熟女高清区二区| 亚洲黄片在线免费播放观看| 国产一区二区高清在线| 成人在线观看一区二区三区| 最新国产av网址大全| 人妻日韩字幕一区二区| 97在线观看免费公开|