C++ 10日目:=(イコール)演算子の入力

この章では、=ボタンがおされたときの処理の説明をしていきます

処理概要

=の処理概要について、もう一度おさらいをします

=の前まで入力していた値(stack[0]とstack[1])を、last_operatorが保持する演算子で計算し、計算結果を表示します
その後、計算結果はstack[0]にコピーし、current_buffer、stack[1]をクリアします
入力された=はlast_operatorに代入しディスプレイにも表示します

=の押された位置で以下のことを考慮します

ケース1. =単独の入力

入力の先頭で=を押すような場合です
この場合、current_buffer、stack[0]、last_operatorともに空文字です
=しか入力されていないため、stack[0]に0を代入し、ディスプレイにも0を表示します
入力された=はlast_operatorに代入しディスプレイにも表示します

ケース2. 演算式で終わる式

1+=、1×-=、1‐= 、1×2==、1+2×=などを想定します
演算子に対して、右辺値が未定義であるため、左辺値のstack[0]の値を計算結果としてディスプレイに表示します
current_buffer、stack[1]はクリアします
入力された=はlast_operatorに代入しディスプレイにも表示します

ケース3. 数値単独の入力

入力の先頭で数値のあとに=と押す場合を想定します(例:3=)
この場合、stack[0]、last_operatorともに空文字で、current_bufferは数値が入っています
演算子および左辺値が未定義であるため、左辺値のstack[0]に0を代入、current_bufferの値をstack[1]に代入し、計算結果としてstack[1]の値をディスプレイに表示します
current_buffer、stack[1]はクリアします
入力された=はlast_operatorに代入しディスプレイにも表示します

前提条件

=ボタンが押される直前の電卓は、処理概要および「考慮すること」に対して、それぞれどのような状態の場合があるかを考えてみます

演算子の表示部分数値の表示部分current_bufferstack[0]状態の説明
入力の先頭で=を押す
―、+、×、÷数値数値演算子のあとに=を押す
―、+、×、÷数値数値数値数値、演算子、数字、演算子、数字、=のように押される場合
数値数値入力の先頭で数値のあとに=を押す

処理内容

イコールボタンのイベント処理フロー

1. 直前の入力が数値かチェック

  • もしcurrent_bufferが空でない(=数値が入力されている)場合:
    • current_bufferの値をstack[1]にコピーする
    • もしstack[0]が空なら、stack[0]に0をコピーする
    • calculate()関数で計算を実行する
  • もしcurrent_bufferが空(=直前の入力が演算子か先頭)の場合:
    • もしstack[0]が空なら、0stack[0]に代入する(入力の先頭で=を押す)
    • それ以外の場合は、resultにstack[0]の値をコピーする

2.共通の処理

  1. calculate()で計算した結果(result)をstack[0]にコピーする
  2. stack[0]の値をディスプレイに表示する
  3. stack[1]をクリアする
  4. =をlast_operatorに保存し、ディスプレイに表示する
  5. current_bufferをクリアする

実装

イベントハンドラの設定

VisualC++の機能を使用してイコールボタンのイベントハンドラを作成します
その後、イベントハンドラに処理を記述していきます
作成されたイベントハンドラはafx_msg void OnBnClickedButtonEqual();です

1. MyCalculatorDlg.h

class CMyCalculatorDlg : public CDialogEx
{
// コンストラクション
public:
    CMyCalculatorDlg(CWnd* pParent = nullptr);  // 標準コンストラクター

// ダイアログ データ
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_MYCALCULATOR_DIALOG };
#endif

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV サポート


// 実装
private:
    void AddEditBoxText(LPCTSTR lpText);
    void setEditBoxText(LPCTSTR lpText);
    void initVariable();
    void clickOperatorButton(LPCTSTR lpText); 
    void setOperatorText(LPCTSTR lpText); 
    void clearCurrentBuffer();
    double calculate();   
    void HandleNumberClick(LPCTSTR number_char);
    void disableButton();    
    void enableButton();
    double IsNumberAndConvert(const TCHAR* lpText);  
    CString ConvertDoubleToCString(double result); 

    CString current_buffer = _T("");
    CString last_operator = _T("");
    CString stack[2] = {_T(""),_T("")};

protected:
    HICON m_hIcon;

    // 生成された、メッセージ割り当て関数
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnBnClickedButtonAc();
    afx_msg void OnBnClickedButtonZero();
    afx_msg void OnBnClickedButtonOne();
    afx_msg void OnBnClickedButtonTwo();
    afx_msg void OnBnClickedButtonThree();
    afx_msg void OnBnClickedButtonFour();
    afx_msg void OnBnClickedButtonFive();
    afx_msg void OnBnClickedButtonSix();
    afx_msg void OnBnClickedButtonSeven();
    afx_msg void OnBnClickedButtonEight();
    afx_msg void OnBnClickedButtonNine();
    afx_msg void OnBnClickedButtonPlus();  
    afx_msg void OnBnClickedButton1Minus(); 
    afx_msg void OnBnClickedButtonMulti();  
    afx_msg void OnBnClickedButtonDiv();  
    afx_msg void OnBnClickedButtonEqual(); // =演算子  
    afx_msg void OnBnClickedButtonDecimal();
};

2. MyCalculatorDlg.cpp

void CMyCalculatorDlg::OnBnClickedButtonEqual()
{
    // TODO: ここにコントロール通知ハンドラー コードを追加します。
    bool flg = current_buffer.IsEmpty();
    double result = 0.0;

    try {
        if (flg == true) { // current_bufferが空文字のとき
            if (stack[0].IsEmpty())
            {
                stack[0] = "0";
                result = 0;
            }
            else {
                result = IsNumberAndConvert(stack[0]);
            }
        }
        else {
            if (stack[0].IsEmpty())
            {
                stack[0] = "0";
            }

            stack[1] = current_buffer;

            result = calculate();
        }

        // 計算結果を文字列に変換しディスプレイに表示する
        CString str;
        str = ConvertDoubleToCString(result);

        setEditBoxText(str);

        // 計算結果をstack[0]にコピーする
        stack[0] = str;

        // 変数を初期状態に戻す
        clearCurrentBuffer();
        stack[1] = "";

        // 最後に入力した演算子に=を代入
        setOperatorText(_T("="));
        last_operator = _T("=");
    }
    catch (const std::invalid_argument& e) {
        CString str(e.what());
        setEditBoxText(str);
        disableButton();
    }
}

以上が、イコールボタンを実装したプログラムです
ここまでが、フェーズ1です
次回は、フェーズ2の「戻る」ボタンの実装を行います

コメント

この記事へのコメントはありません。

関連記事

Python 応用編 6日目

Java 応用編 2日目

C言語 応用編 ~7日目~

PAGE TOP