في نافذة الطباعة اختر «حفظ كملف PDF» كوجهة.
نظم التشغيل 1، الدرس العملي 4
ارسم على النموذج باستخدام GDI+، ثم اجعل الصورة تتحرك باستخدام مؤقت (Timer).
Math.Cos وMath.Sinالجزء 1
كائن Graphics، وقلم، وفرشاة، وإحداثيات بالبكسل
System.Drawing). وكل دوال الرسم، مثل DrawLine وFillEllipse وDrawString، تنتمي إليه.| طريقة الحصول عليه | الشيفرة | استخدمها عندما |
|---|---|---|
| الحدث Paint | Graphics g = e.Graphics; | ترسم صورة النموذج (الطريقة المعتادة) |
CreateGraphics | Graphics g = this.CreateGraphics(); | ترسم على نموذج موجود بالفعل |
| من صورة | Graphics.FromImage(myBitmap) | تعدل صورة موجودة |
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
// draw here
}(0, 0) هي الركن العلوي الأيسر من منطقة العميل (client area)x إلى اليمين، ويزيد y إلى الأسفل، لا إلى الأعلى كما في درس الهندسةDrawLine(myPen, 2, 2, 4, 1) يكاد لا يرىpublic Form1()
{
InitializeComponent();
this.Width = 500;
this.Height = 500;
}Pen myPen = new Pen(Color.Black); // width 1
Pen bluePen = new Pen(Color.Blue, 3); // width 3
SolidBrush myBrush = new SolidBrush(Color.Red);
SolidBrush orange = new SolidBrush(
Color.FromArgb(255, 255, 140, 0)); // alpha, red, green, blue| الكائن | يلون | تستخدمه |
|---|---|---|
| قلم (Pen) | الحد الخارجي (outline) | DrawLine, DrawRectangle, DrawEllipse, DrawArc, DrawPolygon |
| فرشاة (Brush) | الداخل | FillRectangle, FillEllipse, FillPolygon, DrawString |
داخل Form1_Paint. توقع النقطتين اللتين يصل بينهما الخط، والأركان الأربعة للمستطيل.
g.DrawLine(myPen, 20, 20, 400, 420); // x1, y1, x2, y2
g.DrawRectangle(myPen, 100, 100, 200, 150); // x, y, width, height(20, 20) إلى (400, 420)(100, 100) و(300, 100)(100, 250) و(300, 250)(x, y): الركن العلوي الأيسر؛ وw وh: العرض والارتفاع؛ و(x_2, y_2): الركن السفلي الأيمنتوقع: ما هذا الشكل، وأين مركزه، وهل يلمس المستطيل من الشريحة السابقة؟
g.DrawEllipse(myPen, 300, 200, 50, 50); // the bounding rectangle: x, y, width, height25(300 + 25, 200 + 25) = (325, 225)(300, 225): تقع على الضلع الأيمن للمستطيل (x = 300، وy من 100 إلى 250). فهما يتلامسان.g.DrawArc(myPen, x, y, width, height,
startAngle, sweepAngle);DrawEllipsestartAngle: الدرجات مقيسة من المحور x؛ و0 هي النقطة اليمنىsweepAngle: مقدار ما يرسم، في اتجاه عقارب الساعة (لأن y يزيد إلى الأسفل)أربعة مربعات مقاس كل منها 100 x 100، وعرض القلم 3. توقع جزء الدائرة الذي يرسمه كل استدعاء.
g.DrawArc(arcPen, x, 30, 100, 100, 0, 90);
g.DrawArc(arcPen, x, 30, 100, 100, 0, 180);
g.DrawArc(arcPen, x, 30, 100, 100, 0, -90);
g.DrawArc(arcPen, x, 30, 100, 100, 90, 180);
الاستدعاءات الأربعة السابقة، مع نص، وقلم أسود، وفرشاة حمراء، ونموذج 500 x 500. ارسمها على الورق، ثم قارن.
g.DrawArc(myPen, 400, 100, 50, 50, 0, 90);
g.DrawString("Hello World", new Font("Arial", 16), myBrush, 150, 400);
(300, 225)(150, 400) هي الركن العلوي الأيسر للنصقلم أزرق عرضه 3، وفرشاة برتقالية. العمود 1 يرسم، والعمود 2 يلون، والعمود 3 يلون ثم يرسم.
g.DrawRectangle(bluePen, 20, 20, 120, 80);
g.FillRectangle(orangeBrush, 170, 20, 120, 80);
g.FillRectangle(orangeBrush, 320, 20, 120, 80);
g.DrawRectangle(bluePen, 320, 20, 120, 80);
// the same three columns for Ellipse and for Polygon (a Point[] triangle)
الجزء 2
Paint مقابل CreateGraphics
Invalidate(): "أعد رسمي عندما تستطيع"Refresh(): امسح المنطقة وأعد رسمها الآنيلون Paint مستطيلا أزرق. ويرسم كل من Load والزر دائرة باستخدام CreateGraphics. توقع شكل النافذة عند فتحها.
private void Form1_Load(object sender, EventArgs e)
{
Graphics formGraphics = this.CreateGraphics();
formGraphics.FillEllipse(greenBrush, 200, 70, 100, 100);
formGraphics.Dispose();
}
private void drawButton_Click(object sender, EventArgs e)
{
Graphics formGraphics = this.CreateGraphics();
formGraphics.FillEllipse(redBrush, 330, 70, 100, 100);
formGraphics.Dispose();
}
انقر Draw circle، ثم انقر Refresh (this.Refresh();).


