PDA

View Full Version : مبتدی: رسم خط



مجتبی جوادی
پنج شنبه 21 آذر 1398, 17:54 عصر
دوستان عزیز درود
من یک پیکچرباکس دارم و میخوام چند خط درون آن ترسیم کنم. من میخوام با اولین کلیک روی صفحه، خط رابط بین کرسر و نقطه کلیک کرده را قبل از کلیک نقطه دوم ببینم. یعنی با حرکت موس جهت خط را بتوان دید.
امیدوارم توانسته باشم منظورم را برسانم.
با سپاس از شما
بدرود

the king
پنج شنبه 21 آذر 1398, 19:06 عصر
دوستان عزیز درود
من یک پیکچرباکس دارم و میخوام چند خط درون آن ترسیم کنم. من میخوام با اولین کلیک روی صفحه، خط رابط بین کرسر و نقطه کلیک کرده را قبل از کلیک نقطه دوم ببینم. یعنی با حرکت موس جهت خط را بتوان دید.
امیدوارم توانسته باشم منظورم را برسانم.
با سپاس از شما
بدرود



public partial class Form1 : Form
{
private BufferedGraphics _buffer;
private Point _pos = new Point(-1, -1);

public Form1()
{
InitializeComponent();
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
_pos = e.Location;
pictureBox1.Invalidate();
}

private void Form1_Load(object sender, EventArgs e)
{
using (var g = pictureBox1.CreateGraphics())
{
_buffer = BufferedGraphicsManager.Current.Allocate(g, new Rectangle(Point.Empty, pictureBox1.ClientSize));
_buffer.Graphics.Clear(pictureBox1.BackColor);
_buffer.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
}
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (_buffer == null)
{
return;
}
_buffer.Render(e.Graphics);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (_pos != new Point(-1, -1))
{
var pos = pictureBox1.PointToClient(Cursor.Position);
e.Graphics.DrawLine(Pens.Blue, _pos, pos);
e.Graphics.FillEllipse(Brushes.Yellow, new Rectangle(_pos.X - 2, _pos.Y - 2, 4, 4));
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(_pos.X - 2, _pos.Y - 2, 4, 4));
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(pos.X - 2, pos.Y - 2, 4, 4));
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(pos.X - 2, pos.Y - 2, 4, 4));
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
pictureBox1.Invalidate();
}
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
var pos = pictureBox1.PointToClient(Cursor.Position);
_buffer.Graphics.DrawLine(Pens.Blue, _pos, pos);
_pos = new Point(-1, -1);
pictureBox1.Invalidate();
}
}
}

مجتبی جوادی
پنج شنبه 21 آذر 1398, 23:25 عصر
دوست عزیز سپاسگزارم
ولی من نمیخوام موس را نگهدارم و دراگ کنم . من میخوام از کلیک دوم به بعد با هر کلیک یک خط ترسیم شود. کلیک اول نقطه اول را انتخاب می کند و کلیکهای بعدی ترسیم خط.

با سپاس فراوان

the king
پنج شنبه 21 آذر 1398, 23:54 عصر
دوست عزیز سپاسگزارم
ولی من نمیخوام موس را نگهدارم و دراگ کنم . من میخوام از کلیک دوم به بعد با هر کلیک یک خط ترسیم شود. کلیک اول نقطه اول را انتخاب می کند و کلیکهای بعدی ترسیم خط.

با سپاس فراوان


public partial class Form1 : Form
{
private List<Point> _points = new List<Point>();

public Form1()
{
InitializeComponent();
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
_points.Add(e.Location);
pictureBox1.Invalidate();
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (_points.Count == 1)
{
e.Graphics.FillEllipse(Brushes.Red, new Rectangle(_points[0].X - 2, _points[0].Y - 2, 4, 4));
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(_points[0].X - 2, _points[0].Y - 2, 4, 4));
}
else if (_points.Count > 1)
{
e.Graphics.DrawLines(Pens.Blue, _points.ToArray());
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) && (_points.Count > 0))
{
_points[_points.Count - 1] = e.Location;
pictureBox1.Invalidate();
}
}
}

مجتبی جوادی
جمعه 22 آذر 1398, 00:21 صبح
سپاس دوباره دوست گرامی
ولی باز هم آن چیزی که من میخواهم نشد. بعد ار اولین کلیک قبل از اینکه کلیک های بعدی را انجام دهیم، با حرکت دادن کرسر خط بین نقطه کیک شده و موقعیت کرسر همواره نمایش داده شود مثل اتوکد.

با سپاس

the king
جمعه 22 آذر 1398, 01:17 صبح
سپاس دوباره دوست گرامی
ولی باز هم آن چیزی که من میخواهم نشد. بعد ار اولین کلیک قبل از اینکه کلیک های بعدی را انجام دهیم، با حرکت دادن کرسر خط بین نقطه کیک شده و موقعیت کرسر همواره نمایش داده شود مثل اتوکد.

با سپاس


public partial class Form1 : Form
{
private List<Point> _points = new List<Point>();
private bool _down;

public Form1()
{
InitializeComponent();
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
_down = true;
_points.Add(e.Location);
pictureBox1.Invalidate();
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (_points.Count > 1)
{
e.Graphics.DrawLines(Pens.Blue, _points.ToArray());
}
if (_down || (_points.Count == 0))
{
return;
}
using (var pen = new Pen(Color.FromArgb(128, Color.Black), 1f))
{
var endCap = new System.Drawing.Drawing2D.AdjustableArrowCap(5, 5);
pen.CustomEndCap = endCap;
e.Graphics.DrawLine(pen, _points[_points.Count - 1], pictureBox1.PointToClient(Cursor.Position));
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) && (_points.Count > 0))
{
_points[_points.Count - 1] = e.Location;
}
pictureBox1.Invalidate();
}

