گفتگو هایی در باب سی شارپ

the_king

مدیرکل انجمن
ممنون
یه دکمه با رویدادهای زیر :

کد:
        private void button24_MouseDown(object sender, MouseEventArgs e)
        {
            MessageBox.Show("Down");
        }

        private void button24_MouseLeave(object sender, EventArgs e)
        {
            MessageBox.Show("Leave");
        }

من که روش کلیک میکنم ، هم زمان ، هر دو رویداد اجرا میشه و اتفاقا MouseLeave زودتر اجرا میشه
بله، غیر از این باشه اشتباهه. شما داخل رخداد MouseDown درخواست نمایش یک DialogBox می کنید، ماوس که در حال حاضر توسط Button مورد نظر Capture شده آزاد میشه و به همین دلیل MouseLeave رخ میده، کد اون که تموم شد، تازه فرصت برای نمایش DialogBox تون فراهم میشه. این به این معنی نیست که MouseLeave زودتر اتفاق افتاده. MouseDown زودتر رخ داده بود که اون کد نمایش "Down" باعث MouseLeave شده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بله، غیر از این باشه اشتباهه. شما داخل رخداد MouseDown درخواست نمایش یک DialogBox می کنید، ماوس که در حال حاضر توسط Button مورد نظر Capture شده آزاد میشه و به همین دلیل MouseLeave رخ میده، کد اون که تموم شد، تازه فرصت برای نمایش DialogBox تون فراهم میشه. این به این معنی نیست که MouseLeave زودتر اتفاق افتاده. MouseDown زودتر رخ داده بود که اون کد نمایش "Down" باعث MouseLeave شده.

ممنون استاد علی
بابت کد قبلی تون هم ، ممنونم
درباره ی این قضیه ، نمیدونم . در کد زیر :


کد:
        public Point MouseMoveForm;
        public bool ClickingDownFlag;
        public int FirstEnterButtonCounter;
        public Point InitMouseMove;
        public Point MouseMoveRather;
        private void Buttons_MouseDown(object sender, MouseEventArgs e)
        {
            this.ClickingDownFlag = true;

            this.DoDragDrop(sender, DragDropEffects.All);  // باعث انجام عمل درگ و دروپ میشه
        }

        private void Buttons_MouseMove(object sender, MouseEventArgs e)
        {
            this.FirstEnterButtonCounter++;
            if (this.FirstEnterButtonCounter == 1)  // اولین باره که این رویداد اجرا میشه
            {
                this.InitMouseMove = e.Location;  // مکان اولین باری که موس وارد دکمه شد را بگیر
                MouseMoveRather = new Point(0, 0);  // تفاوت تغییر مکان موس به نسبت اولین ورود
            }
            else
            {
                MouseMoveRather = new Point(e.Location.X - this.InitMouseMove.X, e.Location.X - this.InitMouseMove.Y);
            }

            if (this.ClickingDownFlag == true)  // کد اصلی
            {
                Button button = sender as Button;
                if (button == null)
                    return;

                Point virtualMouseMoveForm = new Point(this.MouseMoveForm.X + this.MouseMoveRather.X, this.MouseMoveForm.Y + this.MouseMoveRather.Y);

            }

        }
       
        private void FormTest_MouseMove(object sender, MouseEventArgs e)
        {
            this.MouseMoveForm = e.Location;
        }

        private void Buttons_MouseUp(object sender, MouseEventArgs e)
        {
            this.ClickingDownFlag = false;
        }

        private void Buttons_MouseLeave(object sender, EventArgs e)
        {
            this.FirstEnterButtonCounter = 0;
        }

قصدم اینه که وقتی روی دکمه ای کلیک میکنم ، و موس را هر جایی که میبرم ، اون کنترل (در اینجا ، دکمه) با موس به همون مکان بره
البته کد کامل نیست و به مشکل برخوردم . اونم اینکه وقتی روس موس برای اولین بار کلیک میکنم ، و موس را جابجا میکنم ، درست کار میکنه ولی وقتی که موس (کلیک چپ موس) را رها میکنم ، هنوز کد کار میکنه که احتمالا واسه ی این قضیه ی دو رویدادی هست که گفتم (چون رویداد موس هست ، نمیشه بریک پوینت بذارم چون بسیار تکرار میشه و همزمان نمیشه عمل رو دید)
 

the_king

مدیرکل انجمن
ممنون استاد علی
بابت کد قبلی تون هم ، ممنونم
درباره ی این قضیه ، نمیدونم . در کد زیر :


کد:
        public Point MouseMoveForm;
        public bool ClickingDownFlag;
        public int FirstEnterButtonCounter;
        public Point InitMouseMove;
        public Point MouseMoveRather;
        private void Buttons_MouseDown(object sender, MouseEventArgs e)
        {
            this.ClickingDownFlag = true;

            this.DoDragDrop(sender, DragDropEffects.All);  // باعث انجام عمل درگ و دروپ میشه
        }

        private void Buttons_MouseMove(object sender, MouseEventArgs e)
        {
            this.FirstEnterButtonCounter++;
            if (this.FirstEnterButtonCounter == 1)  // اولین باره که این رویداد اجرا میشه
            {
                this.InitMouseMove = e.Location;  // مکان اولین باری که موس وارد دکمه شد را بگیر
                MouseMoveRather = new Point(0, 0);  // تفاوت تغییر مکان موس به نسبت اولین ورود
            }
            else
            {
                MouseMoveRather = new Point(e.Location.X - this.InitMouseMove.X, e.Location.X - this.InitMouseMove.Y);
            }

            if (this.ClickingDownFlag == true)  // کد اصلی
            {
                Button button = sender as Button;
                if (button == null)
                    return;

                Point virtualMouseMoveForm = new Point(this.MouseMoveForm.X + this.MouseMoveRather.X, this.MouseMoveForm.Y + this.MouseMoveRather.Y);

            }

        }
      
        private void FormTest_MouseMove(object sender, MouseEventArgs e)
        {
            this.MouseMoveForm = e.Location;
        }

        private void Buttons_MouseUp(object sender, MouseEventArgs e)
        {
            this.ClickingDownFlag = false;
        }

        private void Buttons_MouseLeave(object sender, EventArgs e)
        {
            this.FirstEnterButtonCounter = 0;
        }

قصدم اینه که وقتی روی دکمه ای کلیک میکنم ، و موس را هر جایی که میبرم ، اون کنترل (در اینجا ، دکمه) با موس به همون مکان بره
البته کد کامل نیست و به مشکل برخوردم . اونم اینکه وقتی روس موس برای اولین بار کلیک میکنم ، و موس را جابجا میکنم ، درست کار میکنه ولی وقتی که موس (کلیک چپ موس) را رها میکنم ، هنوز کد کار میکنه که احتمالا واسه ی این قضیه ی دو رویدادی هست که گفتم (چون رویداد موس هست ، نمیشه بریک پوینت بذارم چون بسیار تکرار میشه و همزمان نمیشه عمل رو دید)
اگر میدونید چیزی قراره حتما Button باشه چرا as Button رو بکار می برید؟ as Button برای زمانی ئه که ممکنه Button نباشه و بعدا بخواهید چک کنید که نتیجه null هست یا نه. وقتی میدونید null نیست با (Button) کار کنید.
همچنین برای ساده تر شدن کد نویسی می توانید بجای تعریف نوع داده var رو بکار ببرید و this های اضافی رو هم ننویسید. اصولا فقط زمانی this لازمتون میشه که یا صرفا خود this را می خواهید و یا مشابه چیزی مانند Text در اون بلوک کد هست که نمی خواهید با this.Text اشتباه گرفته بشه.
می توانید از DoDragDrop استفاده کنید، اشکالی هم نداره، اما کاری که انجام می دهید خیلی شبیه DragDrop داده نیست. شما که نمی خواهید به همه کنترل های روی فرم بگید آماده DragDrop اون کنترل مبارک باشند، عملی هست اما خیلی جالب نیست. اگر هم نمی خواهید از رخداد DragDrop استفاده کنید که اصلا چرا DoDragDrop می کنید. شما می توانید همه کد تون رو بر اساس رخداد های همون Button بنویسید، نه کاری به Form دارید و نه سایر کنترل ها.
کد:
        private Point _dragPos;

        private void Buttons_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _dragPos = e.Location;
            }
        }

        private void Buttons_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                var c = (Control)sender;
                c.Location = new Point(c.Left + e.X - _dragPos.X, c.Top + e.Y - _dragPos.Y);
            }
        }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
اگر میدونید چیزی قراره حتما Button باشه چرا as Button رو بکار می برید؟ as Button برای زمانی ئه که ممکنه Button نباشه و بعدا بخواهید چک کنید که نتیجه null هست یا نه. وقتی میدونید null نیست با (Button) کار کنید.
همچنین برای ساده تر شدن کد نویسی می توانید بجای تعریف نوع داده var رو بکار ببرید و this های اضافی رو هم ننویسید. اصولا فقط زمانی this لازمتون میشه که یا صرفا خود this را می خواهید و یا مشابه چیزی مانند Text در اون بلوک کد هست که نمی خواهید با this.Text اشتباه گرفته بشه.
می توانید از DoDragDrop استفاده کنید، اشکالی هم نداره، اما کاری که انجام می دهید خیلی شبیه DragDrop داده نیست. شما که نمی خواهید به همه کنترل های روی فرم بگید آماده DragDrop اون کنترل مبارک باشند، عملی هست اما خیلی جالب نیست. اگر هم نمی خواهید از رخداد DragDrop استفاده کنید که اصلا چرا DoDragDrop می کنید. شما می توانید همه کد تون رو بر اساس رخداد های همون Button بنویسید، نه کاری به Form دارید و نه سایر کنترل ها.
کد:
        private Point _dragPos;

        private void Buttons_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                _dragPos = e.Location;
            }
        }

        private void Buttons_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                var c = (Control)sender;
                c.Location = new Point(c.Left + e.X - _dragPos.X, c.Top + e.Y - _dragPos.Y);
            }
        }

خیلی ممنونم استاد علی
ولی من یه چیز رو نفهمیدم .
چرا الگوریتم c.Left + e.X - _dragPos.X رو بکار بردین در صورتی که مقدار e.X و _dragPos.X یکی هست؟ یعنی جواب آخر ، دوباره همون مقدار c.Left میشه . ولی اگه فقط c.Left هم به تنهایی باشه ، کار نمیکنه! چرا؟
و دوم اینکه چرا مقدار e.X با _dragPos.X که برابره ، هر دو رو یه متغییر نگرفتین و متغییر _dragPos رو از یه رویداد دیگه ننوشتین؟ یعنی چرا ین جوری ننوشتین c.Left + e.X - e.X ؟ این جوری هم هر چند کار نمیکنه ولی دلیل اش رو نمیدونم
-------------------------------
درباره ی کلمه ی کلیدی as ، باشه
درباره ی کلمه ی کلیدی this ، میدونم ولی کلا عادت به دقیق نویسی دارم
 

the_king

مدیرکل انجمن
خیلی ممنونم استاد علی
ولی من یه چیز رو نفهمیدم .
چرا الگوریتم c.Left + e.X - _dragPos.X رو بکار بردین در صورتی که مقدار e.X و _dragPos.X یکی هست؟ یعنی جواب آخر ، دوباره همون مقدار c.Left میشه . ولی اگه فقط c.Left هم به تنهایی باشه ، کار نمیکنه! چرا؟
و دوم اینکه چرا مقدار e.X با _dragPos.X که برابره ، هر دو رو یه متغییر نگرفتین و متغییر _dragPos رو از یه رویداد دیگه ننوشتین؟ یعنی چرا ین جوری ننوشتین c.Left + e.X - e.X ؟ این جوری هم هر چند کار نمیکنه ولی دلیل اش رو نمیدونم
-------------------------------
درباره ی کلمه ی کلیدی as ، باشه
درباره ی کلمه ی کلیدی this ، میدونم ولی کلا عادت به دقیق نویسی دارم
چطور ممکنه e.X که هر لحظه با جابجایی ماوس امکان تغییر مقدار داره با مقدار DragPos.X که فقط یکبار مقدار دهی شده مقدارش یکسان بمونه؟
DragPos.X موقعیتی ئه که موقع شروع Drag کردن ماوس روی دکمه قرار داشت، به اصطلاح محل Grip ئه، اما e.X محل فعلی ماوس ئه، که سریع ماوس جابجا بشه الزاما اصلا روی فضای خود دکمه هم نیست. اگر قرار بود طبق فرمایش شما e.X همیشه برابر DragPos.X باشه که اصلا جابجایی هیچوقت صورت نگرفته و ماوس جابجا نشده و دکمه هم از جاش تکون نخورده. شرط جابجایی اینه که ماوس موقعیت اش تغییر کنه و e.X و e.Y جای دیگری بره. درسته؟ از طرف دیگه DragPos.X موقعیت شروع Drag ئه، دیگه بعدا که مقدارش تغییری نخواهد کرد، در کل فرایند Drag این مقدار ثابته. اما e.X و e.Y که ثابت نیستند، تغییر می کنند، پس همانقدر که به نگهداری مقدار DragPos نیاز هست و متغیر میخواد دلیلی برای نگهداری e.X و e.Y نیست و متغیری برای اینکار اختصاص نمی دهیم. اگر DragPos.X در موقعیت 10 باشه و حالا e.X برابر 12 باشه معنی اش چیه؟ معنی اش اینه که ماوس از 10 به 12 جابجا شده و به مقدار 10 - 12 پیکسل جابجایی صورت گرفته، نه معنی اش اینه که 10 پیکسل جابجا شده و نه معنی اش اینه 12 پیکسل جابجا شده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
بازم ممنون استاد علی
توی رویداد paint (کلا کلاس Graphic) ، مهم ترین اعضا ، اینان؟ :
پروپرتی های PageScale (برای بزرگنمایی گرافیک) و SmoothingMode (برای تعیین کیفیت گرافیک)
متدهای CopyFromScreen (رسم هر شکلی که در مانیتور دیده میشه در گرافیک) ، GetHdc (برای گرفتن Handel Device Context و ساخت شی گرافیک از اون) ، انواع متدهایی که با Draw شروع میشن برای رسم اشکال تو خالی و انواع متدهایی که با Fill شروع میشن ، برای رسم اشکال تو پر، Save برای ذخیره کردن گرافیک و Restore هم برای برگردوندن گرافیک Save شده از قبل . Clear برای پاک کردن گرافیک با رنگ خاص

