پیاده سازی ماشین حساب با سی شارپ — مرور مفاهیم پایه

 

ماشین حساب

برای شروع ابتدا یک فرم ایجاد می کنیم و فونت آن را مشخص نموده و قسمت maximizebox و formborderstyle را از قسمت properties انتخاب می کنیم به قسمی که اندازه پنجره، در زمان اجرا تغییر نکند. سپس به آن یک panel اضافه می کنیم.

 

ماشین حساب

برای شروع ابتدا یک فرم ایجاد می کنیم و فونت آن را مشخص نموده و قسمت maximizebox و formborderstyle را از قسمت properties انتخاب می کنیم به قسمی که اندازه پنجره، در زمان اجرا تغییر نکند.
سپس به آن یک panel اضافه می کنیم. به شکل زیر

1

سپس ظاهر فرم را می سازیم وtext آنها را مشخص می کنیم. بعد از آن به نام گذاری می پردازیم.

بعد از نامگذاری باید دقت کرد که TextBox نباید مستقیما از طرف کاربر نوشته شود. به این معنی که حتما باید فقط از طریق دکمه ها در جعبه متن تایپ شود. لذا در قسمت properties/ ReadOnly ارزش آن راTrue قرار می دهیم.
سپس رنگ را تعیین می کنیم که در شکل زیر نمایش داده شده است.

2
برای button های ۰ تا ۹ یک رخداد مشترک به اسم Numbers می سازیم .شکل زیر

3
و در آن قطعه کد زیر را می نویسیم. که با فشار بر هر دکمه آن عدد را در جعبه متن وارد کنید.

private void numbers(object sender, EventArgs e)
{
txtdisplay.Text += ((Control)sender).Text;
}

حال که یک عدد را وارد کردیم برای اعداد بعدی و عملگر ها که میخواهیم وارد کنیم باید این اعداد ذخیره شوند، لذا باید در متغیرهای سراسری ذخیره شوند تا با وارد کردن عملگر ها، عدد بعدی از بین نروند.
برای تحقق این موضوع به صورت زیر عمل می کنیم:
x اولین عدد مساله ، y دومین عدد محاسبه و z نتیجه نهایی است.
Op عملگر است .

