ماشینحساب چهار عمل اصلی
این نمونه دو عدد را میگیرد، جمع، تفریق، ضرب یا تقسیم انجام میدهد، نتیجه را در متغیر اپ مینویسد و در صورت تعریف، عملکرد onResult را اجرا میکند. به پکیج جدید نیاز ندارد و از Flutter و API ویجت استفاده میکند.
افزودن نمونه
- ویجت Flutter سفارشی را داخل گروه اضافه کنید.
- فایل calculator.dart را دانلود کنید و با «بارگذاری فایل دارت» وارد فرم کنید؛ یا کد کامل انتهای این صفحه را کپی کنید.
- عرض را «به اندازه والد» و ارتفاع را «به اندازه محتوا» قرار دهید.
- پارامترهای زیر را وارد کنید، ویجت و صفحه را ذخیره کنید و خروجی جدید بسازید.
{
"title": "ماشین حساب من",
"resultVariable": "calculator_result",
"decimals": 2,
"storeResult": false
}
پارامترها
| کلید | نوع و پیشفرض | کاربرد |
|---|---|---|
title | رشته؛ «ماشین حساب» | عنوان داخل کارت |
resultVariable | رشته؛ calculator_result | نام متغیر عددی خروجی |
decimals | عدد؛ 2 | اعشار نمایش، محدود به ۰ تا ۸ |
storeResult | بولی؛ false | ذخیرهٔ نتیجه روی دستگاه |
اعشار فقط نحوهٔ نمایش را تغییر میدهد؛ مقدار متغیر، نتیجهٔ عددی محاسبه است. نتیجهٔ ذخیرهشده در اجرای بعدی توسط این نمونه در کارت بازیابی نمیشود؛ میتوانید آن را در نمایشگر متغیر نشان دهید.
اتصال به عملکرد و دیگر ویجتها
در فهرست عملکردهای همین ویجت، یک عملکرد با شناسهٔ onResult تعریف کنید؛ مثلاً «بازکردن صفحهٔ نتیجه». در آن صفحه، نمایشگر متغیری با نام calculator_result بگذارید.
ترتیب کار نمونه:
- بررسی معتبر بودن دو عدد و جلوگیری از تقسیم بر صفر.
- نمایش نتیجه در کارت.
- ساخت یا بازنویسی متغیر خروجی.
- اجرای
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,
),
],
],
),
),
);
}
}