private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Cursor = Cursors.Cross;
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_down = false;
pictureBox1.Invalidate();
}
}

مجتبی جوادی
جمعه 22 آذر 1398, 15:24 عصر
public partial class Form1 : Form
{
private List<Point> _points = new List<Point>();
private bool _down;

public Form1()
{
InitializeComponent();
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
_down = true;
_points.Add(e.Location);
pictureBox1.Invalidate();
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (_points.Count > 1)
{
e.Graphics.DrawLines(Pens.Blue, _points.ToArray());
}
if (_down || (_points.Count == 0))
{
return;
}
using (var pen = new Pen(Color.FromArgb(128, Color.Black), 1f))
{
var endCap = new System.Drawing.Drawing2D.AdjustableArrowCap(5, 5);
pen.CustomEndCap = endCap;
e.Graphics.DrawLine(pen, _points[_points.Count - 1], pictureBox1.PointToClient(Cursor.Position));
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) && (_points.Count > 0))
{
_points[_points.Count - 1] = e.Location;
}
pictureBox1.Invalidate();
}

private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Cursor = Cursors.Cross;
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_down = false;
pictureBox1.Invalidate();
}
}


درود بر دوست گرامی
خیلی خیلی سپاسگزار مشکلم حل شد
پیروز باشید

مجتبی جوادی
سه شنبه 09 اردیبهشت 1399, 23:19 عصر
درود بر شما (the king) دوست گرامی
باز هم از بابت کد بالا سپاسگزارم و یک زحمت دیگه در رابطه با همین کد داشتم
من با یک ماتریس نقطه صفر را از گوشه سمت چپ بالا به گوشه سمت چپ پایین انتقال دادم تا نقاط بصورت کارتزین باشند. ولی متاسفانه خط امتداد حرکت کرسر , آخرین کلیک برعکس شده و نمیدونم باید چکار بکنم. اگر امکان داره باز هم به شما زحمت بدم. یک سوال دیگه اینکه آیا برای دایره و کمان هم میشه همین کار را کرد بطوریه که قبل از کلید یک شمایی از دایره یا کمان به همراه خط رابط بین آخرین کلیک و کرسر را هم دید؟
خیلی سپاسگزارم
بدرود

the king
چهارشنبه 10 اردیبهشت 1399, 00:10 صبح
درود بر شما (the king) دوست گرامی
باز هم از بابت کد بالا سپاسگزارم و یک زحمت دیگه در رابطه با همین کد داشتم
من با یک ماتریس نقطه صفر را از گوشه سمت چپ بالا به گوشه سمت چپ پایین انتقال دادم تا نقاط بصورت کارتزین باشند. ولی متاسفانه خط امتداد حرکت کرسر , آخرین کلیک برعکس شده و نمیدونم باید چکار بکنم. اگر امکان داره باز هم به شما زحمت بدم.
تبدیل سیستم مختصات گرافیک به کارتزین که معمولا دو تا متد میخواد، اولی برای انتقال مبدا مختصات به پایین کادر و دومی برای برعکس کردن جهت محور y

e.Graphics. TranslateTransform(0, pictureBox1.ClientSize.Height - 1);
e.Graphics.ScaleTransform(1, -1);

و هر نقطه روی کادر PictureBox رو هم میشه با یک متد به این مختصات کارتزین تبدیل کرد :

private Point PointToCartesian(Point p)
{
return new Point(p.X, pictureBox1.ClientSize.Height - p.Y);
}

پس تغییرات میشه یکی اضافه کردن دو تا متد برای تبدیل مختصات گرافیک و دومی برای تبدیل همه e.Location ها و PointToClient ها به کارتزین :

public partial class Form1 : Form
{
private List<Point> _points = new List<Point>();
private bool _down;

public Form1()
{
InitializeComponent();
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
_down = true;
_points.Add(PointToCartesian( e.Location));
pictureBox1.Invalidate();
}

private Point PointToCartesian(Point p)
{
return new Point(p.X, pictureBox1.ClientSize.Height - p.Y);
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.TranslateTransform(0, pictureBox1.ClientSize.Height - 1);
e.Graphics.ScaleTransform(1, -1);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D. SmoothingMode.AntiAlias;
if (_points.Count > 1)
{
e.Graphics.DrawLines(Pens.Blue, _points.ToArray());
}
if (_down || (_points.Count == 0))
{
return;
}
using (var pen = new Pen(Color.FromArgb (128, Color.Black), 1f))
{
var endCap = new System.Drawing. Drawing2D.AdjustableArrowCap (5, 5);
pen.CustomEndCap = endCap;
e.Graphics.DrawLine(pen, _points[_points.Count - 1], PointToCartesian( pictureBox1.PointToClient (Cursor.Position)));
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) && (_points.Count > 0))
{
_points[_points.Count - 1] = PointToCartesian(e.Location);
}
pictureBox1.Invalidate();
}

private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Cursor = Cursors.Cross;
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_down = false;
pictureBox1.Invalidate();
}
}




یک سوال دیگه اینکه آیا برای دایره و کمان هم میشه همین کار را کرد بطوریه که قبل از کلید یک شمایی از دایره یا کمان به همراه خط رابط بین آخرین کلیک و کرسر را هم دید؟
خیلی سپاسگزارم
بدرود
بله، همون روال ئه، صرفا محاسبات زاویه و شعاع رو انجام می دهید و بجای DrawLine از DrawArc و DrawEllipse استفاده می کنید.

مجتبی جوادی
چهارشنبه 10 اردیبهشت 1399, 21:12 عصر
درود دوباره بر شما دوست گرامی
خیلی خیلی از شما سپاسگزارم
دوست گرامی از چه منبعی میتونم استفاده کنم تا من هم مثل شما در گرافیک ماهر بشم؟

the king
چهارشنبه 10 اردیبهشت 1399, 22:54 عصر
درود دوباره بر شما دوست گرامی
خیلی خیلی از شما سپاسگزارم
دوست گرامی از چه منبعی میتونم استفاده کنم تا من هم مثل شما در گرافیک ماهر بشم؟
احتمالا خیلی از دوستان در اینجور موارد تجربه بیشتری از من دارند که به سوال تون پاسخ بدهند.
هر کتاب و منبعی که در مورد دو تا موضوع باشه کمک تون می کنه.
اول آموزش ترسیم با +GDI و دوم هندسه و ریاضیات. یاد گرفتن کار با توابع +GDI راحته چون تعدادشون خیلی زیاد نیست.
هر کتاب و ویدئو و مقاله ای که عنوانش شبیه GDI+ Programming in C#‎ باشه یا به توابع مثلثاتی و مشتقگیری و فرمول های ریاضی مرتبط بپردازه کمک می کنه.
متاسفانه منابع فارسی یا ترجمه شده بد و گنگ ای هستند یا جامع نیستند و یا از حد مثال های خیلی ابتدایی فراتر نمیرن.

مجتبی جوادی
چهارشنبه 10 اردیبهشت 1399, 23:46 عصر
از بابت ریاضی من مشکلی ندارم و چند کتاب بصورت پی دی اف به زبان انگلیسی پیدا کردم ولی گفتم شاید منبع فارسی خوبی داشته باشیم که خواندنش برام راحت تر باشه
بابت کدی که زحمتشو کشیدید اگه یونیت را روی میلیمتر بگذاریم چطور میشه؟
با سپاس فراوان

the king
پنج شنبه 11 اردیبهشت 1399, 00:39 صبح
بابت کدی که زحمتشو کشیدید اگه یونیت را روی میلیمتر بگذاریم چطور میشه؟
با سپاس فراوان
اتفاق خاصی نمی افته، فقط مواردی مثل ضخامت خط در Pen که یک پیکسلی بود یک میلی متری میشه.

public partial class Form1 : Form
{
private List<PointF> _points = new List<PointF>();
private bool _down;
private float _dpi;

public Form1()
{
InitializeComponent();
}

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
_down = true;
_points.Add(PointToCartesian (e.Location));
pictureBox1.Invalidate();
}

private float GetDisplayDpi()
{
if (_dpi < 1)
{
using (var g = CreateGraphics())
{
_dpi = g.DpiX;
}
}
return _dpi;
}

private PointF PointToCartesian(Point p)
{
var factor = GetDisplayDpi() / 25.4f;
return new PointF(p.X / factor, (pictureBox1.ClientSize. Height - p.Y) / factor);
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.PageUnit = GraphicsUnit.Millimeter;
e.Graphics.TranslateTransform(0, e.Graphics.VisibleClipBounds.Height - 1);
e.Graphics.ScaleTransform(1, -1);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D. SmoothingMode.AntiAlias;
if (_points.Count > 1)
{
e.Graphics.DrawLines( Pens.Blue, _points.ToArray());
}
if (_down || (_points.Count == 0))
{
return;
}
using (var pen = new Pen(Color.FromArgb (128, Color.Black), 1f))
{
var endCap = new System.Drawing.Drawing2D .AdjustableArrowCap(5, 5);
pen.CustomEndCap = endCap;

e.Graphics.DrawLine (pen, _points[_points.Count - 1], PointToCartesian( pictureBox1.PointToClient (Cursor.Position)));
}
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button == MouseButtons.Left) && (_points.Count > 0))
{
_points[_points.Count - 1] = PointToCartesian(e.Location);
}
pictureBox1.Invalidate();
}

private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.Cursor = Cursors.Cross;
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
_down = false;
pictureBox1.Invalidate();
}
}

مجتبی جوادی
پنج شنبه 11 اردیبهشت 1399, 21:54 عصر
دوست گرامی خیلی سپاسگزارم

مجتبی جوادی
جمعه 12 اردیبهشت 1399, 02:48 صبح
درود دوباره دوست گرامی
من این کد را روی Rectangle اجرای کردم و زمانی طول و عرض مثبت هستند چهار ضلعی نمایش داده میشه

the king
جمعه 12 اردیبهشت 1399, 05:56 صبح
درود دوباره دوست گرامی
من این کد را روی Rectangle اجرای کردم و زمانی طول و عرض مثبت هستند چهار ضلعی نمایش داده میشه
متوجه مشکل یا هدف تون نشدم، اما اگر مقصود تون این باشه که مستطیل رو بر اساس موقعیت دو نقطه A و B تعریف کنید و بعد با DrawRectangle رسم اش کنید نکته ای هست.
151659
در Rectangle می توانید موقعیت شروع رو B در نظر بگیرید و با طول و عرض منفی A رو توصیف کنید، Rectangle ثبت اش می کنه.
ولی DrawRectangle برای تعریف مستطیل تعریف خودش رو داره، مستطیل با طول یا عرض منفی رو رسم نمی کنه.
برای DrawRectangle مستطیل همواره از یک نقطه شروع A و طول و عرض مثبت تشکیل شده و طول و عرض نمیتونه منفی باشه.
اگر می خواهید همچین Rectangle ای رسم بشه، باید قبل از رسم یک Rectangle بسازید که موقعیت شروع اش A باشه، نه B و بجای Rectangle اصلی اون رو رسم کنید.

مجتبی جوادی
جمعه 12 اردیبهشت 1399, 22:16 عصر
درود بر شما دوست گرامی
خدمت شما عرض کنم من میخوام بعد از اینکه یک نقطه را به عنوان نقطه شروع Rectangle کلیک میکنم، اگر اشاره گر موس را به هر جهتی که حرکت میدم مثل ترسیم خط امتداد فرضی Rectangle را قبل از کلیک دوم ببینم
با سپاس فراوان

مجتبی جوادی
جمعه 12 اردیبهشت 1399, 22:18 عصر
گفتم شاید با چک کردن موقعیت موس نسبت به نقطه اول و تعیین مثت یا منفی بودن عرض و ارتفاع بتونم یک دوران به ترسیم بدم ولی موفق نشدم و یک جای کار ایراد داره

مجتبی جوادی
جمعه 12 اردیبهشت 1399, 22:34 عصر
با عوض کردن نقطه کلیک شده اول و مکان کرسر مشکل حل شد

مجتبی جوادی
جمعه 12 اردیبهشت 1399, 23:10 عصر
به شکل زیر مشکل را حل کردم. شاید شما راه حل بهتری داشته باشید


float w = PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).X - _points[_points.Count - 1].X;
float h = PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).Y - _points[_points.Count - 1].Y;

if ((w < 0) && (h < 0))
e.Graphics.DrawRectangle(pen, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).X, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).Y, Math.Abs(w), Math.Abs(h));
else if ((w > 0) && (h < 0))
e.Graphics.DrawRectangle(pen, (float)_points[_points.Count - 1].X, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).Y, Math.Abs(w), Math.Abs(h));
else if ((w < 0) && (h > 0))
e.Graphics.DrawRectangle(pen, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).X, (float)_points[_points.Count - 1].Y, Math.Abs(w), Math.Abs(h));
else
e.Graphics.DrawRectangle(pen, (float)_points[_points.Count - 1].X, (float)_points[_points.Count - 1].Y, w, h);

the king
شنبه 13 اردیبهشت 1399, 00:17 صبح
به شکل زیر مشکل را حل کردم. شاید شما راه حل بهتری داشته باشید


float w = PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).X - _points[_points.Count - 1].X;
float h = PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).Y - _points[_points.Count - 1].Y;

if ((w < 0) && (h < 0))
e.Graphics.DrawRectangle(pen, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).X, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).Y, Math.Abs(w), Math.Abs(h));
else if ((w > 0) && (h < 0))
e.Graphics.DrawRectangle(pen, (float)_points[_points.Count - 1].X, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).Y, Math.Abs(w), Math.Abs(h));
else if ((w < 0) && (h > 0))
e.Graphics.DrawRectangle(pen, PointToCartesian(pictureBox1.PointToClient(Cursor. Position)).X, (float)_points[_points.Count - 1].Y, Math.Abs(w), Math.Abs(h));
else
e.Graphics.DrawRectangle(pen, (float)_points[_points.Count - 1].X, (float)_points[_points.Count - 1].Y, w, h);




var p1 = PointToCartesian( pictureBox1.PointToClient( Cursor.Position));
var p2 = _points[_points.Count - 1];
e.Graphics.DrawRectangle (pen, Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y), Math.Abs(p1.X - p2.X), Math.Abs(p1.Y - p2.Y));

مجتبی جوادی
شنبه 13 اردیبهشت 1399, 00:31 صبح
دست شما درد نکنه
به درستی که شما ماهرید

مجتبی جوادی
شنبه 13 اردیبهشت 1399, 00:55 صبح
ببخشید یک سوال داشتم:
توی ترنسفرم چرا شما ارتفاع را منهای یک کردید؟
e.Graphics.TranslateTransform(0, e.Graphics.VisibleClipBounds.Height - 1);

the king
شنبه 13 اردیبهشت 1399, 06:00 صبح
ببخشید یک سوال داشتم:
توی ترنسفرم چرا شما ارتفاع را منهای یک کردید؟
e.Graphics.TranslateTransform(0, e.Graphics.VisibleClipBounds.Height - 1);
فرض کنیم که Height ئه 100 باشه. محدوده y داخل کادر Rectangle میشه 0 الی 99. تعدادشون 100 تا است.
y ئه 100 دیگه داخل کادر نیست، چون از 0 الی 100 میشه 101 پیکسل.
حالا مبدا مختصات 0,0 ئه و میخواهیم جابجا بشویم به حداکثر مقدار y که پایین کادر ئه. یعنی 0,99. چند تا پیکسل باید پایین بیاییم؟ 99 پیکسل.
میخواهیم از 0,0 به 0,99 جابجا بشیم، چون اون 99 مقدار y پایین کادر ئه. اگر 100 پیکسل پایین بیاییم میشه 0,100 که نقطه 0,100 داخل کادر نیست، از کادر زده بیرون.

مجتبی جوادی
شنبه 13 اردیبهشت 1399, 14:27 عصر
فهمیدم
ایندکس از صفر شروع میشه
خیلی خیلی سپاسگزارم

مجتبی جوادی
شنبه 13 اردیبهشت 1399, 17:57 عصر
درود دوباره دوست گرامی
میخواستم بپرسم چطور میشه PaintEventArgs یا MouseEventArgs و .. را override کرد؟
با سپاس

the king
شنبه 13 اردیبهشت 1399, 19:35 عصر
درود دوباره دوست گرامی
میخواستم بپرسم چطور میشه PaintEventArgs یا MouseEventArgs و .. را override کرد؟
با سپاس
اگر هدف تون رو بدونم احتمالا بتوانم راهنمایی کنم وگرنه خود PaintEventArgs و MouseEventArgs رو نمیشه override کرد.
اگر در داخل کلاس کنترل ای فرضا OnMouseMove رو override کنید، می توانید MouseEventArgs با مقدار متفاوتی رو Invoke کنید یا حتی یکی از وارثین کلاس MouseEventArgs رو ارسال کنید.
اینها کلاس هایی هستند که به عنوان پارامتر رخداد بکار می روند، اینجور کلاس ها رو میشه با وراثت تغییر داد ولی رخدادی که از اون کلاس اصلی به عنوان پارامتر استفاده میکنه، کاری با کلاس وارث شما نداره.
حتی می توانید کلاس جدیدی بر اساس PaintEventArgs بسازید و رخداد جدیدی تعریف کنید که از کلاس شما به عنوان پارامتر استفاده کنه.
معمولا متد ها و مشخصه ها رو override می کنند تا کار متفاوت یا اضافه ای انجام بده یا از کار بندازنش، اما کلاس رو نمیشه override کرد.

مجتبی جوادی
شنبه 13 اردیبهشت 1399, 21:38 عصر
برای نمونه میشه مقادیر X, Y را در PaintEventArgs یا رویدادهای موس override کرد به طوریکه X,Y را به مقدار float یا double تبدیل کرد. واقعیت من میخوام یک پیکچر باکسی طراحی بشه که تمام این رویدادهایی که ثابت هستند یا اینکه نیاز دارم در آن تغییر داده شده باشه مثل دوران یا انتقال نقطه و ...
با سپاس

the king
یک شنبه 14 اردیبهشت 1399, 05:19 صبح
برای نمونه میشه مقادیر X, Y را در PaintEventArgs یا رویدادهای موس override کرد به طوریکه X,Y را به مقدار float یا double تبدیل کرد. واقعیت من میخوام یک پیکچر باکسی طراحی بشه که تمام این رویدادهایی که ثابت هستند یا اینکه نیاز دارم در آن تغییر داده شده باشه مثل دوران یا انتقال نقطه و ...
با سپاس

البته اینکه float یا double بشه در محاسبات تون تاثیر مثبت داره، ولی دقت در موقعیت خود X و Y رو افزایش نمیده، اونها همیشه اعداد بدون اعشار می مونند، چون ویندوز رخداد ها رو همبشه بر حسب پیکسل ارسال میکنه، X و Y چه int باشه و چه double باشه بعد ممیز فقط صفر ئه.

در منوی ویژوال استدیو با ...Project > Add Class یک کلاس جدید با نام MouseFloatEventArgs.cs بسازید و یک چیزی شبیه MouseEventArgs پیاده سازی کنید که بجای int بر حسب float باشه :

public class MouseFloatEventArgs : EventArgs
{
private readonly System.Windows.Forms. MouseButtons _button;
private readonly int _clicks;
private readonly float _x;
private readonly float _y;
private readonly int _delta;

public MouseFloatEventArgs (System.Windows.Forms. MouseEventArgs e)
{
_button = e.Button;
_clicks = e.Clicks;
_x = e.X;
_y = e.Y;
_delta = e.Delta;
}

public MouseFloatEventArgs (System.Windows.Forms. MouseButtons button, int clicks, float x, float y, int delta)
{
_button = button;
_clicks = clicks;
_x = x;
_y = y;
_delta = delta;
}

public System.Windows.Forms. MouseButtons Button
{
get
{
return _button;
}
}

public int Clicks
{
get
{
return _clicks;
}
}

public float X
{
get
{
return _x;
}
}

public float Y
{
get
{
return _y;
}
}

public int Delta
{
get
{
return _delta;
}
}
public System.Drawing.PointF Location
{
get
{
return new System.Drawing.PointF(_x, _y);
}
}
}

اگر ویژوال استدیو تون قدیمی نباشه اینطوری هم میشه خلاصه تر نوشت :

public class MouseFloatEventArgs : EventArgs
{
public MouseFloatEventArgs (System.Windows.Forms. MouseEventArgs e)
{
Button = e.Button;
Clicks = e.Clicks;
X = e.X;
Y = e.Y;
Delta = e.Delta;
}

public MouseFloatEventArgs (System.Windows.Forms. MouseButtons button, int clicks, float x, float y, int delta)
{
Button = button;
Clicks = clicks;
X = x;
Y = y;
Delta = delta;
}

public System.Windows.Forms. MouseButtons Button { get; }

public int Clicks { get; }

public float X { get; }

public float Y { get; }

public int Delta { get; }

public System.Drawing.PointF Location => new System.Drawing.PointF(X, Y);
}


حالا در منوی ویژوال استدیو با ...Project > Add Class یک کلاس جدید با نام MyPictureBox.cs بسازید و یک نوعی از PictureBox پیاده سازی کنید که چند تا رخداد اضافی داره :

public class MyPictureBox : System.Windows.Forms.PictureBox
{
public event EventHandler<MouseFloatEventArgs> MouseClickF;
public event EventHandler<MouseFloatEventArgs> MouseMoveF;
public event EventHandler<MouseFloatEventArgs> MouseDownF;
public event EventHandler<MouseFloatEventArgs> MouseUpF;

protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var ev = MouseMoveF;
if (ev != null)
{
ev.Invoke(this, new MouseFloatEventArgs(e));
}
}

protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
var ev = MouseClickF;
if (ev != null)
{
ev.Invoke(this, new MouseFloatEventArgs(e));
}
}

protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
var ev = MouseUpF;
if (ev != null)
{
ev.Invoke(this, new MouseFloatEventArgs(e));
}
}

protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
var ev = MouseDownF;
if (ev != null)
{
ev.Invoke(this, new MouseFloatEventArgs(e));
}
}
}

حالا بعد یکبار Build کردن پروژه (Build > Build Solution) بالای Toolbox یک MyPictureBox جدید اضافه شده که می توانید روی فرم ها اضافه کنید.
اون MyPictureBox رخداد هایی مثل MouseMoveF و MouseDownF داره که X و Y و Location شون بر حسب float و PointF ئه :

private void myPictureBox1_MouseMoveF(object sender, MouseFloatEventArgs e)
{

}

مجتبی جوادی
یک شنبه 14 اردیبهشت 1399, 16:14 عصر
درود بر دوست گرامی
سپاس از زحمت شما
من به یک مشکل دیگه برخوردم
وقتی SizeMode پیکچرباکس را به AutoSize تغییر می دم ، بین نقاط کلیک شده و ترسیم شده یک احتلاف ایجاد میشه
با سپاس

the king
یک شنبه 14 اردیبهشت 1399, 19:12 عصر
درود بر دوست گرامی
سپاس از زحمت شما
من به یک مشکل دیگه برخوردم
وقتی SizeMode پیکچرباکس را به AutoSize تغییر می دم ، بین نقاط کلیک شده و ترسیم شده یک احتلاف ایجاد میشه
با سپاس
تصویری که داخل PictureBox.Image قرار داده اید اونقدر بزرگ بوده که از حد نمایشی فرم فراتر بوده و همه تصویر در کادر فرم دیده نمیشه و بخشی اش پنهان شده.
به همین خاطر e.Graphics.VisibleClipBounds که قرار بود فضای داخل PictureBox بر حسب میلی متر باشه، یک کادر کوچکتر از اندازه کامل PictureBox شده.
در نتیجه کد زیر که در ابتدای pictureBox1_Paint بود، موقعیت درستی برای Transform بکار نمی بره :

e.Graphics.TranslateTransform(0, e.Graphics.VisibleClipBounds.Height - 1);

پس مجبور هستیم بجای e.Graphics.VisibleClipBounds که بخش پنهان PictureBox رو شامل نمیشه، از کد دیگری استفاده کنیم :

e.Graphics.TranslateTransform(0, PointToCartesian(Point.Empty).Y);

مجتبی جوادی
یک شنبه 14 اردیبهشت 1399, 19:29 عصر
خیلی از شما بابت کمک سپاسگزارم

مجتبی جوادی
یک شنبه 21 اردیبهشت 1399, 16:54 عصر
جناب The King گرامی درود بر شما
با راهنمایی ها شما من یک مثال انجام داده ام که در ضمیمه ارسال میکنم. اگر برای شما امکانپذیره سپاسگزار میشم درباره سوال های زیر منو راهنمایی کنید و ایراد برنامه را بگیرد.
یکی اینکه من میخوام با MouseWheel کار بزرگنمایی را انجام بدم که این کار را کردم ولی درست کار نمیکنه. زمانیکه گرافیک ترسیم شده (یا در حال ترسیم) بزرگ یا کوچک میشه، بین آخرین کلیک و موقعیت مکان نمای موس اختلاف ایجاد میشه.
دوم اینکه من میخوام مرکز بزرگنمایی موقعیت موس باشه و بر مبنای موقعیت موس شکل بزرگ یا کوچک بشه.
همانگونه که شما راهنمایی کردید من نقطه صفر صفحه را به سمت پایین چپ انتقال دادم یا به عبارتی سیستم را کارتزین کردم . حالا وقتی برنامه اجرا میشه ابتدا نقطه صفر استاندارد برنامه نمایش داده میشه و من میخوام که نقطه صفر جدید نمایش داده بشه.

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

the king
دوشنبه 22 اردیبهشت 1399, 09:36 صبح
جناب The King گرامی درود بر شما
با راهنمایی ها شما من یک مثال انجام داده ام که در ضمیمه ارسال میکنم. اگر برای شما امکانپذیره سپاسگزار میشم درباره سوال های زیر منو راهنمایی کنید و ایراد برنامه را بگیرد.
یکی اینکه من میخوام با MouseWheel کار بزرگنمایی را انجام بدم که این کار را کردم ولی درست کار نمیکنه. زمانیکه گرافیک ترسیم شده (یا در حال ترسیم) بزرگ یا کوچک میشه، بین آخرین کلیک و موقعیت مکان نمای موس اختلاف ایجاد میشه.
دوم اینکه من میخوام مرکز بزرگنمایی موقعیت موس باشه و بر مبنای موقعیت موس شکل بزرگ یا کوچک بشه.
همانگونه که شما راهنمایی کردید من نقطه صفر صفحه را به سمت پایین چپ انتقال دادم یا به عبارتی سیستم را کارتزین کردم . حالا وقتی برنامه اجرا میشه ابتدا نقطه صفر استاندارد برنامه نمایش داده میشه و من میخوام که نقطه صفر جدید نمایش داده بشه.

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

151685

زمینه برای gPanel رو رنگ سفید در نظر گرفته بودید و موقعی که اندازه DrawingEditor کوچکتر از gPanel میشد، کاربر متوجه نمیشد که مرز رسم کجا است و چرا در فلان نقطه رسم و کلیک صورت نمی گیره. با یک تصویر زمینه تعویض اش کردم. خود PictureBox نمی تونه Focus بگیره، به همین جهت علاوه بر DrawingEditor.MouseWheel که داشتید، this.MouseWheel خود فرم رو هم به متد DrawingEditor_MouseWheel متصل کردم.
DoubleBuffered رو در PictureBox ئه فعال کردم که پر پر زدن و Flicker کمتر بشه.
الان زوم سعی می کنه اون موقعیت ماوس رو در مرکز کادر gPanel قرار بده.
اون bmp بلا استفاده تون رو حذف کردم و بجایش size_ رو اضافه کردم. موقعی که زوم تغییر میکنه از size_ برای محاسبه دقیق ابعاد جدید استفاده می کنیم.

مجتبی جوادی
دوشنبه 22 اردیبهشت 1399, 20:38 عصر
درود بر دوست گرامی
با سپاس از لطف شما
یک سوال: نمیشه مقیاس را هم روی PictureBox اعمال کرد که همیشه صفحه سفید دیده بشه؟
چطور میشه نمایش اولیه را وقتی یک گرافیک جدید باز میشه روی نقطه صفری که تعریف کردیم باشه؟ یعنی اسکرول افقی پایین باشه اسکرول عموی هم سمت راست
سپاس فراوان

the king
سه شنبه 23 اردیبهشت 1399, 09:16 صبح
درود بر دوست گرامی
با سپاس از لطف شما
یک سوال: نمیشه مقیاس را هم روی PictureBox اعمال کرد که همیشه صفحه سفید دیده بشه؟

مقیاس همچین نتیجه ای نمیده، ScrollBar چه افقی و چه عمودی بر اساس یک ابعادی است، PictureBox ابعاد مشخصی داره، وقتی کادر پنل از اون ابعاد بزرگتر باشه ناگزیر بخشی اش خالی میمونه که جزو تصویر نیست. اگر با اتوکد مقایسه می کنید، اتوکد کادر اش ابعاد مشخصی نداره، طول و عرض نداره، سر و ته نداره، بی انتها است.



چطور میشه نمایش اولیه را وقتی یک گرافیک جدید باز میشه روی نقطه صفری که تعریف کردیم باشه؟ یعنی اسکرول افقی پایین باشه اسکرول عموی هم سمت راست
سپاس فراوان
اون gPanel.AutoScrollPosition رو تنظیم کنید.

.
.
.
DrawingEditor.ContextMenuStrip = popup;
gPanel.Controls.Add(DrawingEditor);
this.Shown += GraphicEditor_Shown;
.
.
.


private void GraphicEditor_Shown(object sender, EventArgs e)
{
gPanel.AutoScrollPosition = new Point(0, _size.Height);
}

مجتبی جوادی
چهارشنبه 24 اردیبهشت 1399, 00:01 صبح
مقیاس همچین نتیجه ای نمیده، ScrollBar چه افقی و چه عمودی بر اساس یک ابعادی است، PictureBox ابعاد مشخصی داره، وقتی کادر پنل از اون ابعاد بزرگتر باشه ناگزیر بخشی اش خالی میمونه که جزو تصویر نیست. اگر با اتوکد مقایسه می کنید، اتوکد کادر اش ابعاد مشخصی نداره، طول و عرض نداره، سر و ته نداره، بی انتها است.


اون gPanel.AutoScrollPosition رو تنظیم کنید.

.
.
.
DrawingEditor.ContextMenuStrip = popup;
gPanel.Controls.Add(DrawingEditor);
this.Shown += GraphicEditor_Shown;
.
.
.


private void GraphicEditor_Shown(object sender, EventArgs e)
{
gPanel.AutoScrollPosition = new Point(0, _size.Height);
}


سپاسگزار

جناب the King وقتی که میخواهیم یک رویداد را به یک کنترل نسبت بدیم از عملگر =+ استفاده میکنیم و بعضی مواقع از عملگر =- استفاده میشه. چه فرقی باهم دارند؟ امکان داره با یک مثال توضیح
بدید
سپاس فراوان

the king
چهارشنبه 24 اردیبهشت 1399, 08:05 صبح
سپاسگزار

جناب the King وقتی که میخواهیم یک رویداد را به یک کنترل نسبت بدیم از عملگر =+ استفاده میکنیم و بعضی مواقع از عملگر =- استفاده میشه. چه فرقی باهم دارند؟ امکان داره با یک مثال توضیح
بدید
سپاس فراوان
با =+ متصل می کنیم و با =- حذف می کنیم. درست برعکس هم هستند. در نظر بگیرید که می توانیم یک متد رو بیشتر از یکبار متصل کنیم، به همون تعداد اتصال فراخوانی میشه.
رخداد ها بر اساس الگوی delegate ها به متد هایی متصل می شوند تا موقع بروز رخداد اون متد های متصل با ترتیب اتصال شون اجرا شوند.
یکی از خاصیت های delegate در #C اینه که خاصیت چند پخشی (multicast) دارند، یعنی موقع بروز رخداد به همه متد های متصل رجوع می کنه، الزاما فقط یک متد نیست، ممکنه صد تا متد به یک رخداد متصل شده باشه.
اگر قابلیت multicast وجود نداشت، فقط می توانستیم یک متد رو به رخداد متصل کنیم و همون رو هم حذف کنیم، وقتی فقط صحبت یک متد در میون باشه دیگه =+ و =- معنی نداشت.
استفاده از عملگر =+ و =- دقیقا به این دلیل معنی میده که داریم یک متد رو به مجموعه متد های متصل اضافه می کنیم (=+) یا داریم از مجموعه متد های متصل حذف می کنیم (=-)

مثلا پیام "امروز چهار شنبه است" به این دلیل نمایش داده میشه که متد نمایش دهنده "سه شنبه" رو که با =+ اضافه کرده بودیم در ادامه با =- از مجموعه متد های متصل حذف می کنیم و موقع رخداد کلیک اون متد فراخوانی نمیشه :

public partial class Form1 : Form
{
private readonly StringBuilder _s = new StringBuilder();

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
button1.Click += Click1;
button1.Click += Click2;
button1.Click += Click3;
button1.Click += Click4;
button1.Click += Click5;
button1.Click -= Click2;
}

private void Click1(object sender, EventArgs e)
{
_s.Append("امروز ");
}

private void Click2(object sender, EventArgs e)
{
_s.Append("سه شنبه ");
}

private void Click3(object sender, EventArgs e)
{
_s.Append("چهار شنبه ");
}

private void Click4(object sender, EventArgs e)
{
_s.Append("است");
}

private void Click5(object sender, EventArgs e)
{
MessageBox.Show(_s.ToString());
}
}


و همانطور که اشاره کردم میشه یک متد رو بیشتر از یکبار متصل کرد، با همون ترتیب اتصال فراخوانی می شوند :

public partial class Form1 : Form
{
private readonly StringBuilder _s = new StringBuilder();

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
button1.Click += ClickR;
button1.Click += ClickA;
button1.Click += ClickD;
button1.Click += ClickA;
button1.Click += ClickR;
button1.Click += ClickEnd;
}

private void ClickA(object sender, EventArgs e)
{
_s.Append("A");
}

private void ClickD(object sender, EventArgs e)
{
_s.Append("D");
}

private void ClickR(object sender, EventArgs e)
{
_s.Append("R");
}

private void ClickEnd(object sender, EventArgs e)
{
MessageBox.Show(_s.ToString());
}
}

مجتبی جوادی
چهارشنبه 24 اردیبهشت 1399, 15:40 عصر
درود دوباره دوست گرامی
این ویژگی کاربرد زیادی داره و من نمیدونستم.
خیلی خیلی سپاسگزارم :تشویق::تشویق::تشویق::تشویق:

pe32_64
چهارشنبه 24 اردیبهشت 1399, 18:26 عصر
سپاسگزار

جناب the King وقتی که میخواهیم یک رویداد را به یک کنترل نسبت بدیم از عملگر =+ استفاده میکنیم و بعضی مواقع از عملگر =- استفاده میشه. چه فرقی باهم دارند؟ امکان داره با یک مثال توضیح
بدید
سپاس فراوان
درود

عملگر =+ راست رو به چپ اضافه میکنه .
عملگر =- راست رو از چپ کم میکنه.

مجتبی جوادی
جمعه 02 خرداد 1399, 14:46 عصر
درود دوباره بر جناب The King گرامی
ببخشید که من وقتی به مشکل بر میخورم دوباره به شما زحمت میدم
خدمت شما عرض کنم من میخوام وقتی اندازه PictureBox از ClientSize کوچکتر میشه بتونم نقاط منفی را هم کلیک کنم یا به عبارتی هرچه شکل کوچکتر میشه PictureBox از اندازه ClientSize کوچکتر نشه که من بتونم در ان فضای اختلاف مقدار منفی را وارد کنم. البته از اینکه میگم مقدار منفی اینه که من اندازه های pictureBox1.Left و pictureBox1.Top را در رویداد MouseWheel طبق کد زیر انتقال داده ام تا در سمت چب و پایین فضای مقادیر منفی ایجاد بشه. من سایز PictureBox را در صورت کوچکتر شدن از ClientSize با سایز ClientSize مساوی قرار دادم و اختلاف اندازه های Width و Height را به x و y نقاط اضافه کردم ولی جواب نداد.

DrawingEditor.Left = (ClientSize.Width - DrawingEditor.Width) / 2;
DrawingEditor.Top = (ClientSize.Height - DrawingEditor.Height) / 2;

امیدوارم توانسته باشم منظورم را برسانم
با سپاس فراوان

the king
جمعه 02 خرداد 1399, 20:47 عصر
درود دوباره بر جناب The King گرامی
ببخشید که من وقتی به مشکل بر میخورم دوباره به شما زحمت میدم
خدمت شما عرض کنم من میخوام وقتی اندازه PictureBox از ClientSize کوچکتر میشه بتونم نقاط منفی را هم کلیک کنم یا به عبارتی هرچه شکل کوچکتر میشه PictureBox از اندازه ClientSize کوچکتر نشه که من بتونم در ان فضای اختلاف مقدار منفی را وارد کنم. البته از اینکه میگم مقدار منفی اینه که من اندازه های pictureBox1.Left و pictureBox1.Top را در رویداد MouseWheel طبق کد زیر انتقال داده ام تا در سمت چب و پایین فضای مقادیر منفی ایجاد بشه. من سایز PictureBox را در صورت کوچکتر شدن از ClientSize با سایز ClientSize مساوی قرار دادم و اختلاف اندازه های Width و Height را به x و y نقاط اضافه کردم ولی جواب نداد.

DrawingEditor.Left = (ClientSize.Width - DrawingEditor.Width) / 2;
DrawingEditor.Top = (ClientSize.Height - DrawingEditor.Height) / 2;

امیدوارم توانسته باشم منظورم را برسانم
با سپاس فراوان
DrawingEditor رو جابجا نکنید، کمکی نمی کنه.
تا حالا روش بزرگنمایی و انتقال در کد شما اینطور بوده که یک PictureBox مطابق با zoom بزرگ و کوچک میشه و داخل یک کادر با ScrollBar جابجا میشه.
زمانی که zoom مقدار کمی داشت، PictureBox زیادی کوچیک میشه و در نتیجه دیگه همه پنجره رو پوشش نمیده و بخشی از کادر پنجره بیرون PictureBox ئه.
میشه برای Click در بیرون کادر کاری انجام داد تا Click اش مشابه Click در داخل PictureBox بکار برده بشه، اما چون بیرون کادر ئه، در رسم PictureBox دیده نمیشه.
با جابجا کردن PictureBox هم نمیشه مشکل رسم رو برطرف کرد.

حالا اگر بخواهید PictureBox هیچوقت کوچکتر از کادر نشه، همه جای پنجره قابل کلیک باشه و در رسم دیده بشه، باید کلا از بزرگ و کوچک شدن PictureBox جلوگیری کنید، یعنی zoom روی ابعاد PictureBox بی تاثیر باشه. اینکار هم نتیجه اش اینه که دیگه نمی توانید از ScrollBar خودکار استفاده کنید.
ابعاد PictureBox رو همواره برابر با کادر ثابت دورش در نظر بگیرید و برای Scroll شدن و به اصطلاح فرمان Pan روش دیگری رو بکار ببرید.

مجتبی جوادی
یک شنبه 04 خرداد 1399, 14:31 عصر
درود بر جناب The King گرامی
از پاسخ شما سپاسگزارم
من یک قایل را ضمیمه کردم و خواستم نظر شما را هم بدونم که آیا میشه کد بهتری براش در نظر گرفت
با سپاس دوباره