Skip to content

電卓の機能を実装する(後編)

公開日:January 31, 2025更新日:January 31, 2025
FlutterDartCoding📄

前編では、状態管理の仕組みを導入し、数値と演算子を保持する方法について学びました。後編では、ボタンタップ時の処理、計算ロジックの実装、そして状態の更新とUIへの反映について説明します。

3. ボタンタップ時の処理

まず、ボタンがタップされたときの処理を実装しましょう。CalculatorButton ウィジェットの onPressed プロパティに、ボタンの種類に応じた処理を記述します。

dart
CalculatorButton(
  text: '7',
  onPressed: () => _onNumberPressed('7'),
),

数値ボタンの場合は、_onNumberPressed メソッドを呼び出し、引数としてボタンのテキストを渡します。演算子ボタンの場合は、_onOperatorPressed メソッドを呼び出します。イコールボタンの場合は、_onEqualsPressed メソッドを呼び出します。クリアボタンの場合は、_onClearPressed メソッドを呼び出します。

_CalculatorState クラスに、これらのメソッドを追加しましょう。

dart
class _CalculatorState extends State<Calculator> {
  // ... 省略 ...

  void _onNumberPressed(String number) {
    setState(() {
      if (_currentValue == 0) {
        _currentValue = double.tryParse(number);
      } else {
        _currentValue = double.tryParse('$_currentValue$number');
      }
      _display = '$_currentValue';
    });
  }

  void _onOperatorPressed(String operator) {
    setState(() {
      _previousValue = _currentValue;
      _currentValue = 0;
      _operator = operator;
      _display = '$_previousValue $_operator';
    });
  }

  void _onEqualsPressed() {
    setState(() {
      if (_previousValue != null && _operator != null) {
        switch (_operator) {
          case '+':
            _currentValue = _previousValue! + _currentValue!;
            break;
          case '-':
            _currentValue = _previousValue! - _currentValue!;
            break;
          case 'x':
            _currentValue = _previousValue! * _currentValue!;
            break;
          case '/':
            if (_currentValue == 0) {
              _currentValue = null;
              _display = 'Error';
              return;
            }
            _currentValue = _previousValue! / _currentValue!;
            break;
        }
        _display = '$_currentValue';
        _previousValue = null;
        _operator = null;
      }
    });
  }

  void _onClearPressed() {
    setState(() {
      _currentValue = 0;
      _previousValue = null;
      _operator = null;
      _display = '0';
    });
  }

  // ... 省略 ...
}

各メソッドでは、setState を呼び出して状態を更新し、UIを再描画しています。

_onNumberPressed メソッドでは、数値ボタンが押されたときの処理を記述します。現在の値が0の場合は、押された数値に置き換えます。それ以外の場合は、現在の値の後ろに押された数値を追加します。そして_displayに現在の値を代入します。

_onOperatorPressed メソッドでは、演算子ボタンが押されたときの処理を記述します。現在の値を _previousValue に保存し、_currentValue を0にリセットします。選択された演算子を _operator に保存します。そして_displayに前回の値と演算子を代入します。

_onEqualsPressed メソッドでは、イコールボタンが押されたときの処理を記述します。_previousValue_operator がnullでないことを確認し、_operator の値に応じて計算を実行します。計算結果を _currentValue に保存し、_display に表示します。_previousValue_operator をnullにリセットします。

_onClearPressed メソッドでは、クリアボタンが押されたときの処理を記述します。すべての状態変数を初期値にリセットします。

4. 計算ロジックの実装

_onEqualsPressed メソッドで、簡単な四則演算を実装しました。ただし、この実装にはまだ改善の余地があります。例えば、連続して演算子ボタンが押された場合や、0で除算しようとした場合の処理が不十分です。

これらの問題を解決するために、計算ロジックを改良しましょう。

dart
void _onEqualsPressed() {
  setState(() {
    if (_previousValue != null && _operator != null && _currentValue != null) {
      double result = _calculate(_previousValue!, _currentValue!, _operator!);
      if (result.isFinite) {
        _currentValue = result;
        _display = '$_currentValue';
      } else {
        _currentValue = null;
        _display = 'Error';
      }
      _previousValue = null;
      _operator = null;
    }
  });
}

double _calculate(double previousValue, double currentValue, String operator) {
  switch (operator) {
    case '+':
      return previousValue + currentValue;
    case '-':
      return previousValue - currentValue;
    case 'x':
      return previousValue * currentValue;
    case '/':
      if (currentValue == 0) {
        return double.infinity;
      }
      return previousValue / currentValue;
    default:
      return currentValue;
  }
}

_calculate という新しいメソッドを追加し、実際の計算処理をこのメソッドに移動しました。_onEqualsPressed メソッドでは、_calculate メソッドを呼び出し、計算結果を取得します。計算結果が有限値(isFinite)の場合は、_currentValue_display を更新します。無限大やNaNの場合は、エラーを表示します。

_calculate メソッドでは、switch 文を使って演算子に応じた計算を実行します。0で除算しようとした場合は、無限大(double.infinity)を返します。

5. 状態更新とUIへの反映

最後に、状態の更新をUIに反映させましょう。_CalculatorState クラスの build メソッドで、_display 変数の値を Text ウィジェットに表示します。

dart
class _CalculatorState extends State<Calculator> {
  // ... 省略 ...

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: <Widget>[
          // 結果表示エリア
          Expanded(
            child: Container(
              color: Colors.blueGrey,
              alignment: Alignment.bottomRight,
              padding: const EdgeInsets.all(16.0),
              child: Text(
                _display, // _display 変数の値を表示
                style: const TextStyle(
                  fontSize: 48.0,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
            ),
          ),
          // ボタンエリア
          // ... 省略 ...
        ],
      ),
    );
  }
}

_display 変数の値が Text ウィジェットに表示されるようになりました。

また、CalculatorButton ウィジェットの onPressed プロパティを修正し、ボタンの種類に応じたメソッドを呼び出すようにします。

dart
CalculatorButton(
  text: '7',
  onPressed: () => _onNumberPressed('7'),
),
CalculatorButton(
  text: '8',
  onPressed: () => _onNumberPressed('8'),
),
// ... 省略 ...
CalculatorButton(
  text: '/',
  onPressed: () => _onOperatorPressed('/'),
),
CalculatorButton(
  text: 'x',
  onPressed: () => _onOperatorPressed('x'),
),
// ... 省略 ...
CalculatorButton(
  text: '=',
  flex: 2,
  onPressed: () => _onEqualsPressed(),
  color: Colors.orange,
),
CalculatorButton(
  text: 'C',
  onPressed: () => _onClearPressed(),
),

これで、ボタンをタップしたときの処理が実装され、状態の更新がUIに反映されるようになりました。