| مكان الرسم | بعد إعادة الرسم التالية |
|---|---|
Paint باستخدام e.Graphics | يرسم من جديد: يبقى |
نقرة باستخدام CreateGraphics | يمحى: لا أحد يرسمه من جديد |
| Load | لا يرى أبدا |
الجزء 3
لوحتان، وأربعة مربعات نص، وقليل من حساب المثلثات

controlPanel: Dock = Top، وتحمل أربعة مربعات نص والزر Gocanvas: Dock = Fill، بيضاء؛ ونعالج الحدث Paint الخاص بهاcanvas.Refresh(): يمسحها ويطلق Paint| الرمز | المعنى |
|---|---|
(x_1, y_1), (x_2, y_2) | بداية الخط ونهايته |
L | طوله (بالبكسل) |
θ | زاويته (بالدرجات) |
α, d | المربعان Angle وIncrement |
int startX = canvas.Width / 2, startY = canvas.Height / 2; // the centre
int myAngle = 0; // first line points right
for (int i = 0; i < lines; i++)
{
int endX = (int)(startX + Math.Cos(myAngle * Math.PI / 180) * myLength);
int endY = (int)(startY + Math.Sin(myAngle * Math.PI / 180) * myLength);
Point[] points = { new Point(startX, startY), new Point(endX, endY) };
g.DrawLines(myPen, points);
startX = endX; startY = endY; // the next line starts here
myAngle = myAngle + turn; // the Angle box
myLength = myLength + step; // the Increment box
}لوحة الرسم 560 x 400، فمركزها (280, 200). توقع نقاط النهاية الأربع.
| الخط | θ | من | إلى |
|---|---|---|---|
| 1 | 0 | (280, 200) | (380, 200) |
| 2 | 90 | (380, 200) | (380, 300) |
| 3 | 180 | (380, 300) | (280, 300) |
| 4 | 270 | (280, 300) | (280, 200) |
يمتد الخط 1 من (280, 200) إلى (285, 200). توقع نهاية الخط 2: θ = 74، L = 6.

الجزء 4
غير عددا، واطلب إعادة الرسم، وكرر
| العضو | المعنى |
|---|---|
Interval | الزمن بالملي ثانية بين حدثي Tick متتاليين |
Enabled | true: المؤقت يعمل |
Tick | الحدث؛ انقر المؤقت نقرا مزدوجا لإنشاء معالجه |
int x = 10;
int y = 70;
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(redBrush, x, y, 50, 50);
e.Graphics.DrawString("x = " + x, this.Font, Brushes.Black, 10, 10);
}
private void timer1_Tick(object sender, EventArgs e) // Interval = 50
{
x += 5;
this.Invalidate();
}x بمقدار 5 بكسلاتInvalidate() من ويندوز حدث Paint جديداx الجديدةيبدأ x من 10. توقع قيمة x بعد 20 نبضة (tick)، ثم انظر إلى ثلاث لقطات شاشة للنموذج أثناء تشغيله.

صار معالج Tick الآن x += 5; فقط. توقع ما تعرضه النافذة.

tick 10 at 642 ms: x = 60
tick 30 at 1909 ms: x = 160
tick 50 at 3177 ms: x = 260v: السرعة (بكسل/ث)، وs: الخطوة في كل نبضة (بكسل)، وT: Interval (ms)| Interval | الفاصل المقيس | عدد النبضات المقيسة |
|---|---|---|
| 10 | 16.4 ms | 250 |
| 25 | 31.7 ms | 180 |
| 50 | 62.6 ms | 40 |
| 100 | 110.8 ms | 28 |
الجزء 5
الحدث Tick نفسه، مع أفكار أخرى قليلة
int L1x = 5; // fields: outside every method,
int L1y = 5; // so they keep their value between ticks
private void timer1_Tick(object sender, EventArgs e)
{
label1.Left -= L1x;
label1.Top -= L1y;
if (label1.Left + label1.Width > ClientSize.Width || label1.Left < 0)
L1x = -L1x; // bounce off the left or right border
if (label1.Top + label1.Height > ClientSize.Height || label1.Top < 0)
L1y = -L1y; // bounce off the top or bottom border
}L1x وL1y حقلان: ولو عرفا داخل Tick لعادت قيمتهما إلى 5 في كل نبضةLeft وTop: بلا شيفرة في Paint|| تعني أو: تجاوز الحافة اليمنى أو الحافة اليسرىlabelA: Left = 230، وWidth = 50، والسرعة +10. وClientSize.Width = 300. توقع Left والسرعة في النبضات من 1 إلى 5.
| النبضة | Left بعد الحركة | هل Left + Width > 300؟ | السرعة بعد النبضة |
|---|---|---|---|
| 1 | 240 | 290: لا | 10 |
| 2 | 250 | 300: لا (ليس أكبر) | 10 |
| 3 | 260 | 310: نعم | -10 |
| 4 | 250 | 300: لا | -10 |
| 5 | 240 | 290: لا | -10 |

L1x وL1y للتسمية label1، وL2x وL2y للتسمية label2-=) وتجمعها label2 (+=): فتبدآن في اتجاهين متعاكسينenum Position { Left, Right, Up, Down }
Position objectPosition = Position.Right;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left) objectPosition = Position.Left;
else if (e.KeyCode == Keys.Right) objectPosition = Position.Right;
else if (e.KeyCode == Keys.Up) objectPosition = Position.Up;
else if (e.KeyCode == Keys.Down) objectPosition = Position.Down;
}// in timer1_Tick
if (objectPosition == Position.Right) x += 5;
else if (objectPosition == Position.Left) x -= 5;
else if (objectPosition == Position.Up) y -= 5;
else if (objectPosition == Position.Down) y += 5;
this.Invalidate();Bitmap picture = new Bitmap("mushroom.png"); // a field: load once
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(picture, x, y, 64, 64);
}.exe
private string[] frames = { "frames/run0.png", /* ... */ "frames/run7.png" };
private int currentFrame = 0;
private void animationTimer_Tick(object sender, EventArgs e)
{
currentFrame = (currentFrame + 1) % frames.Length; // 0, 1, ..., 7, 0, ...
frameImage.Image = images[currentFrame];
}% (باقي القسمة) العدد 8 إلى 0، بلا حاجة إلى ifعنصر TrackBar فيه Minimum = 50 وMaximum = 100. ومعالج حدثه ValueChanged ينفذ animationTimer.Interval = speedBar.Value;
62.8 ms عند 50، و110.8 ms عند 100يكبر كلا الزرين لوحة زرقاء حتى 300 x 200، بكسلا واحدا في كل مرة. توقع كيف يبدو كل منهما.
private void tmrMain_Tick(object sender, EventArgs e) // Interval = 10
{
if (pnlMain.Width < targetWidth) pnlMain.Width++;
if (pnlMain.Height < targetHeight) pnlMain.Height++;
}private void btnAnimation2_Click(object sender, EventArgs e)
{
pnlMain.Height = targetHeight;
while (pnlMain.Width < targetWidth)
pnlMain.Width++;
}
نحو 7 دقائق
Pen myPen = new Pen(Color.Black, 2);
g.DrawRectangle(myPen, 60, 120, 200, 140); // walls
Point[] roof = { new Point(60, 120),
new Point(160, 40), new Point(260, 120) };
g.DrawPolygon(myPen, roof); // roof
g.FillRectangle(doorBrush, 140, 190, 40, 70); // door
g.FillEllipse(windowBrush, 90, 150, 30, 30); // window
g.DrawString("Home", new Font("Arial", 14), Brushes.Black, 135, 8);(60, 120) و(260, 120) و(60, 260) و(260, 260)؛ وقمة السقف (160, 40)190 + 70 = 260 = أسفل الجدار: نعم، فهو يقف عليه(105, 165)، ونصف القطر 15
نحو 7 دقائق
labelB: Left = 20، وWidth = 40، والسرعة -8. وClientSize.Width = 300. الشرط if نفسه الذي في label1.
Left والسرعة بعد كل نبضة من النبضات 1 إلى 5|| يكون صحيحا؟Left للتسمية؟| النبضة | Left | السرعة بعد النبضة |
|---|---|---|
| 1 | 12 | -8 |
| 2 | 4 | -8 |
| 3 | -4 | 8 |
| 4 | 4 | 8 |
| 5 | 12 | 8 |
نحو 6 دقائق
تطبيق أنماط الخطوط: 5 خطوط، وAngle 144، وLength 150، وIncrement 0.
(280, 200))(280, 200) تماما؟(280, 200) إلى (430, 200)(430, 200) إلى (308, 288)5 * 144 = 720، أي دورتان كاملتان(278, 198): فالتحويل (int) يفقد قليلا في كل خط
نحو 10 دقائق
L3x = 3 وL3y = 7، واجعل label3 تتحرك باستخدام += وترتدLeft = 150 وTop = 160، وحجمها 92 x 32، وClientSize هو 420 x 300label3.Left += L3x;
label3.Top += L3y;
if (label3.Left + label3.Width > ClientSize.Width || label3.Left < 0)
{
L3x = -L3x;
}
if (label3.Top + label3.Height > ClientSize.Height || label3.Top < 0)
{
L3y = -L3y;
}Top = 272، و272 + 32 = 304 > 300150 + 3k + 92 > 420 أن يكون k > 59.3، أي بعد ذلك بكثيرtick 16: label3 (198, 272) L3y -7e.Graphics: فويندوز يطلب الصورة مرة بعد مرة(0, 0) هي الركن العلوي الأيسر، وy يزيد إلى الأسفل؛ وتحدد الأشكال بركن وعرض وارتفاعInvalidate()Mahmoud Abas|الرسوميات والحركة بلغة C#