public partial class Form1 : Form
{
double x, y, z;
string op;
.
.
.

بعد از این، برای بکار بردن چهار عمل * , / , + , – یک رخداد با نام oprators ایجاد می کنیم .

4

الگوریتم این قسمت به این شکل است:
۱- عدد درون جعبه متن را وارد متغییر سراسری x می کنیم .
۲- عملگر انتخاب شده را وارد متغیر سراسریop می کنیم .
۳- جعبه متن را خالی می کنیم.

private void oprators(object sender, EventArgs e)
{
x = Convert.ToDouble(txtdisplay.Text);
op = ((Button)sender).Text;
txtdisplay.Text =””;
}

چون عملکرد دکمه مساوی شبیه هیچ یک از بقیه دکمه ها ی دیگر نیست پس برای آن یک رخداد جداگانه ایجاد می کنیم و نام آن را btnequal می گذاریم.

الگوریتم این رخداد به صورت زیر است:
۱ – عددی که در جعبه متن وجود دارد عدد دوم برای محاسبه هست پس آن را ازstring تبدیل به double می کنیم و در متغییر سراسری y می ریزیم.

۲ – با استفاده از دستور switch case برای متغییر op عمل مناسب آن را اعمال می کنیم و نتیجه را در متغییر سراسری z می ریزیم.

۳- متغییر سراسری z را به stringتبدیل کرده و برای نمایش در جعبه متن قرار می دهیم.

private void btnequal_Click(object sender, EventArgs e)
{
y = Convert.ToDouble(txtdisplay.Text);
switch (op)
{
case “+”:
z = x + y;
break;
case “-“:
z = x – y;
break;
case “*”:
z = x * y;
break;
case “/”:
z = x / y;
break;

}
txtdisplay.Text = z.ToString();
}

حال برای دکمه ی ” . ” می خواهیم کد بنویسیم. برای این منظور دقت می کنیم و متوجه می شویم که این دکمه، شبیه دکمه های ۰ تا ۹عمل می کند. لذا رخداد کلیک آن را رویداد مشترک اعداد ۰ تا ۹ یعنی همان رخداد Numbers قرار می دهیم.

5

مشکلی که ایجاد می شود این است که کاربر میتواند چندین بار عبارت ” . ” را تایپ کند. برای رفع این مشکل وارد قسمت TextChanged جعبه متن می شویم قطعه کد زیر را می نویسیم.

private void txtdisplay_TextChanged(object sender, EventArgs e)
{
btnpoint.Enabled = !txtdisplay.Text.Contains(“.”);
}

چون خصوصیت enabled فقط دو حالت trueو false می گیرد لذا قسمت راست کد هم توجیه می شود با این توضیح که اگر جعبه متن حاوی عبارت ” . ” نبود، مقدار false را برمی گرداند. (علامت ! به مفهوم not کردن یک عبارت است)
عمکرد تابع contains() در ادامه نمایش داده شده است:

6
حال برای پاک کردن کارکترهای درون جعبه متن به صورت یکی یکی و از انتها از دکمه backspace که در صورت برنامه به شکل —-> نمایش دادیم استفاده می کنیم و در رخداد کلیک ان کد زیر را مینویسم:

private void btnbackspace_Click(object sender, EventArgs e)
{
txtdisplay.Text = txtdisplay.Text.Substring(0, txtdisplay.Text.Length – 1);
}

توضیح کد:

تابع substring(int SrtartIndex , int lenght) به این صورت عمل می کند که یک رشته را می گیرد و از اندیس startIndex به اندازه length جدا می کند و برمی گرداند.

و در این کد هم از اندیس صفر تا یکی مانده به آخر را دوباره به جعبه متن برمی گرداند و این کار به این معنی است که آخرین عدد ورودی پاک می شود.

اما مشکلی که ایجاد می شود این است که اگر جعبه متن خالی باشد، با زدن دکمه backspace دچار یک Runtime erroe می شود. به این دلیل که در قطعه کد ذکر شده نمی شود رشته به طول صفر وارد نمود.
برای حل این مشکل باید کاری کنیم که وقتی جعبه متن خاموش است دکمه backspace خاموش باشد. به همین منظور در قسمت Textchanged جعبه متن قطعه کد زیر را وارد می کنیم.

btnbackspace.Enabled = Convert.ToBoolean(txtdisplay.Text.Length);

حال برای اینکه این کد برای بار اول هم درست کار کند. باید در هنگام لود شدن فرم قسمت Textchanged را صدا بزنیم:

private void Form1_Load(object sender, EventArgs e)
{
textBox1_TextChanged(null, null);

}

تمرین ۱:

برنامه ماشین حساب را به نحوی تغییر دهید که با کلیک روی دکمه های عملگر (+ – * / ) جعبه متن خالی نگردد، در عوض با زدن اولین رقم عدد دوم جعبه متن خالی شود (همانند ماشین حساب ویندوز امتحان کنید).
جواب : برای این کار باید به الگوریتم حل مساله دقت کنیم. یعنی مساله از ما می خواهد که جعبه متن با زدن اولین عدد خالی نگردد و با زدن عملگر بدون تغییر در جعبه متن بماند و پس از زدن اولین رقم از عدد دومی که قرار است در محاسبه شرکت کند، جعبه متن خالی شود وقتی دقت می کنیم می بینیم که دستوری که جعبه متن را خالی می کند در ریزبرنامه oprators هست. اولین کار این است که این کد (txtdisplay.Text =””; ) را برمی داریم. سپس دقت می کنیم جعبه متن بعد از زدن عملگر درست کار می کند ولی با زدن رقم های عدد دوم جعبه متن خالی نمی شود که در ادامه این مشکل حل خواهد شد.
خب باید برنامه دو موضوع را درک کند:
۱- جعبه متن را خالی کن. (زمانی باید این اتفاق بیفتد که عدد دوم وارد شود و می دانم که اعداد با استفاده ریز برنامه Numberes وارد میشوند)

۲- عدد دوم وارد شده با عدد اول وارد شده فرق می کند. (با استفاده از یک پرچم(flage) از نوع بولین این قسمت حل می شود. به این صورت در ریز برنامهNumbers شرط می کنیم که اگر flage مقدار trueرا داشت به این معنی است که داریم عدد دومی را وارد می کنیم پس جعبه متن را خالی کن. اما در چه زمانی متوجه می شویم که عدد دوم را می خواهیم وارد کنیم؟ زمانی که یکی از عملگرها اعمال شود در نتیجه درریز برنامه oprators ، پرچم(flage) مقدار true را میگیرد)

private void oprators(object sender, EventArgs e)
{
x = Convert.ToDouble(txtdisplay.Text);
op = ((Button)sender).Text;
//txtdisplay.Text =””;
flag = true;

}

——————————————————–//

private void numbers(object sender, EventArgs e)
{
if (flag == true)
{
txtdisplay.Text = “”;
flag = false;
}
txtdisplay.Text += ((Control)sender).Text;
}

 

تمرین ۲:

برنامه ماشین حساب را به نحوی تغییر دهید که دکمه عملگر (+ – * /) تکرار پذیر باشند به این معنی که بدون کلیک کردن دکمه ی = بتوان عملگر جدیدی وارد کرد و محاسبات درست انجام شود (مانند ماشین حساب ویندوز)
جواب : مثلا ما میخواهیم پنج عدد را با هم جمع کنیم و مساله از ما میخواهد که با وارد کردن علمگر جمع برای بار دوم و سوم و چهارم، هر بار جمع اعداد قبلی را در جعبه متن نمایش دهد. برای حل این قسمت باز به الگوریتم مساله دقت می کنیم. باید بین وارد کردن عملگر برای بار اول و بقیه بار ها تمایز قایل شوم. پس از متغییر op کمک می گیریم به این صورت که زمانی متغییر op خالی است که برای بار اول عملگرها شرکت کرده اند و در غیر این صورت با هر بار شرکت کردن عملگر ها در محاسبه، محاسبات قبل از آن عملگر باید حساب شود و در جعبه متن نمایش داده شود که در زیر آمده)

7

.          

.          

            op = null;

{       

می خواهیم کاری کنیم که ماشین حساب با فشار دکمه ها روی کی‌برد که توسط کاربر فشرده میشوند، کار کند.
هدف :آشنایی با رخداد های صفحه کلید و استفاده از پارامتر دوم همه رخداد ها (e)

تعاریف اولیه :

keypress: رخدادی است که بر اثر فشرده شدن کلید روی کیبرد ، برای شی فوکوس دار، اتفاق می افتد.
Keypreview: خصوصیتی از form (موجود در قسمت properties) که درصورتی true باشد، به ازای هر کلیدی که توسط کاربر زده شود اجرا می شود.
e.keychar: پارامتردوم ورودی رخدادها است که حاوی کلید فشار داده شده توسط کاربر است.

در ابتدا خصوصیت Keypreview را true کرده و در قسمت رخدادِ keypress موجود در فرم ، شروع به نوشتن کد می کنیم.

private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{

Button temp = new Button();//یک دکمه تعریف میکنیم .
temp.Text = e.KeyChar.ToString();کارکتر ورودی را به صورت رشته میکنیم و در قسمت تکست دکمه قرار میدهیم .//
if (e.KeyChar >= ‘0’ && e.KeyChar <= ‘9’)
Numbers(temp, null);
else if (e.KeyChar == ‘+’||e.KeyChar == ‘-‘||e.KeyChar ==’*’||e.KeyChar== ‘/’)
Operators(temp, null);
else if (e.KeyChar == ‘=’)
btnequal_Click(null, null);
else if (e.KeyChar == ‘.’ && txtdisplay.Text.Contains(“.”) == false)
Numbers(temp, null);
else if (e.KeyChar == ‘\b’)با ایجاد یه بریک پوینت در برنامه میتوان کارکتر مربوط به بک اسپیس فهمید//
btnbackspace_Click(null, null);
}

حال اگر دکمه backspace را فشار دهیم در حالی که جعبه متن خالی است، برنامه دچار یک Runtime Error می شود. پس با یک شرط رخداد کلیک دکمهbackspace را اصلاح می کنیم:

private void btnbackspace_Click(object sender, EventArgs e)
{
if(txtdisplay.TextLength>0)
txtdisplay.Text = txtdisplay.Text.Substring(0, txtdisplay.Text.Length – 1);
}

حال میخواهیم کاری کنیم که هر دکمه ای میزنیم داری فوکوس شود و رنگ آن هم قرمز شود:

9

 

 

8

تمام کد نهایی به صورت زیر است :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace calculator
{
public partial class Form1 : Form
{
double x, y, z;
string op;
Boolean flag;

public Form1()
{
InitializeComponent();
}

private void Numbers(object sender, MouseEventArgs e)
{
if (flag == true)
{
txtdisplay.Text = “”;
flag = false;
}

txtdisplay.Text += ((Button)sender).Text;
}

private void Operators(object sender, MouseEventArgs e)
{
if (op != null)
btnequal_Click(null, null);
x = Convert.ToDouble(txtdisplay.Text);
op = ((Button)sender).Text;
flag = true;
}

private void btnequal_Click(object sender, MouseEventArgs e)
{
y = Convert.ToDouble(txtdisplay.Text);
switch (op)
{

case “+”:
z = x + y;
break;
case “-“:
z = x – y;
break;
case “*”:
z = x * y;
break;
case “/”:
z = x / y;
break;

}
txtdisplay.Text = z.ToString();
op = null;
}

private void btnonoff_Click(object sender, EventArgs e)
{
panel1.Enabled = !panel1.Enabled;
if (btnonoff.Text == “On”)
{
btnonoff.Text = “Off”;
this.KeyPreview = true;
}
else
{
btnonoff.Text = “On”;
this.KeyPreview = false;
}
}

private void txtdisplay_TextChanged(object sender, EventArgs e)
{
//if (txtdisplay.Text.Contains(“.”) == true)
// btnpoint.Enabled = false;
//else
// btnpoint.Enabled = true;
btnpoint.Enabled = !txtdisplay.Text.Contains(“.”);
btnbackspace.Enabled = Convert.ToBoolean(txtdisplay.Text.Length);
}

private void btnbackspace_Click(object sender, EventArgs e)
{
if(txtdisplay.TextLength>0)
txtdisplay.Text = txtdisplay.Text.Substring(0, txtdisplay.Text.Length – 1);
}

private void Form1_Load(object sender, EventArgs e)
{
txtdisplay_TextChanged(null, null);
}

private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
foreach (Button x in panel1.Controls)
if (x.Text == e.KeyChar.ToString())
{
x.Focus();
x.ForeColor = Color.Red;
}
else
x.ForeColor = Color.Black;

Button temp = new Button();
temp.Text = e.KeyChar.ToString();
if (e.KeyChar >= ‘0’ && e.KeyChar <= ‘9’)
Numbers(temp, null);
else if (e.KeyChar == ‘+’|| e.KeyChar == ‘-‘ || e.KeyChar == ‘*’ || e.KeyChar == ‘/’)
Operators(temp, null);
else if (e.KeyChar == ‘=’)
btnequal_Click(null, null);
else if (e.KeyChar == ‘.’ && txtdisplay.Text.Contains(“.”) == false)
Numbers(temp, null);
else if (e.KeyChar == ‘\b’)
btnbackspace_Click(null, null);
}

private void Form1_KeyUp(object sender, KeyEventArgs e)
{
//MessageBox.Show(“Im in Keyup”);
if (e.KeyCode == Keys.Enter){
btnequal_Click(null, null);
btnequal.Focus();
}
}

private void btnonoff_MouseClick(object sender, MouseEventArgs e)
{
MessageBox.Show(“Im in btnonoff MouseClick”);
}
}
}

 

آنچه مطالعه کردید، توسط یکی از مخاطبان فرادرس به عنوان پیاده سازی و برداشت متنی بخش هایی از آموزش «مجموعه آموزش های کاربردی برنامه نویسی C#‎ (سی شارپ)» تهیه شده و جهت استفاده سایر مخاطبین گرامی در متلب سایت منتشر می شود.

 

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *