首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

MFC 簡單計算器實作教學:Switch 邏輯與介面設計

     編輯:程式設計疑難解答

使用 MFC (Microsoft Foundation Classes) 開發簡單計算器,需求:四則運算、小數點、Switch 語句邏輯、暫存運算元與結果。本文提供完整架構設計、核心代碼與常見坑指南。

專案建立步驟

  1. Visual Studio → MFC Application → Dialog based → 專案名 SimpleCalc。
  2. 資源視圖編輯對話框 IDD_SIMPLECALC_DIALOG:
    • 編輯框 IDC_EDIT_DISPLAY (顯示輸入/結果,Right Align、Read Only)。
    • 按鈕:0-9、+ - * /、.、=、C (清除)、CE (清除輸入)。
    • 按鈕 ID 命名:IDC_BTN_0...IDC_BTN_9, IDC_BTN_ADD, IDC_BTN_SUB, IDC_BTN_MUL, IDC_BTN_DIV, IDC_BTN_DOT, IDC_BTN_EQ, IDC_BTN_CLR, IDC_BTN_CE。
  3. 類向導為所有按鈕添加 BN_CLICKED 處理器。

核心資料成員 (Dialog 類別)

// SimpleCalcDlg.h
double m_firstOperand;   // 前一個運算元
double m_secondOperand;  // 當前輸入運算元
int    m_operator;       // 運算子代碼:0=無, 1=+, 2=-, 3=*, 4=/
bool   m_waitingForSecond; // 是否等待輸入第二運算元
CString m_displayStr;    // 顯示字串 (DDX 綁定 IDC_EDIT_DISPLAY)

統一按鈕處理架構

數字鍵 0-9

void CSimpleCalcDlg::OnBtnDigit(UINT nID) {
    int digit = nID - IDC_BTN_0; // 假設 ID 連續
    if (m_waitingForSecond) {
        m_displayStr = _T("");
        m_waitingForSecond = false;
    }
    if (m_displayStr == _T("0") || m_displayStr.IsEmpty())
        m_displayStr = std::to_wstring(digit).c_str();
    else
        m_displayStr += std::to_wstring(digit).c_str();
    UpdateData(FALSE); // 更新 UI
}

在類向導為 10 個數字鍵分別綁定,或手動在 ON_COMMAND_RANGE(IDC_BTN_0, IDC_BTN_9, OnBtnDigit)。

小數點

void CSimpleCalcDlg::OnBtnDot() {
    if (m_waitingForSecond) { m_displayStr = _T("0"); m_waitingForSecond = false; }
    if (m_displayStr.Find(_T('.')) == -1) m_displayStr += _T(".");
    UpdateData(FALSE);
}

運算子 + - * / (核心 Switch 邏輯)

void CSimpleCalcDlg::OnBtnOperator(UINT nID) {
    // 1. 取得當前顯示值作為運算元
    double currentValue = _ttof(m_displayStr);
    
    // 2. 若有前一運算子且非等待第二運算元,先執行前一運算 (連續運算支援)
    if (m_operator != 0 && !m_waitingForSecond) {
        Calculate(); // 執行 m_firstOperand (op) m_secondOperand
        m_firstOperand = m_secondOperand; // 結果作為下一運算的左運算元
    } else {
        m_firstOperand = currentValue;
    }
    
    // 3. 記錄新運算子
    switch (nID) {
        case IDC_BTN_ADD: m_operator = 1; break;
        case IDC_BTN_SUB: m_operator = 2; break;
        case IDC_BTN_MUL: m_operator = 3; break;
        case IDC_BTN_DIV: m_operator = 4; break;
    }
    m_waitingForSecond = true; // 下一個輸入為右運算元
    UpdateData(FALSE);
}

等號 = (執行計算)

void CSimpleCalcDlg::OnBtnEq() {
    if (m_operator == 0) return; // 無運算子
    m_secondOperand = _ttof(m_displayStr);
    Calculate();
    m_operator = 0; // 重置運算子
    m_waitingForSecond = true; // 下一輸入重新開始
    UpdateData(FALSE);
}

void CSimpleCalcDlg::Calculate() {
    double result = 0;
    switch (m_operator) {
        case 1: result = m_firstOperand + m_secondOperand; break;
        case 2: result = m_firstOperand - m_secondOperand; break;
        case 3: result = m_firstOperand * m_secondOperand; break;
        case 4: 
            if (m_secondOperand == 0) {
                AfxMessageBox(_T("除數不能為零"));
                result = m_firstOperand; // 保持原值
            } else {
                result = m_firstOperand / m_secondOperand;
            }
            break;
    }
    m_secondOperand = result;
    m_displayStr.Format(_T("%.10g"), result); // 科學計數法自動切換,去除尾隨 0
}

清除鍵 C / CE

void CSimpleCalcDlg::OnBtnClr() { // C: 全清
    m_firstOperand = m_secondOperand = 0;
    m_operator = 0;
    m_waitingForSecond = false;
    m_displayStr = _T("0");
    UpdateData(FALSE);
}

void CSimpleCalcDlg::OnBtnCe() { // CE: 清除當前輸入
    m_displayStr = _T("0");
    m_waitingForSecond = false;
    UpdateData(FALSE);
}

進階強化建議

  • 鍵盤支援:PreTranslateMessage 攔截 VK_NUMPAD0-9, VK_ADD 等觸發對應按鈕。
  • 運算優先級:若需支援 1+2*3=7,需實作運算式解析 (Shunting-yard 算法或遞歸下降),而非簡單左結合。
  • 歷史記錄:CListBox 記錄每次運算式與結果。
  • 單元測試:將 Calculate() 邏輯抽離為獨立類/函數,配合 Google Test 驗證邊界值。

常見坑避雷

現象原因修正
連續按運算子 (+ 後按 -) 邏輯錯亂未處理「運算子替換」情況在 OnBtnOperator 中判斷 m_waitingForSecond 為 true 時直接替換 m_operator
小數精度顯示問題 (0.1+0.2=0.30000000000000004)double 二進位浮點誤差顯示用 Format(_T("%.10g")) 或引入定點數/十進位庫
除零崩潰未檢查除數Calculate() 中 case 4 判斷 m_secondOperand == 0

MFC 計算器是理解「事件驅動、狀態機、UI/邏輯分離」的絕佳練習。掌握 Switch 狀態機模式,後續擴充科學計算機、程式設計師計算機皆同理可循。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved