پرش به مطلب اصلی

ماشین‌حساب چهار عمل اصلی

این نمونه دو عدد را می‌گیرد، جمع، تفریق، ضرب یا تقسیم انجام می‌دهد، نتیجه را در متغیر اپ می‌نویسد و در صورت تعریف، عملکرد onResult را اجرا می‌کند. به پکیج جدید نیاز ندارد و از Flutter و API ویجت استفاده می‌کند.

افزودن نمونه​

  1. ویجت Flutter سفارشی را داخل گروه اضافه کنید.
  2. فایل calculator.dart را دانلود کنید و با «بارگذاری فایل دارت» وارد فرم کنید؛ یا کد کامل انتهای این صفحه را کپی کنید.
  3. عرض را «به اندازه والد» و ارتفاع را «به اندازه محتوا» قرار دهید.
  4. پارامترهای زیر را وارد کنید، ویجت و صفحه را ذخیره کنید و خروجی جدید بسازید.
{
"title": "ماشین حساب من",
"resultVariable": "calculator_result",
"decimals": 2,
"storeResult": false
}

پارامترها​

کلیدنوع و پیش‌فرضکاربرد
titleرشته؛ «ماشین حساب»عنوان داخل کارت
resultVariableرشته؛ calculator_resultنام متغیر عددی خروجی
decimalsعدد؛ 2اعشار نمایش، محدود به ۰ تا ۸
storeResultبولی؛ falseذخیرهٔ نتیجه روی دستگاه

اعشار فقط نحوهٔ نمایش را تغییر می‌دهد؛ مقدار متغیر، نتیجهٔ عددی محاسبه است. نتیجهٔ ذخیره‌شده در اجرای بعدی توسط این نمونه در کارت بازیابی نمی‌شود؛ می‌توانید آن را در نمایشگر متغیر نشان دهید.

اتصال به عملکرد و دیگر ویجت‌ها​

در فهرست عملکردهای همین ویجت، یک عملکرد با شناسهٔ onResult تعریف کنید؛ مثلاً «بازکردن صفحهٔ نتیجه». در آن صفحه، نمایشگر متغیری با نام calculator_result بگذارید.

ترتیب کار نمونه:

  1. بررسی معتبر بودن دو عدد و جلوگیری از تقسیم بر صفر.
  2. نمایش نتیجه در کارت.
  3. ساخت یا بازنویسی متغیر خروجی.
  4. اجرای onResult در صورت تعریف‌شدن.

برای دو ماشین‌حساب مستقل، به هرکدام resultVariable متفاوت بدهید. از نام ساده بدون نقطه و اندیس استفاده کنید.

امتحان در خروجی​

  • 12.5 + 7.5 باید 20.00 نمایش دهد و متغیر مقدار عددی 20 داشته باشد.
  • 10 / 0 پیام خطا می‌دهد و نتیجهٔ قبلی را بازنویسی نمی‌کند.
  • ورودی خالی یا نامعتبر پیام خطا می‌دهد.
  • اگر onResult تعریف نشده باشد، محاسبه و ذخیرهٔ نتیجه همچنان انجام می‌شود.

اعداد را با رقم انگلیسی و نقطه برای اعشار وارد کنید. این نمونه عبارت ریاضی مانند 2 + 3 * 4، پرانتز، تاریخچه یا عملیات علمی را پردازش نمی‌کند؛ هر بار یک عمل روی دو عدد انجام می‌دهد.

کد کامل​

تمام این کد را در یک ویجت قرار دهید:

import 'package:flutter/material.dart';
import 'package:my_app/appeditor/custom/AppEditorWidgetContext.dart';

Widget buildCustomWidget(BuildContext context, AppEditorWidgetContext app) {
return CalculatorWidget(app: app);
}

class CalculatorWidget extends StatefulWidget {
const CalculatorWidget({super.key, required this.app});
final AppEditorWidgetContext app;

State<CalculatorWidget> createState() => _CalculatorWidgetState();
}

class _CalculatorWidgetState extends State<CalculatorWidget> {
final _first = TextEditingController();
final _second = TextEditingController();
String _operation = '+';
double? _result;
bool _busy = false;


void dispose() {
_first.dispose();
_second.dispose();
super.dispose();
}

Future<void> _calculate() async {
final a = double.tryParse(_first.text.trim());
final b = double.tryParse(_second.text.trim());
if (a == null || b == null || !a.isFinite || !b.isFinite) {
widget.app.showMessage('دو عدد معتبر با رقم انگلیسی وارد کنید.');
return;
}
if (_operation == '/' && b == 0) {
widget.app.showMessage('تقسیم بر صفر ممکن نیست.');
return;
}
final result = switch (_operation) {
'+' => a + b,
'-' => a - b,
'*' => a * b,
_ => a / b,
};
if (!result.isFinite) {
widget.app.showMessage('نتیجه خارج از محدوده عددی است.');
return;
}
final app = widget.app;
final variable =
app.params['resultVariable'] as String? ?? 'calculator_result';
setState(() {
_busy = true;
_result = result;
});
try {
await app.addVar(
name: variable,
value: result,
storeOnDevice: app.params['storeResult'] == true,
overwrite: true,
);
if (mounted && app.hasAction('onResult')) await app.runAction('onResult');
} catch (error) {
app.showMessage('ذخیره نتیجه یا اجرای عملکرد ممکن نشد: $error');
} finally {
if (mounted) setState(() => _busy = false);
}
}


Widget build(BuildContext context) {
final args = widget.app.params;
final decimals = ((args['decimals'] as num?)?.toInt() ?? 2).clamp(0, 8);
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
args['title'] as String? ?? 'ماشین حساب',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 16),
Wrap(
spacing: 12,
runSpacing: 12,
crossAxisAlignment: WrapCrossAlignment.center,
children: [
SizedBox(
width: 130,
child: TextField(
controller: _first,
textDirection: TextDirection.ltr,
keyboardType: const TextInputType.numberWithOptions(
decimal: true,
signed: true,
),
decoration: const InputDecoration(labelText: 'عدد اول'),
),
),
DropdownButton<String>(
value: _operation,
items: ['+', '-', '*', '/'].map((value) {
return DropdownMenuItem(value: value, child: Text(value));
}).toList(),
onChanged: _busy
? null
: (value) {
if (value != null) setState(() => _operation = value);
},
),
SizedBox(
width: 130,
child: TextField(
controller: _second,
textDirection: TextDirection.ltr,
keyboardType: const TextInputType.numberWithOptions(
decimal: true,
signed: true,
),
decoration: const InputDecoration(labelText: 'عدد دوم'),
),
),
],
),
const SizedBox(height: 16),
FilledButton(
onPressed: _busy ? null : _calculate,
child: Text(_busy ? 'در حال انجام…' : 'محاسبه'),
),
if (_result != null) ...[
const SizedBox(height: 16),
Text(
_result!.toStringAsFixed(decimals),
textDirection: TextDirection.ltr,
style: Theme.of(context).textTheme.headlineMedium,
),
],
],
),
),
);
}
}