PDA

View Full Version : آموزش: ساخت ساعت آنالوگ در سی شارپ به صورت User Control



Sirwan Afifi
چهارشنبه 16 آذر 1390, 18:05 عصر
با سلام خدمت دوستان، می خوام نحوه ساخت ساعت آنالوگ رو براتون توضیح بدم. در محیط Visual Studio.NET یه امکان به اسم User Control وجود داره که با استفاده از اون ما می تونیم کنترل های جدیدی بسازیم که تو برنامه های دیگه بتونیم از اون استفاده کنیم.اول مفهوم کنترل رو توضیح می دم : کنترل ها قطعاتی از رابط کاربری (User Interface) هستند که قابلیت استفاده مجدد را دارند.در دنیای ویندوز کنترل ها راه را برای استفاده متقابل کاربر از برنامه کاربردی نشان می دهند. مثلا ورود اطلاعات و یا ویرایش اطلاعات همگی توسط کنترل انجام می گیرد.


78840

هر نرم افزار کاربردی یک قسمت نامرئی دارد که کار واقعی را انجام می دهد،و یک قسمت قابل دیدن که رابط کاربری را فراهم می کند.یک نرم افزار کامل اصولا هر دو قسمت را شامل می شود. شکل روبرو نمونه ای از چند کنترل ویندوزی را نشان می دهد.


کنترل ها دو عملکرد اصلی دارند :
• گوش دادن به فرامین کاربر و ارسال آنها به برنامه(Application)
• نمایش نتایج قابل فهم برای کاربر


78841

حالا که با مفهوم کنترل آشنا شدید بریم سراغ نحوه ی ساخت یک کنترل سفارشی(Custom Control) یا همون ساعت آنالوگ.
اول یک پروژه از نوع ویندوز ایجاد کنید بعد توی پروژه تون Add New Items… رو کلیک کنید سپس از پنجره باز شده قسمت Windows Forms و سپس گزینه ی User Control و در نهایت یه اسم واسه کنترل سفارشیتون انتخاب کنید و کلید OK رو بزنید.

78843


خوب روی فرمتون راست کلید کنید و مطابق شکل روی گزینه ی View Code کلیک کنید.
78844

یک متد جدید به اسم drawclock ایجاد کنید لیست آرگومان های متد هم به این شکل باشه :
private void drawclock(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rec = new Rectangle(40, 40, 300, 300);
LinearGradientBrush linearbrush = new LinearGradientBrush(rec, Color.MediumPurple, Color.Silver, 225);


خط اول توی این متد یک نسخه محلی از شیء گرافیک رو برای فرم ایجاد می کنه.

خط دوم یک مستطیل ایجاد می کنه و با استفاده از خط سوم رنگ گرادیانت پس زمینه رو برای ساعت انتخاب می کنیم.
دستورات زیر مربوط به ظاهر ساعت هستند. در این خطوط ما اشیاء بالا رو با خطوط زیر به شکل بیضی رنگ می کنیم
g.FillEllipse(linearbrush, 20, 20, 200, 200);
linearbrush.LinearColors = new Color[] { Color.White, Color.White, };
g.FillEllipse(linearbrush, 30, 30, 180, 180);
linearbrush.LinearColors = new Color[] { Color.YellowGreen, Color.Green };
g.FillEllipse(linearbrush, 33, 33, 174, 174);

با استفاده از دستور زیر ما رنگ و نوع فونت اعداد روی ساعت رو مشخص می کنیم.
SolidBrush solidbrush = new SolidBrush(Color.White);
Font textFont = new Font("Arial Bold", 14F);
Font textFont1 = new Font("Arial Black", 8F);

نوشتن اعداد و متن به صورت گرافیکی روی ساعت رو با استفاده از دستورات زیر مشخص می کنیم. توجه کنید که مختصات اعداد روی ساعت به این شکل است.
g.DrawString("12", textFont, solidbrush, 109, 40);
g.DrawString("Sirwan Afifi", textFont1, Brushes.White, 83, 150);
g.DrawString("11", textFont, solidbrush, 75, 50);
g.DrawString("10", textFont, solidbrush, 47, 75);
g.DrawString("9", textFont, solidbrush, 43, 110);
g.DrawString("8", textFont, solidbrush, 52, 145);
g.DrawString("7", textFont, solidbrush, 75, 170);
g.DrawString("6", textFont, solidbrush, 113, 180);
g.DrawString("5", textFont, solidbrush, 150, 170);
g.DrawString("4", textFont, solidbrush, 173, 145);
g.DrawString("3", textFont, solidbrush, 182, 110);
g.DrawString("2", textFont, solidbrush, 173, 75);
g.DrawString("1", textFont, solidbrush, 150, 50);

برای حرکت یک شیء در محور مختصات 2بعدی X-Y از این دستور استفاده می کنیم:
g.TranslateTransform(120, 120, MatrixOrder.Append);
برای تعیین اینکه عقربه های ساعت چه کاری انجام بدن باید هرکدام از آنها را به صورت زیر تعریف کنیم :
int hour = DateTime.Now.Hour;
int min = DateTime.Now.Minute;
int sec = DateTime.Now.Second;

و حالا کشیدن عقربه های ساعت :
Pen hourPen = new Pen(Color.White, 2);
Pen minutePen = new Pen(Color.LightGray, 2);
Pen secondPen = new Pen(Color.Red, 1);


ایجاد زاویه چرخش عقربه ها :
double minuteAngle = 2.0 * Math.PI * (min + sec / 60.0) / 60.0;
double hourAngle = 2.0 * Math.PI * (hour + min / 60.0) / 12.0;


تعیین مرکز دایره :

Point centre = new Point(0, 0);

ترسیم عقربه های ساعت بطوریکه مرکزشون center باشه :

Point hourHand = new Point((int)(40 * Math.Sin(hourAngle)),
(int)(-40 * Math.Cos(hourAngle)));
g.DrawLine(hourPen, centre, hourHand);

// Draw Minute Hand
Point minHand = new Point((int)(70 * Math.Sin(minuteAngle)),
(int)(-70 * Math.Cos(minuteAngle)));
g.DrawLine(minutePen, centre, minHand);

// Draw Second Hand
Point secHand = new Point((int)(70 * Math.Sin(secondAngle)),
(int)(-70 * Math.Cos(secondAngle)));
g.DrawLine(secondPen, centre, secHand);

ترسیم مجدد اشیاء گرافیکی با استفاده از دستور :
Invalidate();
}

در نهایت در قسمت Constructor یا همون سازنده فرم بعد از InitializeComponent() این کد رو اضافه کنید :
public Clock()
{

InitializeComponent();
this.Paint += new PaintEventHandler(drawclock);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);

}


خوب ساخت ساعت عقربه ای تمام شد حالا برای استفاده مثل کنترل های عادی از اون می تونید تو فرمتون ازش استفاده کنید.

78845

MasoudAliAkbari
پنج شنبه 17 آذر 1390, 00:07 صبح
با تشکر از آموزشتون
می خواستم بدونم اگه بخواهین عقربه ها گرافیکی باشند چه کار میکنید. منظورم اینه که شکل عقربه ها یک خط صاف نباشد بلکه مانند بعضی ساعت های واقعی شکل زیبا تری داشته باشند

Sirwan Afifi
پنج شنبه 17 آذر 1390, 01:41 صبح
با تشکر از آموزشتون
می خواستم بدونم اگه بخواهین عقربه ها گرافیکی باشند چه کار میکنید. منظورم اینه که شکل عقربه ها یک خط صاف نباشد بلکه مانند بعضی ساعت های واقعی شکل زیبا تری داشته باشند
به خط 50 به بعد توجه کنید.متوجه می شوید به چه شکلیه کافیه hourHand رو به یه آرایه از Point تبدیل کنید و با استفاده از GraphicsPath اون رو به شکل AddPolygon رسم کنید.برای دو عقربه بعدی هم به دقیقا همین صورته.
public partial class AnClock : UserControl
{
public AnClock()
{
InitializeComponent();
InitializeComponent();
this.Paint += new PaintEventHandler(drawclock);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
private void drawclock(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rec = new Rectangle(40, 40, 300, 300);
LinearGradientBrush linearbrush = new LinearGradientBrush(rec, Color.MediumPurple, Color.Silver, 225);
g.FillEllipse(linearbrush, 20, 20, 200, 200);
linearbrush.LinearColors = new Color[] { Color.White, Color.White, };
g.FillEllipse(linearbrush, 30, 30, 180, 180);
linearbrush.LinearColors = new Color[] { Color.YellowGreen, Color.Green };
g.FillEllipse(linearbrush, 33, 33, 174, 174);
SolidBrush solidbrush = new SolidBrush(Color.White);
Font textFont = new Font("Arial Bold", 14F);
Font textFont1 = new Font("Arial Black", 8F);
g.DrawString("12", textFont, solidbrush, 109, 40);
g.DrawString("Sirwan Afifi", textFont1, Brushes.White, 83, 150);
g.DrawString("11", textFont, solidbrush, 75, 50);
g.DrawString("10", textFont, solidbrush, 47, 75);
g.DrawString("9", textFont, solidbrush, 43, 110);
g.DrawString("8", textFont, solidbrush, 52, 145);
g.DrawString("7", textFont, solidbrush, 75, 170);
g.DrawString("6", textFont, solidbrush, 113, 180);
g.DrawString("5", textFont, solidbrush, 150, 170);
g.DrawString("4", textFont, solidbrush, 173, 145);
g.DrawString("3", textFont, solidbrush, 182, 110);
g.DrawString("2", textFont, solidbrush, 173, 75);
g.DrawString("1", textFont, solidbrush, 150, 50);
g.TranslateTransform(120, 120, MatrixOrder.Append);
int hour = DateTime.Now.Hour;
int min = DateTime.Now.Minute;
int sec = DateTime.Now.Second;


double minuteAngle = 2.0 * Math.PI * (min + sec / 60.0) / 60.0;
double hourAngle = 2.0 * Math.PI * (hour + min / 60.0) / 12.0;
double secondAngle = 2.0 * Math.PI * sec / 60.0;

SolidBrush Min = new SolidBrush(Color.LightGray);

GraphicsPath gpHour = new GraphicsPath();
Point[] hourArrows ={new Point((int)(40 * Math.Sin(hourAngle)),(int)(-40 * Math.Cos(hourAngle))),
new Point((int)(-5*Math.Cos(hourAngle)),(int)(-5*Math.Sin(hourAngle))),
new Point((int)(5*Math.Cos(hourAngle)),(int)(5*Math.Si n(hourAngle))),
new Point((int)(40 * Math.Sin(hourAngle)),(int)(-40 * Math.Cos(hourAngle)))};

Point[] minuteArrows ={new Point((int)(40 * Math.Sin(minuteAngle)),(int)(-40 * Math.Cos(minuteAngle))),
new Point((int)(-5*Math.Cos(minuteAngle)),(int)(-5*Math.Sin(minuteAngle))),
new Point((int)(5*Math.Cos(minuteAngle)),(int)(5*Math. Sin(minuteAngle))),
new Point((int)(40 * Math.Sin(minuteAngle)),(int)(-40 * Math.Cos(minuteAngle)))};

Point[] secArrows ={new Point((int)(40 * Math.Sin(secondAngle)),(int)(-40 * Math.Cos(secondAngle))),
new Point((int)(-5*Math.Cos(secondAngle)),(int)(-5*Math.Sin(secondAngle))),
new Point((int)(5*Math.Cos(secondAngle)),(int)(5*Math. Sin(secondAngle))),
new Point((int)(40 * Math.Sin(secondAngle)),(int)(-40 * Math.Cos(secondAngle)))};

gpHour.AddPolygon(hourArrows);
g.FillPath(solidbrush, gpHour);

gpHour.AddPolygon(minuteArrows);
g.FillPath(Min, gpHour);

gpHour.AddPolygon(secArrows);
g.FillPath(solidbrush, gpHour);

g.FillEllipse(solidbrush, -5, -5, 10, 10);
Invalidate();
}

}

موفق باشید.

MasoudAliAkbari
شنبه 26 آذر 1390, 00:44 صبح
با سلام
منظور من اینه که چطور مثلا از یک عکس (image) عقربه استفاده کنیم به جای اینکه خودمون عقربه را رسم کنیم
و
میشه اون آخر یعنی 4 خطی که در متد سازنده است را توضیح دهید؟

this.Paint += new PaintEventHandler(drawclock);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);

ya30ien2
شنبه 26 آذر 1390, 23:19 عصر
خیلی آموزش جالبی بود ممنون

ya30ien2
شنبه 26 آذر 1390, 23:37 عصر
سوال :
اگه بخوام به مستطیل تبدیل کنم چه خطی از کد و چطوری تغییر بدم؟
منظورم فقط پشتزمینه هستش

Sirwan Afifi
یک شنبه 27 آذر 1390, 00:05 صبح
با سلام
منظور من اینه که چطور مثلا از یک عکس (image) عقربه استفاده کنیم به جای اینکه خودمون عقربه را رسم کنیم
و
میشه اون آخر یعنی 4 خطی که در متد سازنده است را توضیح دهید؟

this.Paint += new PaintEventHandler(drawclock);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);



خط اول یک EventHandler که تابع drawclock رو فراخوانی می کنه.
برای خطوط بعدی هم : برای اینکه تصویر پرش نداشته باشه این سه تا فلاگ رو باید True کنیم.

MasoudAliAkbari
یک شنبه 27 آذر 1390, 15:44 عصر
خط اول یک EventHandler که تابع drawclock رو فراخوانی می کنه.
برای خطوط بعدی هم : برای اینکه تصویر پرش نداشته باشه این سه تا فلاگ رو باید True کنیم.
میشه لطف کنید سوال اول را هم جواب بدید:
سوال:
منظور من اینه که چطور مثلا از یک عکس (image) عقربه استفاده کنیم به جای اینکه خودمون عقربه را رسم کنیم

cancer_448
پنج شنبه 09 آذر 1391, 18:23 عصر
LinearGradientBrush linearbrush = new LinearGradientBrush(rec, Color.MediumPurple, Color.Silver, 225

چرا تو این خط Lineargradientbrush خطا میده؟؟؟:گریه:

Sirwan Afifi
پنج شنبه 09 آذر 1391, 20:02 عصر
LinearGradientBrush linearbrush = new LinearGradientBrush(rec, Color.MediumPurple, Color.Silver, 225

چرا تو این خط Lineargradientbrush خطا میده؟؟؟:گریه:

این Namespace رو به پروژه تون اضافه کنید :using System.Drawing.Drawing2D;

cancer_448
جمعه 10 آذر 1391, 13:23 عصر
Point secHand = new Point((int)(70 * Math.Sin(secondAngle)),(int)(-70 * Math.Cos(secondAngle

وقتی secondangle رو تعریف نکردیم تو این خط error میده که

Sirwan Afifi
جمعه 10 آذر 1391, 13:40 عصر
Point secHand = new Point((int)(70 * Math.Sin(secondAngle)),(int)(-70 * Math.Cos(secondAngle

وقتی secondangle رو تعریف نکردیم تو این خط error میده که

چه errorی متن خطا رو قرار بدید.

cancer_448
جمعه 10 آذر 1391, 13:53 عصر
the name 'secondangle' does not exist in the current context

mreza80
چهارشنبه 15 آذر 1391, 16:48 عصر
آقا چرا به این secondAngle خطا میده

mreza80
شنبه 18 آذر 1391, 09:53 صبح
آقا مشکلم حل شد این تعریف دوست عزیزمون جا انداخته بود
double secondAngle = 2.0 * Math.PI * sec / 60.0;

mgupload
یک شنبه 08 بهمن 1391, 11:25 صبح
خیلی ممنون دو سوال دارم :

<< اگه بخواهیم محل قرار گرفتن ساعت را در فورم تغییر دهیم ( مثلا به اندازه 100 واحد جلو و 200 واحد پایین ) باید مقادیر آن را چگونه تغییر دهیم ؟ >>

<< اگر بخواهیم سایز ساعت را تغییر دهیم ( مثلا نصف کنیم ) باید مقادیر را چگونه تغییر دهیم ؟ >>

با تشکر