この章では、=ボタンがおされたときの処理の説明をしていきます
処理概要
=の処理概要について、もう一度おさらいをします
=の前まで入力していた値(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_buffer | stack[0] | 状態の説明 |
|---|---|---|---|---|
| 空 | 空 | 空 | 空 | 入力の先頭で=を押す |
| ―、+、×、÷ | 数値 | 空 | 数値 | 演算子のあとに=を押す |
| ―、+、×、÷ | 数値 | 数値 | 数値 | 数値、演算子、数字、演算子、数字、=のように押される場合 |
| 空 | 数値 | 数値 | 空 | 入力の先頭で数値のあとに=を押す |
処理内容
イコールボタンのイベント処理フロー
1. 直前の入力が数値かチェック
- もし
current_bufferが空でない(=数値が入力されている)場合:current_bufferの値をstack[1]にコピーする- もし
stack[0]が空なら、stack[0]に0をコピーする calculate()関数で計算を実行する
- もし
current_bufferが空(=直前の入力が演算子か先頭)の場合:- もし
stack[0]が空なら、0をstack[0]に代入する(入力の先頭で=を押す) - それ以外の場合は、
resultにstack[0]の値をコピーする
- もし
2.共通の処理
calculate()で計算した結果(result)をstack[0]にコピーするstack[0]の値をディスプレイに表示するstack[1]をクリアする- =を
last_operatorに保存し、ディスプレイに表示する 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の「戻る」ボタンの実装を行います
コメント