بجز اینا ، اعضای مهم دیگه ای هستن که کاربرد داشته باشه؟ اگه آره ، چه عضوی در کجا کاربرد داره؟
---------------------------------------------------------------------------------------------
و اینکه برای ساخت گرافیک درون رویدادی بجز رویداد Paint ، آیا بهتره از درون اون رویداد ، رویداد Paint را فراخونی کنم یا اینکه توی همون رویدادی که هستم (رویدادی بجز رویداد Paint) ، با CreateGraphic ، گرافیک بسازم؟
و اینکه مثلا یه گرافیکی (فرضا یک مستطیل) کشیدیم ، Bound اون گرافیک را چجوری میشه گرفت؟ یعنی مثلا توی فرم ، یه گرافیکی (مستطیل) با جزئیات X=10 و Y=35 و Width=100 و Height=50 کشیدیم (یا کاربر کشید) ، حالا این مشخصات رو چجوری میشه بصورت کدنویسی بدست آورد؟
در سئوال بالا (یعی وقتی گرافیکی رسم بشه) ، اگه در یک شی گرافیک ، چندین گرافیک (مثلا 2 تا خط یا 2 تا مستطیل) در نواحی مختلف رسم بشه ، حالا چجوری میشه Bound های این دو گرافیکِ رسم شده در یک شی گرافیک را گرفت؟
اگه بخوایم یه بخشی از گرافیک را پاک کنیم (نه همه شو) ، باید چی کار کنیم؟ چون متد Clear ، ورودی ای نداره که ازمون بپرسه که چه منطقه ای رو پاک کنه (کاربردش اینکه مثل مداد پاک کن در نرم افزار paint ویندوز ، هر جا موس بره ، اون قسمت از گرافیک ، پاک شه)
 

the_king

مدیرکل انجمن
سلام
بازم ممنون استاد علی
توی رویداد paint (کلا کلاس Graphic) ، مهم ترین اعضا ، اینان؟ :
پروپرتی های PageScale (برای بزرگنمایی گرافیک) و SmoothingMode (برای تعیین کیفیت گرافیک)
متدهای CopyFromScreen (رسم هر شکلی که در مانیتور دیده میشه در گرافیک) ، GetHdc (برای گرفتن Handel Device Context و ساخت شی گرافیک از اون) ، انواع متدهایی که با Draw شروع میشن برای رسم اشکال تو خالی و انواع متدهایی که با Fill شروع میشن ، برای رسم اشکال تو پر، Save برای ذخیره کردن گرافیک و Restore هم برای برگردوندن گرافیک Save شده از قبل . Clear برای پاک کردن گرافیک با رنگ خاص

بجز اینا ، اعضای مهم دیگه ای هستن که کاربرد داشته باشه؟ اگه آره ، چه عضوی در کجا کاربرد داره؟

من نمیتونم چیزی رو به عنوان مهم و غیر مهم مشخص کنم که اینها تو امتحان میاد بقیه حذف :D کلا مواردی که کاربرد شون خیلی کم ئه در NET Framework. وجود نداره، بیخودی NET. رو برای موارد کم کاربرد سنگین نمی کنند. چیزی در Framework اضافه میشه که کاربرد زیادی داشته باشه و یا وجودش برای سایر کاربرد ها ضروری باشه. فرضا ممکنه در خیلی از اشیاء از Handle به ندرت استفاده بشه ولی برای تبادلش با خارج از محیط NET. وجود این Handle ضروری ئه.

و اینکه برای ساخت گرافیک درون رویدادی بجز رویداد Paint ، آیا بهتره از درون اون رویداد ، رویداد Paint را فراخونی کنم یا اینکه توی همون رویدادی که هستم (رویدادی بجز رویداد Paint) ، با CreateGraphic ، گرافیک بسازم؟
و اینکه مثلا یه گرافیکی (فرضا یک مستطیل) کشیدیم ، Bound اون گرافیک را چجوری میشه گرفت؟ یعنی مثلا توی فرم ، یه گرافیکی (مستطیل) با جزئیات X=10 و Y=35 و Width=100 و Height=50 کشیدیم (یا کاربر کشید) ، حالا این مشخصات رو چجوری میشه بصورت کدنویسی بدست آورد؟

کاربر یا خودتون به هر حال رسم کردن کد داره، توی همون کد Rectangle ای که رسم شده رو به یک متغیر تکی یا List بسپارید و بعدا خودتون رو برای پردازش تصویر برای پیدا کردن ابعاد به دردسر نندازید. یک List از نوع Rectangle بسازید و هر چی رسم کردید به اون مجموعه اضافه کنید. اون Rectangle ها یک Contains دارند که باهاش می توانید بفهمید ماوس الان داخل کادر شون هست یا نه.

برای رسم مجدد، ساختن CreateGraphics هیچوقت گزینه خوبی نیست، چون به هر حال برای Paint شیء Graphics ساخته میشه. CreateGraphics عموما دو جا لازمه، یکی وقتی رسمی در کار نیست، ولی لازمه برای پردازشی به Device Context دسترسی داشته باشید، فرضا برای بدست آوردن ابعاد یک نوشته با یک فونت مشخص. کاربرد دوم زمانیه که میخواهید در یک Bitmap مستقل رسم کنید، فرضا می خواهید ابعاد یک Image رو عوض کنید، یا دو تا تصویر رو ترکیب کنید. بالاخره باید یک جایی Graphics بسازید که اینکار ها رو انجام بدید. اما در سایر موارد و مخصوصا برای رسم مجدد اصلا CreateGraphics رو توصیه نمی کنم. مخصوصا که کلا NET. و اغلب زبان های سطح بالا در رسم گرافیکی خیلی سریع نیستند و تفاوت کارایی روش هایی که استفاده می کنید خیلی مشخص ئه و کندی هر روش نامناسبی به چشم میاد.
اگر رسم تون سبک ئه که Invalidate کنید، خودش Paint رو فراخوانی می کنه. اما اگه رسم سنگینه و نمیخواهید با هر Paint مجددا پردازش رسم صورت بگیره BufferedGraphics توصیه میشه، پردازش رسم رو هم برای استفاده مجدد نگه میداره :
کد:
        private BufferedGraphics _bg;

        private void Form1_Load(object sender, EventArgs e)
        {
            var bgm = BufferedGraphicsManager.Current;
            using (var g = CreateGraphics())
            {
                _bg = bgm.Allocate(g, new Rectangle(0, 0, 100, 100));
                _bg.Graphics.Clear(Color.LightBlue);
            }
        }

        private void button1_Paint(object sender, PaintEventArgs e)
        {
            if (_bg != null)
            {
                _bg.Render(e.Graphics);
            }
        }
در سئوال بالا (یعی وقتی گرافیکی رسم بشه) ، اگه در یک شی گرافیک ، چندین گرافیک (مثلا 2 تا خط یا 2 تا مستطیل) در نواحی مختلف رسم بشه ، حالا چجوری میشه Bound های این دو گرافیکِ رسم شده در یک شی گرافیک را گرفت؟
اگه بخوایم یه بخشی از گرافیک را پاک کنیم (نه همه شو) ، باید چی کار کنیم؟ چون متد Clear ، ورودی ای نداره که ازمون بپرسه که چه منطقه ای رو پاک کنه (کاربردش اینکه مثل مداد پاک کن در نرم افزار paint ویندوز ، هر جا موس بره ، اون قسمت از گرافیک ، پاک شه)
کلا چیزی که رسم می کنید رو جایی ثبت کنید. علاوه بر اینکه برای تفکیک و جابجای و تنظیم شون لازم میشه حتی بعدا برای Undo و Redo هم بدرد میخوره.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
من نمیتونم چیزی رو به عنوان مهم و غیر مهم مشخص کنم که اینها تو امتحان میاد بقیه حذف :D کلا مواردی که کاربرد شون خیلی کم ئه در NET Framework. وجود نداره، بیخودی NET. رو برای موارد کم کاربرد سنگین نمی کنند. چیزی در Framework اضافه میشه که کاربرد زیادی داشته باشه و یا وجودش برای سایر کاربرد ها ضروری باشه. فرضا ممکنه در خیلی از اشیاء از Handle به ندرت استفاده بشه ولی برای تبادلش با خارج از محیط NET. وجود این Handle ضروری ئه.

ممنون استاد علی
:green:
چون توی آموزش ها میخوام سریعتر گرافیک ها و رویداد paint رو بگم (چون نمیتونم زیاد روی گرافیک وقت صرف کنم چون وقت ام خیلی محدوده و مباحثی به مراتب خیلی مهمتر از گرافیک موندش) و از اونجایی هم که زیاد با گرافیک کار نکردم ، گفتم چند عضوی که باز توی اونا بیشترین کاربرد را دارن (مثلا 5 یا 10 عضوِ پر کاربرد دیگه) بگین تا روی اونا تمرکز کنم


کاربر یا خودتون به هر حال رسم کردن کد داره، توی همون کد Rectangle ای که رسم شده رو به یک متغیر تکی یا List بسپارید و بعدا خودتون رو برای پردازش تصویر برای پیدا کردن ابعاد به دردسر نندازید. یک List از نوع Rectangle بسازید و هر چی رسم کردید به اون مجموعه اضافه کنید. اون Rectangle ها یک Contains دارند که باهاش می توانید بفهمید ماوس الان داخل کادر شون هست یا نه.

برای رسم مجدد، ساختن CreateGraphics هیچوقت گزینه خوبی نیست، چون به هر حال برای Paint شیء Graphics ساخته میشه. CreateGraphics عموما دو جا لازمه، یکی وقتی رسمی در کار نیست، ولی لازمه برای پردازشی به Device Context دسترسی داشته باشید، فرضا برای بدست آوردن ابعاد یک نوشته با یک فونت مشخص. کاربرد دوم زمانیه که میخواهید در یک Bitmap مستقل رسم کنید، فرضا می خواهید ابعاد یک Image رو عوض کنید، یا دو تا تصویر رو ترکیب کنید. بالاخره باید یک جایی Graphics بسازید که اینکار ها رو انجام بدید. اما در سایر موارد و مخصوصا برای رسم مجدد اصلا CreateGraphics رو توصیه نمی کنم. مخصوصا که کلا NET. و اغلب زبان های سطح بالا در رسم گرافیکی خیلی سریع نیستند و تفاوت کارایی روش هایی که استفاده می کنید خیلی مشخص ئه و کندی هر روش نامناسبی به چشم میاد.
اگر رسم تون سبک ئه که Invalidate کنید، خودش Paint رو فراخوانی می کنه. اما اگه رسم سنگینه و نمیخواهید با هر Paint مجددا پردازش رسم صورت بگیره BufferedGraphics توصیه میشه، پردازش رسم رو هم برای استفاده مجدد نگه میداره :
کد:
        private BufferedGraphics _bg;

        private void Form1_Load(object sender, EventArgs e)
        {
            var bgm = BufferedGraphicsManager.Current;
            using (var g = CreateGraphics())
            {
                _bg = bgm.Allocate(g, new Rectangle(0, 0, 100, 100));
                _bg.Graphics.Clear(Color.LightBlue);
            }
        }

        private void button1_Paint(object sender, PaintEventArgs e)
        {
            if (_bg != null)
            {
                _bg.Render(e.Graphics);
            }
        }

کلا چیزی که رسم می کنید رو جایی ثبت کنید. علاوه بر اینکه برای تفکیک و جابجای و تنظیم شون لازم میشه حتی بعدا برای Undo و Redo هم بدرد میخوره.

حالا خود کلاس Graphic ، این قابلیت رو نداره که برای رسمِ گرافیک ، یه محدوده ی خاصی تعیین کنیم و در اون محدوده رسم کنیم؟ یا فقط در همون محدوده پاک (متد Clear) کنیم؟
در توضیح (remark) متد Clear در graphic این را نوشته :


کد:
The Clear method clears the state of the graphics object and should not be called when the graphics object cannot be updated. For example, if the Clear method is called on a secure desktop in a terminal server session, an ExternalException may occur, leaving the Graphics object in an inconsistent state.

معنی شو میدونم ولی مفهومش چیه؟ یعنی میگه کجاها نباید این متد فراخونی بشه؟ منظورش از فراخونی نشدن در دسکتاپ امن در فصل سرور پا
یه سئوال دیگه اینکه وقتی Transparent در فرم را رنگی مشخص کردیم و اون رنگ حذف شد و پشت زمینه ی فرم مشخص شد ، حالا از اون قسمت تو خالیِ فرم ، پنجره ی پشت اون را انتخاب میکنم ، باز فرم ام انتخاب میشه و به پنجره ی پشتی ، دسترسی ندارم . چجوری حل میشه؟
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعد اینکه فایل های Abr (فایل براش براس فتوشاپ) رو هم میشه بجای براش در رویداد paint استفاده کرد؟ اگه آره چجوری؟
بعد اینکه پیرو سئوال پست بالا ، اگه این قابلیت توی کلاس Graphic وجود داره که بخشی از گرافیک را با متد Clear پاک کرد ، در این صورت ، اولا کدش چجوری میشه و دوما آیا میشه جوری اون گرافیک (مثلا یه مستطیل که کشیدیم) رو پاک کرد که اگه در پس زمینه ی اون فرم ، عکسی (یا هر چیزی) به عنوان پشت زمینه بود ، اون عکس را پاک نکنه و فقط گرافیکِ روی اون عکس را پاک کنه؟ اگه آره ، اینم چجوری هه؟ بجای کد ، الگوریتم کلی و نامِ متدها و اعضای مورد نیاز از یک کلاس را بگین ، خودم پیگیری میکنم
ممنون
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
در رویداد Paint مربوط به فرم ، کد زیر چرا کار نمیکنه؟ (قسمت GraphicsPath را باید چجوری تغییر داد؟) :


کد:
            Brush brush =  Brushes.Red;
            GraphicsPath grPath = new GraphicsPath(new PointF[] { new PointF(0, 170), new PointF(100, 250)}, new byte[] { 16, 16} , FillMode.Winding);
            e.Graphics.FillRegion(brush, new Region(grPath));

کاربر یا خودتون به هر حال رسم کردن کد داره، توی همون کد Rectangle ای که رسم شده رو به یک متغیر تکی یا List بسپارید و بعدا خودتون رو برای پردازش تصویر برای پیدا کردن ابعاد به دردسر نندازید. یک List از نوع Rectangle بسازید و هر چی رسم کردید به اون مجموعه اضافه کنید. اون Rectangle ها یک Contains دارند که باهاش می توانید بفهمید ماوس الان داخل کادر شون هست یا نه.

یه سئوال دارم و اونم اینکه اگه کدی نوشتیم که کاربر با موس رسم کنه ، حالا چجوری میشه مختصات Rectangle اون شکلی را که با موس رسم کرد رو گرفت؟ هر چند میشه در رویداد MouseMove ، مختصات لحظه لحظه ی تغییرات را توی اعضای List ای از نوع Point ریخت ولی بدست آوردن Rectangle یا Bound ِ کلی شکلی که توسط موس توسط کاربر رسم شده، در این حالت یا حساب کردنش مشکل هه یا واسه ی من زیاد فکر کردن میخواد . الگوریتم و راه سریعتری هست؟
 

the_king

مدیرکل انجمن
حالا خود کلاس Graphic ، این قابلیت رو نداره که برای رسمِ گرافیک ، یه محدوده ی خاصی تعیین کنیم و در اون محدوده رسم کنیم؟ یا فقط در همون محدوده پاک (متد Clear) کنیم؟

به یک نکته توجه داشته باشید که در Graphics مفهوم پاک کردن در یک تصویر که پاک کردن جوهر از روی وایت بورد نیست، رنگ کردن مجدد ئه، اینه که با یک رنگی مثل Transparent محیط اش رو یکدست پر کنید. در گرافیک یک ماسک عمومی داریم به نام Clip یا Region. در Graphics هم ببینید SetClip داره، این همون ناحیه است که بعد از این رسم داخل فقط اون ناحیه اعمال میشه، پنجره ها هم این رو دارند، وقتی شما پنجره ای رو Invalidate می کنید، می توانید مشخص کنید که فقط یک ناحیه اش رسم مجدد بشه. این همون Clip ئه. و البته الزاما نیازی به Clear هم نیست، شما می توانید هر وقت خواستید یک Rectangle در نظر بگیرید و هر محیطی رو با FillRectangle پر کنید که البته Clip رو هم رعایت می کنه.

در توضیح (remark) متد Clear در graphic این را نوشته :

کد:
The Clear method clears the state of the graphics object and should not be called when the graphics object cannot be updated. For example, if the Clear method is called on a secure desktop in a terminal server session, an ExternalException may occur, leaving the Graphics object in an inconsistent state.

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

اون Graphics به یک Handle پنجره و DC یا Device Context ای که از سیستم عامل می گیره وابسته است، از اون منابع محدودیه که تا کارتون تموم شد، باید فورا پسش بدید، همزمان هم نمیشه دو روال جدا از پنجره ای DC بگیرند. برای همین هر لحظه قابل دسترسی نیست، نباید هم به عنوان متغیر سراسری نگهش دارید که الان ساختم و تا آخر برنامه هم همینطور دستم باشه، نه، هر وقت لازم شد همون لحظه بسازیدش و تا کارتون تموم شد فورا آزادش کنید. زمانی میشه داخلش رسم صورت بگیره که توسط روال دیگه ای قبضه نشده باشه، به اصطلاح Update پذیر باشه. مباحث گرافیک خیلی مفصله.

یه سئوال دیگه اینکه وقتی Transparent در فرم را رنگی مشخص کردیم و اون رنگ حذف شد و پشت زمینه ی فرم مشخص شد ، حالا از اون قسمت تو خالیِ فرم ، پنجره ی پشت اون را انتخاب میکنم ، باز فرم ام انتخاب میشه و به پنجره ی پشتی ، دسترسی ندارم . چجوری حل میشه؟
کدتون یه ایرادی داره. بصورت پیشفرض روال اینطوری نیست.
 

the_king

مدیرکل انجمن
بعد اینکه فایل های Abr (فایل براش براس فتوشاپ) رو هم میشه بجای براش در رویداد paint استفاده کرد؟ اگه آره چجوری؟
ساختار Brush فتوشاپ کجا و Brush در +GDI کجا، Brush فتوشاپ با زاویه قلم و موقعیت و انواع تنظیمات فشار و ... که با GDI+ جور در نمیاد. اگر کسی بیاد Brush فتوشاپ رو در NET. استفاده کنه یا باید همه روال رسم Brush فتوشاپ و فرمت abr اش رو پیاده سازی کرده باشه یا اصلا قید همه امکانات Brush رو زده باشه که دیگه چیز دیگه ای میشه.
بعد اینکه پیرو سئوال پست بالا ، اگه این قابلیت توی کلاس Graphic وجود داره که بخشی از گرافیک را با متد Clear پاک کرد ، در این صورت ، اولا کدش چجوری میشه و دوما آیا میشه جوری اون گرافیک (مثلا یه مستطیل که کشیدیم) رو پاک کرد که اگه در پس زمینه ی اون فرم ، عکسی (یا هر چیزی) به عنوان پشت زمینه بود ، اون عکس را پاک نکنه و فقط گرافیکِ روی اون عکس را پاک کنه؟ اگه آره ، اینم چجوری هه؟ بجای کد ، الگوریتم کلی و نامِ متدها و اعضای مورد نیاز از یک کلاس را بگین ، خودم پیگیری میکنم
ممنون
شما دارید Graphics رو مثل پروژه های فتوشاپ و Paint.NET لایه لایه تصور می کنید که یک مستطیل کشیده شده و بعد فرضا میاد یک خط روی اون در لایه دیگه ای رسم میکنه، اصلا اینطوری نیست، Graphics لایه لایه رسم نمی کنه، تک لایه است. همه چی هم Rasterize شده می کشه، وقتی متنی رو رسم می کنید پیکسلی میشه و میره پی کارش. دیگه بعدا نمیشه فونتش رو تغییر داد. پیکسل های مستطیل رو با پیکسل های خط ترکیب کرده و Rasterize شده. دیگه چیزی از متن و خط و مستطیل و Brush در اون نتیجه اثری نمی مونه، همه چی ترکیب شده در یک لایه زمینه. اصلا دیگه تفکیک پذیر نیست. برای همین میگم باید اطلاعات چیزی که رسم می کنید رو جدا نگهدارید. وقتی شما یک لایه رو از گرافیک فتوشاپ حذف می کنید تمامی لایه ها روی صفحه نمایش مجددا رسم میشه، شما هم وقتی یک شیء گرافیکی رو از رسم تون پاک می کنید باید همه رسم های زیرش رو مجددا رسم کنید، نه اینکه بتونید از Graphics بخواهید فلان خط رو از روی مستطیل زیرش حذف کنه.
 

the_king

مدیرکل انجمن
سلامی مجدد
در رویداد Paint مربوط به فرم ، کد زیر چرا کار نمیکنه؟ (قسمت GraphicsPath را باید چجوری تغییر داد؟) :


کد:
            Brush brush =  Brushes.Red;
            GraphicsPath grPath = new GraphicsPath(new PointF[] { new PointF(0, 170), new PointF(100, 250)}, new byte[] { 16, 16} , FillMode.Winding);
            e.Graphics.FillRegion(brush, new Region(grPath));
چه کاری انجام بده؟ دو تا نقطه بهش دادید و گقتید داخل نقطه ها رو رنگ کنه، نقطه که مساحت نداره. مساحت اش صفر ئه.
کد:
            Brush brush = Brushes.Red;
            GraphicsPath grPath = new GraphicsPath(FillMode.Winding);
            grPath.AddPolygon(new[] { new PointF(0, 170), new PointF(100, 250), new PointF(50, 50) });
            e.Graphics.FillRegion(brush, new Region(grPath));

یه سئوال دارم و اونم اینکه اگه کدی نوشتیم که کاربر با موس رسم کنه ، حالا چجوری میشه مختصات Rectangle اون شکلی را که با موس رسم کرد رو گرفت؟ هر چند میشه در رویداد MouseMove ، مختصات لحظه لحظه ی تغییرات را توی اعضای List ای از نوع Point ریخت ولی بدست آوردن Rectangle یا Bound ِ کلی شکلی که توسط موس توسط کاربر رسم شده، در این حالت یا حساب کردنش مشکل هه یا واسه ی من زیاد فکر کردن میخواد . الگوریتم و راه سریعتری هست؟
شما دارید برعکس به قضیه نگاه می کنید، وقتی شما با ماوس دارید رسم می کنید، رسم خود بخود که نمیشه، دارید کد می نویسید که رسم می کنه. کاربر که بدون کد شما چیزی نمیتونه رسم کنه. و با چی رسم می کنه؟ با نقطه. شما موقعیت اون نقطه ها رو ثبت خواهد کرد، بهم وصل کنید میشه مجموعه ای خطوط، میشه محیط اون شکل. که در Graphics و GraphicsPath هم هست، اسمش Polygon ئه، مجموعه ای از Point ها است که بهم وصل میشه.
و اصلا راه درست همونه که دونه دونه اشیاء رو از رو به زیر دونه دونه به اصطلاح Hit Test کنید که آیا Contains فلان موقعیت هستند یا نه. منطق اش هم اینه که شما وقتی زنبور رو روی گل دارید نقطه ای که با ماوس کلیک می کنید هم با کادر زنبور جور در میاد و هم گل. و چون زنبور بالاتر ئه شما کادر زنبور رو می گیرید وگرنه گل رو انتخاب می کردید. هیچ الگوریتمی بدون در نظر گرفتن این مساله ترتیب رو و زیر بودن که نمیتونه کار کنه. سرعت Contains هم اصلا کم نیست. خیلی سریعه. ویندوز ها دائم در حال همین Hit Test کردنه که ببینه ماوس کجا چیکار می کنه، اصلا روالش کند نیست، خیلی سریع ئه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
به یک نکته توجه داشته باشید که در Graphics مفهوم پاک کردن در یک تصویر که پاک کردن جوهر از روی وایت بورد نیست، رنگ کردن مجدد ئه، اینه که با یک رنگی مثل Transparent محیط اش رو یکدست پر کنید. در گرافیک یک ماسک عمومی داریم به نام Clip یا Region. در Graphics هم ببینید SetClip داره، این همون ناحیه است که بعد از این رسم داخل فقط اون ناحیه اعمال میشه، پنجره ها هم این رو دارند، وقتی شما پنجره ای رو Invalidate می کنید، می توانید مشخص کنید که فقط یک ناحیه اش رسم مجدد بشه. این همون Clip ئه. و البته الزاما نیازی به Clear هم نیست، شما می توانید هر وقت خواستید یک Rectangle در نظر بگیرید و هر محیطی رو با FillRectangle پر کنید که البته Clip رو هم رعایت می کنه.


اون Graphics به یک Handle پنجره و DC یا Device Context ای که از سیستم عامل می گیره وابسته است، از اون منابع محدودیه که تا کارتون تموم شد، باید فورا پسش بدید، همزمان هم نمیشه دو روال جدا از پنجره ای DC بگیرند. برای همین هر لحظه قابل دسترسی نیست، نباید هم به عنوان متغیر سراسری نگهش دارید که الان ساختم و تا آخر برنامه هم همینطور دستم باشه، نه، هر وقت لازم شد همون لحظه بسازیدش و تا کارتون تموم شد فورا آزادش کنید. زمانی میشه داخلش رسم صورت بگیره که توسط روال دیگه ای قبضه نشده باشه، به اصطلاح Update پذیر باشه. مباحث گرافیک خیلی مفصله.


کدتون یه ایرادی داره. بصورت پیشفرض روال اینطوری نیست.

آها ممنون
Clip و همینطور ResetClip ، خیلی کاربردی بود (بازم اگه میشه از این اعضای پر کاربرد و اینکه برای چه کاری میان ، معرفی کنین (در حد چند کلمه توضیح و در حد 4 تا 5 تا عضو مهمِ کلاس Graphic) ، ممنون میشم)
من با متد Clear ، با رنگ Transparent را که پاک میکنم ، کل اون گرافیک مربوط به اون شی را سیاه میکنه (یعنی پشت زمینه اش را نشون نمیده) . چی کار باید کنم وقتی پشت زمینه ی فرم ام که مثلا عکس بود و گرافیک جدیدی روش رسم کردم و حالا میخوام پاکش کنم ، عکسِ پشت زمینه مشکلی براش ایجاد نشه؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ساختار Brush فتوشاپ کجا و Brush در +GDI کجا، Brush فتوشاپ با زاویه قلم و موقعیت و انواع تنظیمات فشار و ... که با GDI+ جور در نمیاد. اگر کسی بیاد Brush فتوشاپ رو در NET. استفاده کنه یا باید همه روال رسم Brush فتوشاپ و فرمت abr اش رو پیاده سازی کرده باشه یا اصلا قید همه امکانات Brush رو زده باشه که دیگه چیز دیگه ای میشه.

شما دارید Graphics رو مثل پروژه های فتوشاپ و Paint.NET لایه لایه تصور می کنید که یک مستطیل کشیده شده و بعد فرضا میاد یک خط روی اون در لایه دیگه ای رسم میکنه، اصلا اینطوری نیست، Graphics لایه لایه رسم نمی کنه، تک لایه است. همه چی هم Rasterize شده می کشه، وقتی متنی رو رسم می کنید پیکسلی میشه و میره پی کارش. دیگه بعدا نمیشه فونتش رو تغییر داد. پیکسل های مستطیل رو با پیکسل های خط ترکیب کرده و Rasterize شده. دیگه چیزی از متن و خط و مستطیل و Brush در اون نتیجه اثری نمی مونه، همه چی ترکیب شده در یک لایه زمینه. اصلا دیگه تفکیک پذیر نیست. برای همین میگم باید اطلاعات چیزی که رسم می کنید رو جدا نگهدارید. وقتی شما یک لایه رو از گرافیک فتوشاپ حذف می کنید تمامی لایه ها روی صفحه نمایش مجددا رسم میشه، شما هم وقتی یک شیء گرافیکی رو از رسم تون پاک می کنید باید همه رسم های زیرش رو مجددا رسم کنید، نه اینکه بتونید از Graphics بخواهید فلان خط رو از روی مستطیل زیرش حذف کنه.

آها ممنون استاد علی
پس گرافیک رسم شده ، با پیکسل های زیرش عجین میشه و لایه ای جداگانه نیست و باید بعد از پاک کردن ، مجددا اون قسمت از گرافیک را که حذف کردیم ، پیکسل های زیرش را مجدادا رسم کنیم؟
ولی دو سئوال میمونه
اولا چرا مثل فتوشاپ و افترافکت ، گرافیک در سی شارپ را هم لایه لایه نکردن؟ این جوری خیلی راحت تره
دوم اینکه اگه بخوایم اطلاعاتِ دونه دونه یِ پیکسل هایِ رسم شده یِ زیرِ اون گرافیک را بگیریم (البته فرضا اگه رنگِ یکدست نباشه و فرضا مثل فتوشاپ ، عکس یا چیزِ رنگی ای زیرش باشه) تا زمان حذف اون گرافیک ، مجدادا رسم کنیم که خیلی اطلاعات ، و به طبع اون خیلی رم رو مصرف میکنه و بازگردونی شم شاید الگوریتم سخت و حداقل کلا سربار زیادی مصرف میکنه!
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
چه کاری انجام بده؟ دو تا نقطه بهش دادید و گقتید داخل نقطه ها رو رنگ کنه، نقطه که مساحت نداره. مساحت اش صفر ئه.

ممنون
کلا میخواستم با اون مثال ، کاربردِ GraphicsPath را بفهمم
 

the_king

مدیرکل انجمن
من با متد Clear ، با رنگ Transparent را که پاک میکنم ، کل اون گرافیک مربوط به اون شی را سیاه میکنه (یعنی پشت زمینه اش را نشون نمیده) . چی کار باید کنم وقتی پشت زمینه ی فرم ام که مثلا عکس بود و گرافیک جدیدی روش رسم کردم و حالا میخوام پاکش کنم ، عکسِ پشت زمینه مشکلی براش ایجاد نشه؟
محدودیت اساسی روال های رسم پنجره در ویندوز ئه، برنامه نویسان Flash و اونهایی که میخواستند ویدئو نیمه شفاف پخش کنند هم به همین محدودیت برمی خورند.
چنین چیزی در ذات Graphics و روتین های رسم عادی GDI و +GDI نیست که یک پنجره نیمه شفاف رسم بشه. Bitmap و Image نیمه شفاف داریم ولی پنجره ای که روش رسم نمیشه نه. دلیلش اینه که اون چیزی که به عنوان Transparent Mask اعمال می کنید، برای ساده تعریف کردن ناحیه شفاف Region اونطوری طراحی شده، واقعا ویندوز اینطوری با رنگ فرم ها کار نمی کنه، و به خود رسم داخل فرم کاری نداره، برای فرم یک Region جدید میسازه، با SetWindowRgn. که Mask اش هم Mono ئه یعنی یا 255 ویا 0 و مقادیر مابین اینها رو نداره، و نمیشه کناره های Anti-Aliased و نرم ساخت. اون پنجره های نیمه شفاف واقعی که در بعضی برنامه ها می بینید یا اون سایه اطراف فرم های ویندوز متد رسم متفاوتی دارند که 32 بیتی ئه. اون رسم که شما الان واقعا دارید انجام میدید 24 بیتی ئه و بایت مربوط به Mask اش همیشه 255 ئه. از ویندوز های 2000 به بعد این قابلیت اضافه شد که پنجره ها بتوانند یک لایه نیمه شفاف داشته باشند (شبیه اون سایه اطراف فرم ها) اما لازمه استفاده این قابلیت در رسم، بازنویسی روتین های رسم بود، چیزی که فرضا الان ذاتا در WPF هست و در GDI نیست. پیاده سازی میشه کرد ولی دشواره چون خیلی متد ها باید بازنویسی بشه. مادامی که از روتین های استاندارد GDI و +GDI استفاده بشه اینجور قابلیت های پنجره های نیمه شفاف بخوبی قابل اجرا نیست. قبلا نمونه برنامه Visual Basic در فروم نوشته بودم که همچین چیزی رو اجرا می کرد ولی خوب کلا چون روال های رسم خاصی میخواد کار ساده ای نیست. WPF چون ذاتا روال های رسم اش پشتیبانی اش می کنه ساده تره.
 

the_king

مدیرکل انجمن
اولا چرا مثل فتوشاپ و افترافکت ، گرافیک در سی شارپ را هم لایه لایه نکردن؟ این جوری خیلی راحت تره
گرافیک که متعلق به #C نیست، گرافیک ویندوز ئه. اولا چرا راحت تر باشه؟ سرعت رسم و پردازش تصویر چند لایه فتوشاپ به مراتب کند تر از سیستم های گرافیکی ساده تک لایه است که مناسب اغلب کاربرد های برنامه نویسان هم نیست. فرمی که بخواد با سرعت پردازش فتوشاپ طراحی بشه خیلی کند تر از اینی میشه که +GDI داره. فتوشاپ بر حسب نیازش جهت طراحی اونطوری چند لایه شده، یک مصرف عمومی هم نداره که بگیم همه کاربرد های گرافیکی در #C باید چند لایه باشند. ثانیا فتوشاپ و افترافکت نرم افزار های اختصاصی طراحی هستند، نه برنامه نویسی. اگر کسی بخواد کد یک برنامه طراحی سه بعدی رو بنویسه نباید توقع داشته باشه که روتین های استاندارد رسم در پنجره سه بعدی باشه. شما هستید که می خواهید یک برنامه با رسم چند لایه داشته باشید، این نیاز شخص شما است، کاربرد عمومی همه منظوره نداره.
#C یک زبان برنامه نویسی همه منظوره است، نه فرضا Engine بازی سازی یا فرضا Engine پردازش صوتی. زبان های برنامه نویسی همه منظوره از امکانات سیستم عامل استفاده می کنند، از خودشون Engine اختراع نمی کنند که بگن فلان جور باشه بهتره. فرمت فونت و رسم گرافیک و فرمت ویدئویی و صوتی و ... خودشون رو که ندارند. این چیزهایی که شما میگید کتابخانه است، نه امکانات زبان. هر کسی بنا به نیازش کتابخانه گرافیکی و صوتی و ... دلخواهش رو بکار می بره، اصلا ربطی به خود #C نداره. یکی با DirectX کار می کنه، یکی با OpenGL و ... اون و +GDI هم کتابخانه استاندارد Windows Forms ئه، در حد و نیاز برنامه های عادی ویندوز هم هست. این چیزهایی که شما میگید مناسب موتور های بازی سازی و انیمیشن سازی ئه و نیاز های اساسی طراحی دو بعدی سه بعدی ئه. کتابخانه ها و موتور خاص خودش رو هم لازم داره.
دوم اینکه اگه بخوایم اطلاعاتِ دونه دونه یِ پیکسل هایِ رسم شده یِ زیرِ اون گرافیک را بگیریم (البته فرضا اگه رنگِ یکدست نباشه و فرضا مثل فتوشاپ ، عکس یا چیزِ رنگی ای زیرش باشه) تا زمان حذف اون گرافیک ، مجدادا رسم کنیم که خیلی اطلاعات ، و به طبع اون خیلی رم رو مصرف میکنه و بازگردونی شم شاید الگوریتم سخت و حداقل کلا سربار زیادی مصرف میکنه!
اصلا متوجه نشدید من چی گفتم، شما لازم نیست اطلاعات چیزی رو از پیکسل های رسم شده بگیرید. اطلاعات هیچ چیزی رو. روی تصویر هر چیزی که باشه فرقی نمی کنه. قرار نیست پردازش اش کنید و چیزی ازش رو تفکیک کنید. شما وقتی یک نقطه روی تصویر اضافه می کنید به حافظه می سپارید که یک نقطه با رنگ فلان در موقعیت فلان رسم شد، نه اینکه بعدا تصویر رو زیر و رو کنید که ببینید اون نقطه کجا بوده، مگه شما وقتی روی یک رنگ با همون رنگ رسم کنید بعدا میشه تفکیک شون کرد؟ هیچ نرم افزاری اینطوری اطلاعات نمیتونه استخراج کنه که شما تصور می کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
ممنون استاد علی
توی رویداد MouseMove فرم ام اینو نوشتم :


کد:
        private void FormTest_MouseMove(object sender, MouseEventArgs e)
        {
            this.label1.Text = e.Location.ToString();

            using (Graphics gr = this.CreateGraphics())
            {
               
                gr.FillRectangle(Brushes.Red, new Rectangle(10, 200, 100, 100));
                Bitmap bitmap = new Bitmap(this.Width, this.Height, gr);
                Color color = bitmap.GetPixel(e.Location.X, e.Location.Y);

                this.label2.Text = color.ToString();
                this.label3.Text = this.Width+"    "+ this.Height+"\n"+ this.ClientSize.Width + "    " + this.ClientSize.Height;

            }
        }

ولی بخشی که رنگ قرمز کردم رو میخوام با متد GetPixel رنگ اش را بگیرم ، ولی موس را که هر جا میبرم (حتی روی رنگ قرمز) ، مشخصات رنگ را A=0 R=0 G=0 B=0 مینویسه! (متد CreateGraphic هم فعلا بماند چون با کلاس BufferedGraphics فعلا چندان آشنا نیستم)
کلا دلیل اش چیه و چجوری باید کد را تغییر بدم تا موس را هر کجا که روی فرم میبرم ، رنگِ اون پیکسلی را که موس ام روی اون پیکسل هت را نشون بده؟
ممنون
 

the_king

مدیرکل انجمن
سلام
ممنون استاد علی
توی رویداد MouseMove فرم ام اینو نوشتم :


کد:
        private void FormTest_MouseMove(object sender, MouseEventArgs e)
        {
            this.label1.Text = e.Location.ToString();

            using (Graphics gr = this.CreateGraphics())
            {
              
                gr.FillRectangle(Brushes.Red, new Rectangle(10, 200, 100, 100));
                Bitmap bitmap = new Bitmap(this.Width, this.Height, gr);
                Color color = bitmap.GetPixel(e.Location.X, e.Location.Y);

                this.label2.Text = color.ToString();
                this.label3.Text = this.Width+"    "+ this.Height+"\n"+ this.ClientSize.Width + "    " + this.ClientSize.Height;

            }
        }

ولی بخشی که رنگ قرمز کردم رو میخوام با متد GetPixel رنگ اش را بگیرم ، ولی موس را که هر جا میبرم (حتی روی رنگ قرمز) ، مشخصات رنگ را A=0 R=0 G=0 B=0 مینویسه! (متد CreateGraphic هم فعلا بماند چون با کلاس BufferedGraphics فعلا چندان آشنا نیستم)
کلا دلیل اش چیه و چجوری باید کد را تغییر بدم تا موس را هر کجا که روی فرم میبرم ، رنگِ اون پیکسلی را که موس ام روی اون پیکسل هت را نشون بده؟
ممنون
توضیح فنی اش خیلی طولانی ئه ولی بصورت ساده و خلاصه میتونم بگم که شما به Graphics باید به عنوان دسترسی رسم نگاه کنید، نه حافظه تصویری. Graphics از خودش حافظه نداره که از رسم قبلی چیزی یاد بمونه.
در یک Graphics رسم می کنید، ولی چیزی که رسم میشه در حافظه ای نگهش نمی دارید که بعدا بخواهید چیزی ازش استخراج کنید.
این مساله رو ساده تر هم می توانستید تجربه کنید، وقتی در رخداد Paint چیزی رو یکبار رسم کنید و دیگه بعدا نکنید چه اتفاقی می افته؟ به محض اینکه اون ناحیه Invalidate بشه پاک میشه. این بخاطر اینه که فقط رسم شده، به حافظه ای سپرده نمیشه، و البته به همین دلیل سرعت رسم بالاتره.
کلا این موردی که شما انجام دادید برعکس باید باشه، شما میایید بر اساس یک Graphics ای Bitmap موقتی میسازید که داخلش رسم کنید، بعد Bitmap چی میشه؟ نابود میشه. باید برعکس باشه، باید بر اساس Bitmap تون Graphics موقتی بسازید که اطلاعات Bitmap رو بعدا بتونید استفاده کنید. و نکته اینجاست که لزومی نداره Bitmap رو نمایش بدید تا با GetPixel کار کنید، می توانید بدون نمایش رنگ ازش بخوانید. و همچنین می توانید بار ها و مجزا با Graphic داخلش رسم کنید و به مرور تکمیل اش کنید.
کد:
        private Bitmap _bitmap;

        private void FormTest_MouseMove(object sender, MouseEventArgs e)
        {
            this.label1.Text = e.Location.ToString();
            Color color = _bitmap.GetPixel(e.Location.X, e.Location.Y);
            this.label2.Text = color.ToString();
            this.label3.Text = this.Width + "    " + this.Height + "\n" + this.ClientSize.Width + "    " + this.ClientSize.Height;
        }

        private void FormTest_Load(object sender, EventArgs e)
        {
            _bitmap = new Bitmap(this.Width, this.Height);
            using (var gr = Graphics.FromImage(_bitmap))
            {
                gr.FillRectangle(Brushes.Red, new Rectangle(10, 200, 100, 100));
            }
        }

        private void FormTest_Paint(object sender, PaintEventArgs e)
        {
            var rect = new Rectangle(0, 0, _bitmap.Width, _bitmap.Height);
            e.Graphics.DrawImage(_bitmap, rect, rect, GraphicsUnit.Pixel);
        }
 

جدیدترین ارسال ها

بالا