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

SajjadKhati

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


کد:
    public partial class FormTest : Form
    {

        private Bitmap BitmapForGraphic;
        private bool IsDrawGraphicFlag;
        private Dictionary<Point, Color> GetPixelColorDic;
        private Rectangle Rect;
        public FormTest()
        {
            InitializeComponent();
            this.BackgroundImage = new Bitmap(@"E:\Tasavir\Shahidan\1Hasan Ayat\Shahid Ayat.jpg");
            this.BitmapForGraphic = new Bitmap(this.Width, this.Height);
            Graphics AllOverGraphic = Graphics.FromImage(BitmapForGraphic);
            AllOverGraphic.DrawImage(this.BackgroundImage, new Point(0, 0));
            this.IsDrawGraphicFlag = false;
            this.GetPixelColorDic = new Dictionary<Point, Color>();
        }

     
        private void btnDraw_MouseUp(object sender, MouseEventArgs e)
        {
            Button button = ((Button)sender);
            if (e.Button == MouseButtons.Left)
            {
                this.IsDrawGraphicFlag = true;
                button.Text = "Erase";
            }
            else if (e.Button == MouseButtons.Right)
            {
                this.IsDrawGraphicFlag = false;
                button.Text = "Draw";
            }
            
        }

        private void FormTest_MouseMove(object sender, MouseEventArgs e)
        {
            if(e.Button == MouseButtons.Left)
            {
                if (this.IsDrawGraphicFlag == true)
                {
                    if (this.GetPixelColorDic.ContainsKey(e.Location) == false)
                    {
                        Color mainPixelColor = this.BitmapForGraphic.GetPixel(e.Location.X, e.Location.Y); // رنگ اون پیکسل از بیت مپ که برابر رنگ پشت زمینه ی همون پیکسل از فرم هست را قبل از رسم بگیره
                        this.GetPixelColorDic.Add(e.Location, mainPixelColor); // اون رنگ و همون مختصات اش را ذخیره کنه
                     
                        this.BitmapForGraphic.SetPixel(e.Location.X, e.Location.Y, Color.Green);
                        this.CreateGraphics().DrawImage(this.BitmapForGraphic, new Point(0, 0));
                    }
                 
                }
                else
                {

                }
            }
        }
    }

این کد کار میکنه
ولی اگه BackgroundImageLayout در پشت زمینه ی فرم را عوض کنم مثلا بخشی کد رو در متد سازنده در بالا به کد زیر تغییر بدم :


کد:
            this.BackgroundImage = new Bitmap(@"E:\Tasavir\Shahidan\1Hasan Ayat\Shahid Ayat.jpg");
            this.BackgroundImageLayout = ImageLayout.Stretch;

رسم میکنه ولی بلافاصله بعد از رسم ، scale در پشت زمینه تغییر میکنه (که احتمالا باید واسه این باشه که scale در پشت زمینه ی فرم و همینطور در شی BitmapForGraphic ، یکی نباشه) ولی چرا؟ من که دقیق هر دو رو هم اندازه گرفتم
چجوری باید درست کنم؟
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
در پست بالا ، کدِ بخشی از متد سازنده را به زیر تغییر دادم ، درست شد :


کد:
            this.BitmapForGraphic = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
            Graphics AllOverGraphic = Graphics.FromImage(BitmapForGraphic);
            AllOverGraphic.DrawImage(this.BackgroundImage, new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height));

خط اول که تقریبا مشخص بود که ClientSize باید میشد ولی چرا در خط سوم یعنی در متد AllOverGraphic.DrawImage ، باید کد this.ClientSize.Width, this.ClientSize.Height را (حالا توی شی Rectangle یا اورلودهای دیگه) اضافه کنم تا درست شه؟ مگه خودش بصورت پیش فرض ، ایمیجی که در آرگومان اولِ این متد ، یعنی آرگومان this.BackgroundImage مشخص شد را به همون اندازه ای که در آرگومانِ خط اول یعنی آرگومان new Bitmap(this.ClientSize.Width, this.ClientSize.Height); مشخص کردیم ، تعیین نمیکنه؟
ولی در رویداد FormTest_MouseMove چرا این کار رو نکردم ، کدش درست اجرا شد؟ یعنی قسمت زیر در کدِ پست بالا را دستکاری نکردم :

کد:
                        this.CreateGraphics().DrawImage(this.BitmapForGraphic, new Point(0, 0));
 
آخرین ویرایش:

the_king

مدیرکل انجمن
سلامی مجدد
در پست بالا ، کدِ بخشی از متد سازنده را به زیر تغییر دادم ، درست شد :


کد:
            this.BitmapForGraphic = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
            Graphics AllOverGraphic = Graphics.FromImage(BitmapForGraphic);
            AllOverGraphic.DrawImage(this.BackgroundImage, new Rectangle(0, 0, this.ClientSize.Width, this.ClientSize.Height));

خط اول که تقریبا مشخص بود که ClientSize باید میشد ولی چرا در خط سوم یعنی در متد AllOverGraphic.DrawImage ، باید کد this.ClientSize.Width, this.ClientSize.Height را (حالا توی شی Rectangle یا اورلودهای دیگه) اضافه کنم تا درست شه؟ مگه خودش بصورت پیش فرض ، ایمیجی که در آرگومان اولِ این متد ، یعنی آرگومان this.BackgroundImage مشخص شد را به همون اندازه ای که در آرگومانِ خط اول یعنی آرگومان new Bitmap(this.ClientSize.Width, this.ClientSize.Height); مشخص کردیم ، تعیین نمیکنه؟
ولی در رویداد FormTest_MouseMove چرا این کار رو نکردم ، کدش درست اجرا شد؟ یعنی قسمت زیر در کدِ پست بالا را دستکاری نکردم :

کد:
                        this.CreateGraphics().DrawImage(this.BitmapForGraphic, new Point(0, 0));
یادتون نره، شیء ای که Dispose داره مثل Graphics رو حتما Dispose کنید. حالا با using چه بهتر که اصولی تره. اما به هر حال Dispose کنید. لازمه.
بستگی داره که تصویر منبعش کجا باشه، چون Resolution مبدا و مقصد مهمه.
هر تصویری علاوه بر طول و عرض یک Resolution داره که بر حسب پیکسل بر اینچ ئه. مثلا 96 یا 150. اون bitmap.HorizontalResolution و bitmap.VerticalResolution رو ببینید.
موقع DrawImage کردن در حالت پیشفرض این Resolution ملاک قرار میگیره که طبیعتا اگر Resolution ها با Graphics مقصد یکسان نباشه، ابعاد رسم شده با اون Size پیکسلی یکی نمیشه.
بهترین کار همونه که خودتون ابعاد مبدا و مقصد رو صریحا مشخص کنید، حتی اون GraphicsUnit.Pixel رو تا دیگه Resolution ملاک نباشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
یادتون نره، شیء ای که Dispose داره مثل Graphics رو حتما Dispose کنید. حالا با using چه بهتر که اصولی تره. اما به هر حال Dispose کنید. لازمه.
بستگی داره که تصویر منبعش کجا باشه، چون Resolution مبدا و مقصد مهمه.
هر تصویری علاوه بر طول و عرض یک Resolution داره که بر حسب پیکسل بر اینچ ئه. مثلا 96 یا 150. اون bitmap.HorizontalResolution و bitmap.VerticalResolution رو ببینید.
موقع DrawImage کردن در حالت پیشفرض این Resolution ملاک قرار میگیره که طبیعتا اگر Resolution ها با Graphics مقصد یکسان نباشه، ابعاد رسم شده با اون Size پیکسلی یکی نمیشه.
بهترین کار همونه که خودتون ابعاد مبدا و مقصد رو صریحا مشخص کنید، حتی اون GraphicsUnit.Pixel رو تا دیگه Resolution ملاک نباشه.

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
آها فهمیدم
بهترین راه برای پاک کردن گرافیکِ رسم شده جوری که بک گراند مشخص بشه ، متد Invalidate هه . اونم آرگومانی به عنوان Rectangle داره به عنوان محدود کردن غیر معتبر سازیِ رسم (پاک کردن بخشی از رسم و گرافیک)
 

the_king

مدیرکل انجمن
آها ممنون استاد علی
میگم میخوام مثل نرم افزار paint ویندوز ، وقتی مداد پاک کن را انتخاب میکنم ، گرافیکی مربعی شکل به عنوان مداد پاک کن همراه م رسم بشه و هر جا موس میره ، اون مربع هم بره . کد این رو بلدم ولی مشکل اینجاست که پشت زمینه ی فرم ام چون عکس هست ، یا کلِ مربعِ مداد پاک کن پاک میشه یا اگه بخوام بخشی اش را پاک کنم ، باید رنگی بگم که با رنگ اون پیکسل ها از عکس پشت زمینه ، یکی باشه
میخواستم بگم سودوکد کلی شو میگین که باید مرحله به مرحله چی کار کنم؟
باید همون روشی که قبلا گفتین که قبل از رسم گرافیک ، اون پیکسل را توی متغییر سراسری ذخیره کنم ؛ از این روش باید برم؟ اگه از این روش بخوام برم ، اول باید یه بیت مپ بسازم که پشت زمینه ی فرم را توی این بیت مپ رسم کنم و بعد ، قبل از رسمِ دیگه ای ، رنگ و مختصاتِ اون پیکسلی را که میخوام روش رنگی یا چیزی را رسم کنم رو توی متغییر سراسری ای ذخیره کنم و بعد رسم های مختلف را فقط توی همون بیت مپ (نه اینکه توی شیِ بیت مپِ جدیدِ دیگه) انجام بدم و بعد هم هر وقت خواستم ، اون رنگ های ذخیره شده در متغییر سراسری را برگردونم؟ درسته؟ یعنی سودوکدِ کلی اش اینه یا روش دیگه ای هم هست؟ اگه روش بهتر و راحت تر (البته فعلا بدون استفاده از api ها) هست ، میگین؟
یک قاعده کلی هست، برای چیزی که امکانات سخت افزاری و نرم افزاری آماده هست دنبال پیاده سازی شخصی نگردید مگر اینکه دلیل موجهی برای بازنویسی اش باشه.
مثلا در این مورد Cursor بسازید، البته با نرم افزار های تخصصی طراحی Icon و Cursor چه بهتر. چون کاری که شما می خواهید انجام بدید وظیفه اصلی اش با Cursor ئه، کنترل ها Cursor دارند و هر لحظه هم تغییر پذیره. رسمش هم با بخش مخصوصش در سخت افزار کارت گرافیکی هست که سربار روی پردازنده و پروسه شما نداره و هم کد شما درگیر پاک کردن و رسم مجدد نمیشه، حالا خودتون کد شبیه ساز Cursor می نوشتید، باعث Flicker و پرپر زدن میشد یا نه بماند. و در مورد روال رسم کلا هر نرم افزاری گرافیکی رو بررسی کنید، یا قابلیت ابتدایی Undo داره، یا حتی قابلیت بهتری در حد مخفی و آشکار کردن موردی که قبلا رسم شده. برای هر دو مورد هیچ راهی نیست جز نگهداری اطلاعات چیزی که رسم میشه. به دو روش، یا اطلاعاتی که برای رسم مجدد دقیق اش کفایت کنه، فرضا رنگ و نقطه شروع و پایان خط رو نگه می دارید یا نگهداری اون نتیجه رسم بصورت یک لایه مجزا، مثلا در یک Bitmap با زمینه شفاف. و همه اون نرم افزار ها برای رسم مجدد تصویر از همین اطلاعات استفاده می کنند، راه فرار نداره که بگیم اطلاعات رسم رو نگه نداریم ولی بعدا بتونیم بهش رجوع کنیم. از طرف دیگه هر چقدر رسم بیشتر بشه هم حافظه بیشتری می بره و هم پردازش سنگین تر میشه، اینم باز راه فرار نداره. خیلی طبیعیه و گریز ناپذیر. در همه نرم افزار های گرافیکی هم این مساله رو می بینید. چیزی نیست که با کشف یک الگوریتم برای کد شما پیش نیاد. یا باید سوابق یکسری قبلی ها رو حذف کنید که دیگه تغییر ناپذیر می شوند، مثل Undo و History که یک محدودیتی داره، از حدی بیشتر شد قدیمی ترین رو حذف می کنه، یا به فایل جانبی متوسل بشید که فتوشاپ هم همین کار رو موقع کمبود حافظه RAM داره انجام میده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
یک قاعده کلی هست، برای چیزی که امکانات سخت افزاری و نرم افزاری آماده هست دنبال پیاده سازی شخصی نگردید مگر اینکه دلیل موجهی برای بازنویسی اش باشه.
مثلا در این مورد Cursor بسازید، البته با نرم افزار های تخصصی طراحی Icon و Cursor چه بهتر. چون کاری که شما می خواهید انجام بدید وظیفه اصلی اش با Cursor ئه، کنترل ها Cursor دارند و هر لحظه هم تغییر پذیره. رسمش هم با بخش مخصوصش در سخت افزار کارت گرافیکی هست که سربار روی پردازنده و پروسه شما نداره و هم کد شما درگیر پاک کردن و رسم مجدد نمیشه، حالا خودتون کد شبیه ساز Cursor می نوشتید، باعث Flicker و پرپر زدن میشد یا نه بماند. و در مورد روال رسم کلا هر نرم افزاری گرافیکی رو بررسی کنید، یا قابلیت ابتدایی Undo داره، یا حتی قابلیت بهتری در حد مخفی و آشکار کردن موردی که قبلا رسم شده. برای هر دو مورد هیچ راهی نیست جز نگهداری اطلاعات چیزی که رسم میشه. به دو روش، یا اطلاعاتی که برای رسم مجدد دقیق اش کفایت کنه، فرضا رنگ و نقطه شروع و پایان خط رو نگه می دارید یا نگهداری اون نتیجه رسم بصورت یک لایه مجزا، مثلا در یک Bitmap با زمینه شفاف. و همه اون نرم افزار ها برای رسم مجدد تصویر از همین اطلاعات استفاده می کنند، راه فرار نداره که بگیم اطلاعات رسم رو نگه نداریم ولی بعدا بتونیم بهش رجوع کنیم. از طرف دیگه هر چقدر رسم بیشتر بشه هم حافظه بیشتری می بره و هم پردازش سنگین تر میشه، اینم باز راه فرار نداره. خیلی طبیعیه و گریز ناپذیر. در همه نرم افزار های گرافیکی هم این مساله رو می بینید. چیزی نیست که با کشف یک الگوریتم برای کد شما پیش نیاد. یا باید سوابق یکسری قبلی ها رو حذف کنید که دیگه تغییر ناپذیر می شوند، مثل Undo و History که یک محدودیتی داره، از حدی بیشتر شد قدیمی ترین رو حذف می کنه، یا به فایل جانبی متوسل بشید که فتوشاپ هم همین کار رو موقع کمبود حافظه RAM داره انجام میده.

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

the_king

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

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلام
ممنون استاد علی
به الگوریتم بسیار کوچیک برای نقاشی (رسم با درگ کردن موس) نوشتم و الگوریتمِ رسم اش این بود که توی MouseMove با هر بار تغییر مکان موس ، در شیِ سراسری بیت مپ ، 4 پیکسلِ کنارِ همون پیکسلی که موس هست را رنگ آمیزی میکنه (چون تک پیکسلی رنگ کنه ، خیلی خط اش ریز میشه) . باز هم بماند با این الگوریتم ، اگه آروم موس را حرکت ندم ، توی رسم فاصله میندازه . حالا نمیدونم اگه قراره مثل برنامه ی paint ویندوز که حتی با تغییرِ سریع موس ، باز هم هیچ فاصله ای بین رسم نمیافته ، برای شبیه شدن اش ، باید خودم الگوریتمی بنویسم که فاصله و گپ ای که بین رنگ آمیزی پیکسل ها موقع جابجایی موس بوجود میاد را پر کنه یا اینکه کلا الگوریتمِ اساسی شون متفاوت هه . بعد با جابجاییِ هر باره ی موس ، که 4 پیکسلِ اطرافش رنگ آمیزی میشه را در دیکشنری Dictionary<Point, Rectangle> که Point همون مختصات خونه ی بالا و سمت چپِ مستطیلِ رسم شده و Rectangle هم که همین 4 پیکسلِ رسم شده هست را ذخیره میکنم . بعد اینها را در گرافیکِ فرم ، رسم میکنم
(اگه الگوریتمی بهتر از این برای رسم میدونین ، میگین تا این فاصله ایجاد نشه؟ منظورم کد دادن نیست . منظورم سودوکد و روش کلی کار هست) .

نکته ی مهمتر اینکه موقع پاک کردن (مثل برنامه ی paint ویندوز) ، پاک کنی در ابعاد 16 در 16 و هر جایی که موس میره ، ایجاد و میخوام با کلیک روی اون قسمت ، هر رسمی در اون محدوده ی 16 در 16 پیکسلی هست را پاک کنه . دو نوع الگوریتم به ذهنم میاد . راحت ترین اش اینه که در اون محیطِ نقاطِ درون پاک کن در بیت مپ ، دونه دونه پیکسل ها را چک کنم که اگه رنگِ هر پیکسل ، مخالفِ رنگِ Transparent بود ، رنگِ Transparent را توی اون نقطه از بیت مپ Set کنه و بعد (تغییراتِ) اون بیت مپ را در گرافیکِ فرم ، رسم کنه .
ولی این الگوریتم ، احتمالا در پروژه ای بزرگ تر ، طبعا باید مشکلاتی را به همراه داشته باشه و کلا اصولی نباشه (هر چند حدس میزنم) .
الگوریتم بعدی اینه که چک کنیم دونه دونه ی اون پیکسل های داخلیِ پاک کن (256 پیکسل) ، کدوم نقطه ی شون با کدوم نقطه ی تمام اعضای Dictionary مون یکی هست تا اون مستطیل را پیدا کنیم تا 4 پیکسلِ اون بیت مپ را Transparent و بعد در گرافیکِ فرم ، رسم کنیم که چون ممکنه اعضای Dictionary مون بسیار زیاد باشه ، کارایی برنامه را بسیار بسیار کند میکنه که به درد نمیخوره
الگوریتم بعدی اینه که هر پیکسل ، مخصوصا پیکسل های لبه ی محیط پاک کن را ، هر کدوم از این پیکسل ها را باز 8 پیکسلِ کناری شو چک کنیم (چون بخشی از مستطیلِ رسم شده ، ممکنه در بیرون از مستطیلِ پاک کن مون وجود داشته باشه در صورتی که ما فقط بخش مشترک شو میخوایم حذف کنیم) و بعد از پیدا شدن نقاط ، در Dictionary ، مستطیل مربوطه را گرفته و نقطه ی اشتراک شون را فقط حذف کنیم

ضمن اینکه در هر 3 الگوریتم ، بعد از حذفِ پیکسل ای داخل پاک کن (16 در 16) ، ممکنه بعضی از مستطیل ها از 4 پیکسل بودن خارج شن (چون ممکنه بخشی ازشون در محدوده ی پاک کن باشن که حفظ شده باشن پس باید اون بخش دیگه ای که موندن ، اندازه ی مستطیل شون اصلاح شن و دوباره در Dictionary ذخیره شن که باز این داستان و الگوریتم خودشو داره که زیاد به این الگوریتم فکر نکردم)

کلا بهترین سودوکدی که برای پاک کردن پیشنهاد میدین ، چیه؟
ممنون
 

the_king

مدیرکل انجمن
سلام
ممنون استاد علی
به الگوریتم بسیار کوچیک برای نقاشی (رسم با درگ کردن موس) نوشتم و الگوریتمِ رسم اش این بود که توی MouseMove با هر بار تغییر مکان موس ، در شیِ سراسری بیت مپ ، 4 پیکسلِ کنارِ همون پیکسلی که موس هست را رنگ آمیزی میکنه (چون تک پیکسلی رنگ کنه ، خیلی خط اش ریز میشه) . باز هم بماند با این الگوریتم ، اگه آروم موس را حرکت ندم ، توی رسم فاصله میندازه . حالا نمیدونم اگه قراره مثل برنامه ی paint ویندوز که حتی با تغییرِ سریع موس ، باز هم هیچ فاصله ای بین رسم نمیافته ، برای شبیه شدن اش ، باید خودم الگوریتمی بنویسم که فاصله و گپ ای که بین رنگ آمیزی پیکسل ها موقع جابجایی موس بوجود میاد را پر کنه یا اینکه کلا الگوریتمِ اساسی شون متفاوت هه . بعد با جابجاییِ هر باره ی موس ، که 4 پیکسلِ اطرافش رنگ آمیزی میشه را در دیکشنری Dictionary<Point, Rectangle> که Point همون مختصات خونه ی بالا و سمت چپِ مستطیلِ رسم شده و Rectangle هم که همین 4 پیکسلِ رسم شده هست را ذخیره میکنم . بعد اینها را در گرافیکِ فرم ، رسم میکنم
(اگه الگوریتمی بهتر از این برای رسم میدونین ، میگین تا این فاصله ایجاد نشه؟ منظورم کد دادن نیست . منظورم سودوکد و روش کلی کار هست) .
اصولا نقطه رسم نمیشه. خط کشیده میشه. حالا Line یا Bezier بستگی به خودتون داره. فاصله ایجاد میشه، چون نقطه می کشید. باید نقطه ها رو وصل کنید بهم.
نکته ی مهمتر اینکه موقع پاک کردن (مثل برنامه ی paint ویندوز) ، پاک کنی در ابعاد 16 در 16 و هر جایی که موس میره ، ایجاد و میخوام با کلیک روی اون قسمت ، هر رسمی در اون محدوده ی 16 در 16 پیکسلی هست را پاک کنه . دو نوع الگوریتم به ذهنم میاد . راحت ترین اش اینه که در اون محیطِ نقاطِ درون پاک کن در بیت مپ ، دونه دونه پیکسل ها را چک کنم که اگه رنگِ هر پیکسل ، مخالفِ رنگِ Transparent بود ، رنگِ Transparent را توی اون نقطه از بیت مپ Set کنه و بعد (تغییراتِ) اون بیت مپ را در گرافیکِ فرم ، رسم کنه .
ولی این الگوریتم ، احتمالا در پروژه ای بزرگ تر ، طبعا باید مشکلاتی را به همراه داشته باشه و کلا اصولی نباشه (هر چند حدس میزنم) .
الگوریتم بعدی اینه که چک کنیم دونه دونه ی اون پیکسل های داخلیِ پاک کن (256 پیکسل) ، کدوم نقطه ی شون با کدوم نقطه ی تمام اعضای Dictionary مون یکی هست تا اون مستطیل را پیدا کنیم تا 4 پیکسلِ اون بیت مپ را Transparent و بعد در گرافیکِ فرم ، رسم کنیم که چون ممکنه اعضای Dictionary مون بسیار زیاد باشه ، کارایی برنامه را بسیار بسیار کند میکنه که به درد نمیخوره
الگوریتم بعدی اینه که هر پیکسل ، مخصوصا پیکسل های لبه ی محیط پاک کن را ، هر کدوم از این پیکسل ها را باز 8 پیکسلِ کناری شو چک کنیم (چون بخشی از مستطیلِ رسم شده ، ممکنه در بیرون از مستطیلِ پاک کن مون وجود داشته باشه در صورتی که ما فقط بخش مشترک شو میخوایم حذف کنیم) و بعد از پیدا شدن نقاط ، در Dictionary ، مستطیل مربوطه را گرفته و نقطه ی اشتراک شون را فقط حذف کنیم

ضمن اینکه در هر 3 الگوریتم ، بعد از حذفِ پیکسل ای داخل پاک کن (16 در 16) ، ممکنه بعضی از مستطیل ها از 4 پیکسل بودن خارج شن (چون ممکنه بخشی ازشون در محدوده ی پاک کن باشن که حفظ شده باشن پس باید اون بخش دیگه ای که موندن ، اندازه ی مستطیل شون اصلاح شن و دوباره در Dictionary ذخیره شن که باز این داستان و الگوریتم خودشو داره که زیاد به این الگوریتم فکر نکردم)

کلا بهترین سودوکدی که برای پاک کردن پیشنهاد میدین ، چیه؟
ممنون
بجای اینکه نقاط رو با Dictionary نگهدارید یک Bitmap رو برای لایه رسم نگهدارید. برای پاک کردن از Bitmap هم CompositingMode رو در گرافیکی که بر اساس Bitmap میسازید SourceCopy کنید و با Brushes.Transparent و Pens.Transparent هر چی دایره و مربع بکشید و پر کنید ازش پاک میشه. اگه SourceOver بود چون Transparent ئه هیچ تاثیری نداشت ولی چون SourceCopy ئه خالیش می کنه.
اینکار روی پنجره و e.Graphics جواب نمیده چون بجای پاک شدن سیاه میشه ولی روی Bitmap ها جواب میده و پاک میشه.
 

SajjadKhati

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

بجای اینکه نقاط رو با Dictionary نگهدارید یک Bitmap رو برای لایه رسم نگهدارید. برای پاک کردن از Bitmap هم CompositingMode رو در گرافیکی که بر اساس Bitmap میسازید SourceCopy کنید و با Brushes.Transparent و Pens.Transparent هر چی دایره و مربع بکشید و پر کنید ازش پاک میشه. اگه SourceOver بود چون Transparent ئه هیچ تاثیری نداشت ولی چون SourceCopy ئه خالیش می کنه.
سلام
آها ممنون استاد علی
ولی نمیدونم پروپرتی CompositingMode به چه درد میخوره و کجاها کاربرد داره . مثلا مقدارش که روی SourceCopy باشه چی کار میکنه و کجاها کاربرد داره ویا اینکه روی SourceOver باشه
یه کم بیشتر درباره ی این پروپرتی میگین؟


اینکار روی پنجره و e.Graphics جواب نمیده چون بجای پاک شدن سیاه میشه ولی روی Bitmap ها جواب میده و پاک میشه.

آره قبلا این کار رو کردم و سیاه شد و چون کاربردش رو نمیدونستم ، واسه همین فکر الگوریتم جید که در پست بالا گفتم ، افتادم
ممنون
 

the_king

مدیرکل انجمن
سلام
آها ممنون استاد علی
ولی نمیدونم پروپرتی CompositingMode به چه درد میخوره و کجاها کاربرد داره . مثلا مقدارش که روی SourceCopy باشه چی کار میکنه و کجاها کاربرد داره ویا اینکه روی SourceOver باشه
یه کم بیشتر درباره ی این پروپرتی میگین؟
خیلی ساده است، وقتی رنگ W رو روی رنگ Z می کشید اگه SourceCopy باشه فقط رنگ W میشه، انگار نه انگار که زیرش رنگ دیگری بوده. جاهایی تاثیر داره که دو لایه رسم داره ترکیب میشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ممنون استاد علی
فعلا یه سئوال دیگه دارم
اینکه یه عکسی دارم (فایل jpg که با دوربین گرفتم) که بصورت 4:3 گرفتم (width اش کمتر از height اش هست) . width اش 3096 و height اش 4128 پیکسل هست
حالا این عکس رو توی شی ای از bitmap میریزم ولی نمیدونم چرا پروپرتی width و height مربوط به شی bitmap شو برعکس میگه . یعنی width مربوط به این شی bitmap برای این عکس رو مقدار 4128 و height اش رو هم مقدار 3096 نشون میده . ولی عکس هایی که بصورت 16:9 گرفته شد رو این شی بیت مپ (یا شی image) ، درست نشون میده
میشه اطلاعات واقعی (همون width و height ای که در پنجره ی properties در ویندوز برای اون عکس نشون میده) شو یه جوری متوجه شد؟ اگه آره ، چجوری میشه؟
یا اینکه حداقل به هر روش دیگه ای ، آیا جوری میشه فهمید که کدوم عکس فرمت 4:3 داره و کدوم فرمت 16:9 داره؟
ولی در کل مشکلم علاوه بر اونی که در خط بالا گفتم ، اینه که هر عکسی که فرمت 4:3 داره رو میخوام توی شی picturebox ای که پروپرتی SizeMode اش بجز مقدار Zoom داره نمایش بدم ، 90 درجه به سمت چپ میچرخونه و نشون میده
 
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
بعد اینکه توی متد سازنده ی کلاس GraphicsPath ، در آرگومان types اش که آرایه ای از byte ها را میگیره که این آرایه طبق توضیحاتش باید با مقادیر شمارشی PathPointType ، یکی باشن (با این حال نمیدونم چرا از همین نوع آرایه ای از PathPointType رو نخواستن و بجاش آرایه ای از byte ها خواستن!) ، در این آرایه ، فقط واسه ی من زمانی درست کار میکنه که همه ی نوع ها را از نوع Line یعنی مقدار 1 ، در ازای هر نقطه بگیرم وگرنه مقادیر دیگه مثل bezier که 3 و هر مقدار دیگه ای بگیرم ، کار نمیکنه
مقادیر دیگه رو چجوری باید درست کنم؟
بعد فرق FillMode.Winding و FillMode.Alternate در آرگومان بعدی چیه؟
 

the_king

مدیرکل انجمن
ممنون استاد علی
فعلا یه سئوال دیگه دارم
اینکه یه عکسی دارم (فایل jpg که با دوربین گرفتم) که بصورت 4:3 گرفتم (width اش کمتر از height اش هست) . width اش 3096 و height اش 4128 پیکسل هست
حالا این عکس رو توی شی ای از bitmap میریزم ولی نمیدونم چرا پروپرتی width و height مربوط به شی bitmap شو برعکس میگه . یعنی width مربوط به این شی bitmap برای این عکس رو مقدار 4128 و height اش رو هم مقدار 3096 نشون میده . ولی عکس هایی که بصورت 16:9 گرفته شد رو این شی بیت مپ (یا شی image) ، درست نشون میده
میشه اطلاعات واقعی (همون width و height ای که در پنجره ی properties در ویندوز برای اون عکس نشون میده) شو یه جوری متوجه شد؟ اگه آره ، چجوری میشه؟
یا اینکه حداقل به هر روش دیگه ای ، آیا جوری میشه فهمید که کدوم عکس فرمت 4:3 داره و کدوم فرمت 16:9 داره؟
ولی در کل مشکلم علاوه بر اونی که در خط بالا گفتم ، اینه که هر عکسی که فرمت 4:3 داره رو میخوام توی شی picturebox ای که پروپرتی SizeMode اش بجز مقدار Zoom داره نمایش بدم ، 90 درجه به سمت چپ میچرخونه و نشون میده
ربطی به Bitmap اش نداره، Bitmap اش همونه که نشون داده میشه، زاویه واقعی فایل عکس همونه. NET. و خیلی از Framework های دیگه کاری به اطلاعات جانبی مثل EXIF ندارند. در اون EXIF مواردی مثل زاویه عکسبرداری و مشخصات لنز و محل عکسبرداری و ... ثبت میشه. در EXIF فایل JPEG با orientation زاویه رو تصحیح کرده که در موقع نمایش Bitmap در نرم افزار های نمایش تصویر اعمال میشه، در NET. نادیده گرفته میشه.
دنبال یک کتابخانه بگردید که اطلاعات EXIF رو بخونه. البته هر JPEG ای الزاما اطلاعات EXIF نداره. برای مشخصات Properties هم قبلا گفتم از Microsoft Shell Controls and Automation استفاده کنید.
 

the_king

مدیرکل انجمن
بعد اینکه توی متد سازنده ی کلاس GraphicsPath ، در آرگومان types اش که آرایه ای از byte ها را میگیره که این آرایه طبق توضیحاتش باید با مقادیر شمارشی PathPointType ، یکی باشن (با این حال نمیدونم چرا از همین نوع آرایه ای از PathPointType رو نخواستن و بجاش آرایه ای از byte ها خواستن!) ، در این آرایه ، فقط واسه ی من زمانی درست کار میکنه که همه ی نوع ها را از نوع Line یعنی مقدار 1 ، در ازای هر نقطه بگیرم وگرنه مقادیر دیگه مثل bezier که 3 و هر مقدار دیگه ای بگیرم ، کار نمیکنه
مقادیر دیگه رو چجوری باید درست کنم؟
بعد فرق FillMode.Winding و FillMode.Alternate در آرگومان بعدی چیه؟
اون متد سازنده رو برای دریافت اطلاعات به اصطلاح RAW ساختن، نه اینکه شما اونجوری با بایت پر اش کنید. برای زمانی کاربرد داره که قبلا اطلاعات یک GraphicsPath رو فرضا در فایلی ذخیره شده دارید و حالا میخواهید از طریق اون بایت ها بازیابی بشه، نه اینکه اینطوری خودتون بایت ها رو دستی پر کنید. اصلا برای این منظور نیست که خودتون رو تو دردسر میندازید. یک GraphicsPath عادی بسازید و با Add تکمیلش کنید.
تو گرافیک کامپیوتری وقتی قراره داخل دو ناحیه تو در تو پر بشه دو منطق وجود داره، یکی اش همه رو پر می کنه، یکی هم فضای مشترک شون رو خالی می کنه.
IC534004.png images.png
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
ربطی به Bitmap اش نداره، Bitmap اش همونه که نشون داده میشه، زاویه واقعی فایل عکس همونه. NET. و خیلی از Framework های دیگه کاری به اطلاعات جانبی مثل EXIF ندارند. در اون EXIF مواردی مثل زاویه عکسبرداری و مشخصات لنز و محل عکسبرداری و ... ثبت میشه. در EXIF فایل JPEG با orientation زاویه رو تصحیح کرده که در موقع نمایش Bitmap در نرم افزار های نمایش تصویر اعمال میشه، در NET. نادیده گرفته میشه.
دنبال یک کتابخانه بگردید که اطلاعات EXIF رو بخونه. البته هر JPEG ای الزاما اطلاعات EXIF نداره. برای مشخصات Properties هم قبلا گفتم از Microsoft Shell Controls and Automation استفاده کنید.

ممنون استاد علی . درباره ی اون جواب تون هم ممنون
لطفا دقیقا بگین کدوم کلاس در Microsoft Shell Controls and Automation منظورتون هست که باهاش میشه اطلاعات یه فایل رو گرفت؟ چندین اینترفیس و کلاس داره . منظورتون اینه اعضای این Microsoft Shell Controls and Automation ، عضوی دارن که میشه باهاش aspect ratio ی فایل عکس را فهمید؟ کلا بیشتر راهنمایی کنین
اصطلاح EXIF رو هم تازه شنیدم . چیزی درباره اش نمیدونم :green: ولی توی این عکسی که گرفتم ، توی properties ویندوز اش ، مشخصات کامل از مدل گوشی تا میزان دیافراگم گوشی (دیافراگم کارش همون زوم کردن میشه؟:green:) و ... رو نوشته
بعد اینکه اگه در aspect ratio ی 4:3 ، اندازه یِ درستِ width اش 4128 باشه ، پس اولا چرا توی پروپرتیس ویندوز نوشته 3096 و دوما اینکه خوب مشخص هست چون دوربین عمودی عکس گرفت و aspect ratio ی 4:3 هست ، پس باید پیکسل های عرض اش از پیکسل های ارتفاع اش کمتر باشن . این طور نیست؟!
بعد اینکه چرا نمیشه از کلاس Shell32.ShellClass شی ساخت؟ یا حتی عضو استاتیک هم نداره که بشه ازش استفاده کرد. حتی فرزند هم نداره که از اون شی بسازیم . پس طریقه ی استفاده اش چجوری هه؟ و کلا این کلاس برای چی هه؟
 
آخرین ویرایش:

the_king

مدیرکل انجمن
ممنون استاد علی . درباره ی اون جواب تون هم ممنون
لطفا دقیقا بگین کدوم کلاس در Microsoft Shell Controls and Automation منظورتون هست که باهاش میشه اطلاعات یه فایل رو گرفت؟ چندین اینترفیس و کلاس داره . منظورتون اینه اعضای این Microsoft Shell Controls and Automation ، عضوی دارن که میشه باهاش aspect ratio ی فایل عکس را فهمید؟ کلا بیشتر راهنمایی کنین
اصطلاح EXIF رو هم تازه شنیدم . چیزی درباره اش نمیدونم :green: ولی توی این عکسی که گرفتم ، توی properties ویندوز اش ، مشخصات کامل از مدل گوشی تا میزان دیافراگم گوشی (دیافراگم کارش همون زوم کردن میشه؟:green:) و ... رو نوشته
بعد اینکه اگه در aspect ratio ی 4:3 ، اندازه یِ درستِ width اش 4128 باشه ، پس اولا چرا توی پروپرتیس ویندوز نوشته 3096 و دوما اینکه خوب مشخص هست چون دوربین عمودی عکس گرفت و aspect ratio ی 4:3 هست ، پس باید پیکسل های عرض اش از پیکسل های ارتفاع اش کمتر باشن . این طور نیست؟!
بعد اینکه چرا نمیشه از کلاس Shell32.ShellClass شی ساخت؟ یا حتی عضو استاتیک هم نداره که بشه ازش استفاده کرد. حتی فرزند هم نداره که از اون شی بسازیم . پس طریقه ی استفاده اش چجوری هه؟ و کلا این کلاس برای چی هه؟
راهنمای استفاده شو باید مطالعه کنید، نه اینکه کلاس هاش رو بررسی کنید ببینید از کدوم میتوانید شیء بسازید. کی می خواهید این مساله رو بپذیرید که روال یادگیری تون اشتباهه؟
بارها گفتم که با آزمون و خطا نمی توانید با این چیزها کار کنید. یک ماه هم روی Shell32 با آزمون خطا کار کنید اندازه یکروز مطالعه مستنداتش چیزی دستگیرتون نمیشه. همه ساختار Shell32 هم برای استفاده شما در NET. نیست.
باید مستنداتش رو مطالعه کنید و بر اساس مثال هاش بکار ببرید، نه اینکه هی دونه دونه از کلاس ها شی بسازید و ببینید چیکار می کنه. در مورد بقیه کتابخانه ها و NET. هم همینه.
کارکرد سنسور دوربین ربطی به زاویه دوربین نداره، تصویر خروجی هم همینطور. به همین دلیل دوربین بر عکس هم که گرفته بشه خروجی Bitmap برعکسه. اینکه در اسلاید یا پلیر درست نشون داده میشه به واسطه استفاده از اطلاعات جانبی ئه فایل ئه. نسبت 4:3 یا 16:9 هم مشخصات کلی ئه، تعیین نمی کنه در عکس و فیلم Width کدومه و Height کدومه. شما وقتی در گوشی فیلم و عکس می گیرید می توانید هم طوری بگیرید که Width اش بیشتر باشه یا Height اش. اینکه کج دیده میشه مربوط به تفسیر محتوا است، ربطی به خروجی سنسور نداره. سنسور که مستقل از بدنه نمی چرخه. هر طور بگیرید همونطور سنسور خروجی میده که روی فایل هم ثبت میشه.
کد:
  private void Form1_Load(object sender, EventArgs e)
  {
            Size = new Size(400, 600);
            var path = @"E:\Camera\112456.jpg";
            var grid = new DataGridView() { Dock = DockStyle.Fill, ReadOnly = true, RowHeadersVisible = false, Parent = this, AllowUserToAddRows = false };
            grid.Columns.Add("Name", "Name");
            grid.Columns.Add("ID", "ID");
            grid.Columns.Add("Value", "Value");
            grid.Columns["ID"].Width = 60;
            grid.Columns["Name"].Width = 150;
            grid.Columns["Value"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            var shellAppType = Type.GetTypeFromProgID("Shell.Application");
            var shell = Activator.CreateInstance(shellAppType);
            var folderPath = System.IO.Path.GetDirectoryName(path);
            var folder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod
                , null, shell, new object[] { folderPath });
            var folderItem = folder.ParseName(System.IO.Path.GetFileName(path));
            for (var i = 0; i < 10000; i++)
            {
                var columnName = folder.GetDetailsOf(null, i);
                if (string.IsNullOrEmpty(columnName) == false)
                {
                    grid.Rows.Add(columnName, i, folder.GetDetailsOf(folderItem, i));
                }
            }
  }
برای هر کاربردی ID ستون دلخواه تون رو جایی ثبت کنید که بعدا مستقیما شماره اش رو بدید، بصورت کلی مستند سازی نشده و استاندارد خاصی هم نداره، هر فرمت فایلی از ID های خاصی پشتیبانی می کنه که بستگی به کتابخانه و نرم افزاری داره که اون اطلاعات رو برای Shell استخراج می کنه. بجز یکسری فیلد های عمومی بقیه توسط مایکروسافت تعیین نشده که جایی دنبال لیست کاملش بگردید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
راهنمای استفاده شو باید مطالعه کنید، نه اینکه کلاس هاش رو بررسی کنید ببینید از کدوم میتوانید شیء بسازید. کی می خواهید این مساله رو بپذیرید که روال یادگیری تون اشتباهه؟
بارها گفتم که با آزمون و خطا نمی توانید با این چیزها کار کنید. یک ماه هم روی Shell32 با آزمون خطا کار کنید اندازه یکروز مطالعه مستنداتش چیزی دستگیرتون نمیشه. همه ساختار Shell32 هم برای استفاده شما در NET. نیست.
باید مستنداتش رو مطالعه کنید و بر اساس مثال هاش بکار ببرید، نه اینکه هی دونه دونه از کلاس ها شی بسازید و ببینید چیکار می کنه. در مورد بقیه کتابخانه ها و NET. هم همینه.
کارکرد سنسور دوربین ربطی به زاویه دوربین نداره، تصویر خروجی هم همینطور. به همین دلیل دوربین بر عکس هم که گرفته بشه خروجی Bitmap برعکسه. اینکه در اسلاید یا پلیر درست نشون داده میشه به واسطه استفاده از اطلاعات جانبی ئه فایل ئه. نسبت 4:3 یا 16:9 هم مشخصات کلی ئه، تعیین نمی کنه در عکس و فیلم Width کدومه و Height کدومه. شما وقتی در گوشی فیلم و عکس می گیرید می توانید هم طوری بگیرید که Width اش بیشتر باشه یا Height اش. اینکه کج دیده میشه مربوط به تفسیر محتوا است، ربطی به خروجی سنسور نداره. سنسور که مستقل از بدنه نمی چرخه. هر طور بگیرید همونطور سنسور خروجی میده که روی فایل هم ثبت میشه.
کد:
  private void Form1_Load(object sender, EventArgs e)
  {
            Size = new Size(400, 600);
            var path = @"E:\Camera\112456.jpg";
            var grid = new DataGridView() { Dock = DockStyle.Fill, ReadOnly = true, RowHeadersVisible = false, Parent = this, AllowUserToAddRows = false };
            grid.Columns.Add("Name", "Name");
            grid.Columns.Add("ID", "ID");
            grid.Columns.Add("Value", "Value");
            grid.Columns["ID"].Width = 60;
            grid.Columns["Name"].Width = 150;
            grid.Columns["Value"].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
            var shellAppType = Type.GetTypeFromProgID("Shell.Application");
            var shell = Activator.CreateInstance(shellAppType);
            var folderPath = System.IO.Path.GetDirectoryName(path);
            var folder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod
                , null, shell, new object[] { folderPath });
            var folderItem = folder.ParseName(System.IO.Path.GetFileName(path));
            for (var i = 0; i < 10000; i++)
            {
                var columnName = folder.GetDetailsOf(null, i);
                if (string.IsNullOrEmpty(columnName) == false)
                {
                    grid.Rows.Add(columnName, i, folder.GetDetailsOf(folderItem, i));
                }
            }
  }
برای هر کاربردی ID ستون دلخواه تون رو جایی ثبت کنید که بعدا مستقیما شماره اش رو بدید، بصورت کلی مستند سازی نشده و استاندارد خاصی هم نداره، هر فرمت فایلی از ID های خاصی پشتیبانی می کنه که بستگی به کتابخانه و نرم افزاری داره که اون اطلاعات رو برای Shell استخراج می کنه. بجز یکسری فیلد های عمومی بقیه توسط مایکروسافت تعیین نشده که جایی دنبال لیست کاملش بگردید.

ممنون استاد علی
منظورم این بود که بگین با کدوم عضو (کلاس یا اینترفیس و ...) از Shell32.dll باید کار کنم تا خودم اعضای اون کلاس و مستنداتش رو بررسی کنم و (مستندات اغلب اعضا رو میبینم یا اینکه آموزش یا مقاله ی فارسی شون رو چک میکنم . حالا متوجه شدن یا نشدنم از اون مستندات انگلیسی یا آموزش و مقاله ی فارسی ، یه قضیه ی دیگه هست)

ممنون از کدتون . من خیلی دست و پا شکسته متوجه ی این تیکه از کدتون شدم (مثلا 20 درصد متوجه شدم ) :


کد:
            var shellAppType = Type.GetTypeFromProgID("Shell.Application");
            var shell = Activator.CreateInstance(shellAppType);
            MessageBox.Show(shell.ToString());
            var folderPath = System.IO.Path.GetDirectoryName(path);
            var folder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod
                , null, shell, new object[] { folderPath });
            var folderItem = folder.ParseName(System.IO.Path.GetFileName(path));
            for (var i = 0; i < 10000; i++)
            {
                var columnName = folder.GetDetailsOf(null, i);
                if (string.IsNullOrEmpty(columnName) == false)
                {
                    grid.Rows.Add(columnName, i, folder.GetDetailsOf(folderItem, i));
                }
            }

از آرگومان متد Type.GetTypeFromProgID یعنی مقدار "Shell.Application" گرفته تا متغییر shell که از نوع system.__comobject هست که زیاد نمیشناسمش (پیگیری کردم ولی زیاد چیزی دستگیرم نشد) . همینطور از متد shellAppType.InvokeMember (که همون Type.InvokeMember باشه) و آرگومان هاش مخصوصا 2 تا آرگومان آخر ، زیاد متوجه نشدم
 

the_king

مدیرکل انجمن
ممنون استاد علی
منظورم این بود که بگین با کدوم عضو (کلاس یا اینترفیس و ...) از Shell32.dll باید کار کنم تا خودم اعضای اون کلاس و مستنداتش رو بررسی کنم و (مستندات اغلب اعضا رو میبینم یا اینکه آموزش یا مقاله ی فارسی شون رو چک میکنم . حالا متوجه شدن یا نشدنم از اون مستندات انگلیسی یا آموزش و مقاله ی فارسی ، یه قضیه ی دیگه هست)

ممنون از کدتون . من خیلی دست و پا شکسته متوجه ی این تیکه از کدتون شدم (مثلا 20 درصد متوجه شدم ) :


کد:
            var shellAppType = Type.GetTypeFromProgID("Shell.Application");
            var shell = Activator.CreateInstance(shellAppType);
            MessageBox.Show(shell.ToString());
            var folderPath = System.IO.Path.GetDirectoryName(path);
            var folder = (Shell32.Folder)shellAppType.InvokeMember("NameSpace", System.Reflection.BindingFlags.InvokeMethod
                , null, shell, new object[] { folderPath });
            var folderItem = folder.ParseName(System.IO.Path.GetFileName(path));
            for (var i = 0; i < 10000; i++)
            {
                var columnName = folder.GetDetailsOf(null, i);
                if (string.IsNullOrEmpty(columnName) == false)
                {
                    grid.Rows.Add(columnName, i, folder.GetDetailsOf(folderItem, i));
                }
            }

از آرگومان متد Type.GetTypeFromProgID یعنی مقدار "Shell.Application" گرفته تا متغییر shell که از نوع system.__comobject هست که زیاد نمیشناسمش (پیگیری کردم ولی زیاد چیزی دستگیرم نشد) . همینطور از متد shellAppType.InvokeMember (که همون Type.InvokeMember باشه) و آرگومان هاش مخصوصا 2 تا آرگومان آخر ، زیاد متوجه نشدم
تا مستندات Shell رو مطالعه نکنید خیلی متوجه نمیشید، اما کلا باید Type کلاس دلخواه تون رو بدانید تا داخل #C ازش شیء بسازید. اگه Type مورد نظر در Type Library اون کتابخانه COM باشه که در NET. هم لیست می شه و میبینید و مثل همون Shell32.Folder قابل استفاده است، اما اگر مثل Shell.Application نباشه، مجبور می شوید که راهی به NET. نشان بدهید که Type را از آنجا بخواند. و این Type توسط اسمی به نام ProgID مشخص میشه که مربوط به COM ئه و در ویندوز به ثبت رسیده. کتابخانه COM ای که در Registry ویندوز به ثبت رسیده همچین چیزی داره. و Shell.Application اسمی است که باید بهش رجوع بشه و مربوط به مستندات Shell ئه. باید برای بدست آوردن نوع (Type) کلاسی که Shell برای ساختن اشیاء ای مثل Folder بکار می بره، این ProgID رو به اون Type.GetTypeFromProgID بدهید و Type رو تحویل بگیرید. حالا با استفاده از Activator.CreateInstance می توانید از اون Type شیء جدید از نوع Shell.Application بسازید، شبیه عملکرد new ئه، اما بر اساس Type عمل می کنه. حالا یک شیء ساختید که کامپایلر نمیدونه متد هاش چیه، چون Type ناشناخته است و چیزی ئه که با GetTypeFromProgID در زمان اجرا میسازید و اون موقع معلوم میشه. ولی شما باید بدونید چون مستنداتش رو خوندید. با InvokeMember اون متد Shell.NameSpace داخلش شیء رو اجرا می کنید تا یک شی Folder ساخته بشه.
 

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

بالا