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

SajjadKhati

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

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

خیلی ممنون
بله اون کد را متوجه شدم . ممنون
منظورم از اینکه گاها بجای Invalidate ، کلمه ی رسم را بکار بردم ، منظورم خودِ رسم نیست . :green: مثل اون قضیه ی معلم معروف فارسی میمونه که به شاگردش میگفت من میگم اَنِف تو نگو اَنِف ؛ تو بگو اَنِف (همون الف) .
متوجه شدم که Invalidate ، رسم نیست و فقط ابطال هست . رسم رو هر وقت که دوست داشت انجام میده (اما با متد اجرای متد Update ، میگه همون لحظه رسم را انجام بده) .
من منظورم اینه که وقتی متد Invalidate را فراخونی کردیم ، همه شون توی صف میرن دیگه (اگه برداشتم از گفته ی تون اشتباه نباشه) بعد هم به طبع ، رسم های مربوط به اون کنترل هایی که Invalidate کردیم هم باید به ترتیب توی همون صف باشن (یعنی به ترتیب ، هر کنترلی که زودتر از بقیه ی کنترل ها Invalidate شد ، زمانی که میخواد رسمِ مربوط به اون کنترل انجام بشه هم زودتر از بقیه ی کنترل ها انجام میشه) . با فراخونی متد Update هم که گفتین هر چی توی صف هست ، به ترتیب اجرا میشه . پس باید رسم در صف ها هم به ترتیب اجرا بشه.
 

the_king

مدیرکل انجمن
خیلی ممنون
بله اون کد را متوجه شدم . ممنون
منظورم از اینکه گاها بجای Invalidate ، کلمه ی رسم را بکار بردم ، منظورم خودِ رسم نیست . :green: مثل اون قضیه ی معلم معروف فارسی میمونه که به شاگردش میگفت من میگم اَنِف تو نگو اَنِف ؛ تو بگو اَنِف (همون الف) .
متوجه شدم که Invalidate ، رسم نیست و فقط ابطال هست . رسم رو هر وقت که دوست داشت انجام میده (اما با متد اجرای متد Update ، میگه همون لحظه رسم را انجام بده) .
من منظورم اینه که وقتی متد Invalidate را فراخونی کردیم ، همه شون توی صف میرن دیگه (اگه برداشتم از گفته ی تون اشتباه نباشه) بعد هم به طبع ، رسم های مربوط به اون کنترل هایی که Invalidate کردیم هم باید به ترتیب توی همون صف باشن (یعنی به ترتیب ، هر کنترلی که زودتر از بقیه ی کنترل ها Invalidate شد ، زمانی که میخواد رسمِ مربوط به اون کنترل انجام بشه هم زودتر از بقیه ی کنترل ها انجام میشه) . با فراخونی متد Update هم که گفتین هر چی توی صف هست ، به ترتیب اجرا میشه . پس باید رسم در صف ها هم به ترتیب اجرا بشه.
هر چی که تو صف هست نه، رسمی که تو صف پنجره کنترل خودتون تون هست. Update شدن کنترل پنجره شما که ربطی به صف درخواست رسم سایر پنجره ها نداره. پنجره والد از Update شدن کنترل شما تاثیری نمیگیره.
به این نکته توجه کنید که base.OnEnabledChanged داره کنترل شما رو Update میکنه، نه پنجره والد رو. اون چیزی که base.OnEnabledChanged داره وادار به رسم فوری میکنه پنجره کنترل شما است، اونم زمانی که پنجره والد Invalidate شده و درخواست رسم دریافت کرده ولی هنوز رسم اش رو انجام نداده.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون
چجوری میشه متوجه شد که کنترلی ، در پشتِ کنترل دیگه قرار داره یا نه؟
میخوام مثلا یه کنترلی را چک کنم که آیا این کنترل در جلوی کنترلم قرار داره یا در پشت اش ؟ منظورم این نیست که چک کنم از لحاظ Bound ، داخل محوطه ی کنترلم وجود داره یا نه . منظورم اینه که از لحاظ Front یا Back بودن نسبت به کنترلم ، چجوری میشه چک کرد که جلوش هست یا نیست؟ (حال نمیدونم به این Front یا Back بودن ، z-order میگن یا نه . حالا من میگم) .
کلا منظورم اینه که یه کنترلی داریم ؛ و یه کنترل دیگه ای را بهمون میدن و میگن چک کن آیا این کنترل ، از لحاظ z-order جلوی کنترل مون هست یا پشتِ سرِ کنترمون قرار داره . چی کار باید کنیم؟
 

the_king

مدیرکل انجمن
خیلی ممنون
چجوری میشه متوجه شد که کنترلی ، در پشتِ کنترل دیگه قرار داره یا نه؟
میخوام مثلا یه کنترلی را چک کنم که آیا این کنترل در جلوی کنترلم قرار داره یا در پشت اش ؟ منظورم این نیست که چک کنم از لحاظ Bound ، داخل محوطه ی کنترلم وجود داره یا نه . منظورم اینه که از لحاظ Front یا Back بودن نسبت به کنترلم ، چجوری میشه چک کرد که جلوش هست یا نیست؟ (حال نمیدونم به این Front یا Back بودن ، z-order میگن یا نه . حالا من میگم) .
کلا منظورم اینه که یه کنترلی داریم ؛ و یه کنترل دیگه ای را بهمون میدن و میگن چک کن آیا این کنترل ، از لحاظ z-order جلوی کنترل مون هست یا پشتِ سرِ کنترمون قرار داره . چی کار باید کنیم؟
همون Z-Order ئه.
اگر والد هر دو شون یکی باشه، می توانید از GetNextWindow استفاده کنید که فرضا ببینید چه کنترل هایی جلوی (یا عقب) پنجره کنترل شما است که اگر اون یکی کنترل شامل شون نباشه نتیجه میگیرید که پس حتما پشت (یا جلو) اش قرار داره. اما اگر والد شون یکی نیست، دو حالت داره. یا یکی شون فرزند، نوه یا نتیجه دیگری است که خوب مشخصه کدوم پیش اون یکی قرار داره، یا والد مستقلی دارند، که باید همین بررسی رو از ابتدا برای ترتیب قرار گیری والد ها شون انجام بدید، یعنی بجای خود پنجره ها، وضعیت والد هاشون رو نسبت به هم بررسی کنید.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
همون Z-Order ئه.
اگر والد هر دو شون یکی باشه، می توانید از GetNextWindow استفاده کنید که فرضا ببینید چه کنترل هایی جلوی (یا عقب) پنجره کنترل شما است که اگر اون یکی کنترل شامل شون نباشه نتیجه میگیرید که پس حتما پشت (یا جلو) اش قرار داره. اما اگر والد شون یکی نیست، دو حالت داره. یا یکی شون فرزند، نوه یا نتیجه دیگری است که خوب مشخصه کدوم پیش اون یکی قرار داره، یا والد مستقلی دارند، که باید همین بررسی رو از ابتدا برای ترتیب قرار گیری والد ها شون انجام بدید، یعنی بجای خود پنجره ها، وضعیت والد هاشون رو نسبت به هم بررسی کنید.

سلامی مجدد
خیلی ممنون استاد علی.
GetNextWindow که ماکرو هست . انگار نمیشه استفاده کرد .
از GetWindow استفاده کردم اما چند تا مشکل داره (فرض کنید کنترل a داریم و در جلوش کنترل b داریم و باز در جلوی کنترل b ، دو کنترل c و d داریم . همه ی اینا درون یه کنترل والد که panel باشه ، هستن .) :

اول اینکه کنترلی که در پشتِ یه کنترل دیگه قرار هست را بگیرم (یعنی قصد گرفتن کنترل a در بالا را دارم) . یعنی در آرگومان اول تابع GetWindow ، هندل کنترل b و در آرگومان دومش مقدار GW_HWNDNEXT را که میدم ، این فقط یه کنترلی که پشتش قرار داره را بهم میده که همون کنترل والد یعنی panel را بهم برمیگردونه.

دوم اینکه کنترلی که در جلوی کنترلِ دیگه هست را یخوام بگیرم (یعنی قصد گرفتن کنترل c و d را دارم) . یعنی در آرگومان اول تابع GetWindow ، باز هم هندل کنترل b و در آرگومان دومش مقدار GW_HWNDPREV را که میدم ، این باز هم فقط یک کنترلی که جلوش قرار داره را بهم برمیگردونه . یعنی فقط کنترل c را بهم برمیگردونه .
کلا مشکل اینه که اگه چند تا کنترل در جلو باشن ، فقط یک کنترل از اون را برمیگردونه (توی حلقه هم بذاریم ، فرقی نداره) و اگه چند تا کنترل در عقب باشن ، باز هم فقط یک کنترل از اون را برمیگردونه.
چجوری باید حلش کرد؟
چون من نمیتونم آرگومان اولِ تابع را تغییر بدم . چون نسبت به یه کنترل ، کنترل هایِ جلوی اون یا کنترل هایِ عقب اون (نه فقط یک تک کنترل بلکه همه ی کنترل های جلو یا عقب اون) را میخوام.

مشکل سوم هم اینه که توی قسمت Remarks از توضیحات این تابع ، دقیق متوجه نشدم چی میگه . انگار میگه اگه این تابع توی حلقه قرار بگیره ، ممکنه حلقه گیر کنه و بینهایت اجرا بشه . من توی حلقه گذاشتم ، مشکلی ندیدم . جز همین قضیه ی بالا که باز هم یه کنترل را برمیگردونه.

خیلی ممنون
 

the_king

مدیرکل انجمن
سلامی مجدد
خیلی ممنون استاد علی.
GetNextWindow که ماکرو هست . انگار نمیشه استفاده کرد .
از GetWindow استفاده کردم اما چند تا مشکل داره (فرض کنید کنترل a داریم و در جلوش کنترل b داریم و باز در جلوی کنترل b ، دو کنترل c و d داریم . همه ی اینا درون یه کنترل والد که panel باشه ، هستن .) :
همونه، در ابزار ApiViewer هم می توانید کدش رو ببینید :
کد:
[DllImport("user32.dll", EntryPoint="GetWindow")]
private static extern IntPtr GetNextWindow (IntPtr hwnd, int wFlag);
اول اینکه کنترلی که در پشتِ یه کنترل دیگه قرار هست را بگیرم (یعنی قصد گرفتن کنترل a در بالا را دارم) . یعنی در آرگومان اول تابع GetWindow ، هندل کنترل b و در آرگومان دومش مقدار GW_HWNDNEXT را که میدم ، این فقط یه کنترلی که پشتش قرار داره را بهم میده که همون کنترل والد یعنی panel را بهم برمیگردونه.

دوم اینکه کنترلی که در جلوی کنترلِ دیگه هست را یخوام بگیرم (یعنی قصد گرفتن کنترل c و d را دارم) . یعنی در آرگومان اول تابع GetWindow ، باز هم هندل کنترل b و در آرگومان دومش مقدار GW_HWNDPREV را که میدم ، این باز هم فقط یک کنترلی که جلوش قرار داره را بهم برمیگردونه . یعنی فقط کنترل c را بهم برمیگردونه .
کلا مشکل اینه که اگه چند تا کنترل در جلو باشن ، فقط یک کنترل از اون را برمیگردونه (توی حلقه هم بذاریم ، فرقی نداره) و اگه چند تا کنترل در عقب باشن ، باز هم فقط یک کنترل از اون را برمیگردونه.
چجوری باید حلش کرد؟
چون من نمیتونم آرگومان اولِ تابع را تغییر بدم . چون نسبت به یه کنترل ، کنترل هایِ جلوی اون یا کنترل هایِ عقب اون (نه فقط یک تک کنترل بلکه همه ی کنترل های جلو یا عقب اون) را میخوام.

مشکل سوم هم اینه که توی قسمت Remarks از توضیحات این تابع ، دقیق متوجه نشدم چی میگه . انگار میگه اگه این تابع توی حلقه قرار بگیره ، ممکنه حلقه گیر کنه و بینهایت اجرا بشه . من توی حلقه گذاشتم ، مشکلی ندیدم . جز همین قضیه ی بالا که باز هم یه کنترل را برمیگردونه.

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

در کد زیر ترتیب قرار گیری ها و مبنای جستجو کاملا تصادفیه، برای همین هر بار محل شروع پیمایش (Base) عوض میشه، ولی هیچ مشکلی هم پیش نمیاد چون شرط حلقه ها درست تنظیم شده.
کد:
    public partial class Form1 : Form
    {
        private const int GW_HWNDNEXT = 2;
        private const int GW_HWNDPREV = 3;

        [DllImport("user32.dll", EntryPoint = "GetWindow")]
        private static extern IntPtr GetNextWindow(IntPtr hwnd, int wFlag);
        private Random _rnd = new Random();

        private Panel _panel;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            _panel = new Panel() { BackColor = Color.LightBlue, Dock = DockStyle.Fill, Parent = this };
            var buttons = new Button[10];
            for (var i = 0; i < buttons.Length; i++)
            {
                int j;
                do
                {
                    j = _rnd.Next(buttons.Length);
                } while (buttons[j] != null);
                buttons[j] = new Button()
                {
                    Text = $"Button[{j}]"
                    ,
                    TextAlign = ContentAlignment.TopCenter,
                    Bounds = new Rectangle(220 - i * 10, 200 - i * 20, 80 + i * 20, 40 + i * 40),
                    Parent = _panel
                };
            }
            var button = new Button() { Text = "Get Z-Order", Bounds = new Rectangle(10, 10, 100, 25), Parent = this };
            button.BringToFront();
            button.Click += button_Click;
        }

        private void button_Click(object sender, EventArgs e)
        {
            var handleDic = new Dictionary<IntPtr, Control>();
            var randomBase = _rnd.Next(_panel.Controls.Count);
            var baseHwnd = _panel.Controls[randomBase].Handle;
            for (var i = 0; i < _panel.Controls.Count; i++)
            {
                handleDic.Add(_panel.Controls[i].Handle, _panel.Controls[i]);
            }
            var output = new StringBuilder();
            output.AppendLine($"[{handleDic[baseHwnd].Text}] (Base)");
            var prevHwnd = baseHwnd;
            do
            {
                prevHwnd = GetNextWindow(prevHwnd, GW_HWNDPREV);
                if (prevHwnd == IntPtr.Zero)
                {
                    break;
                }
                output.Insert(0, $"[{handleDic[prevHwnd].Text}] (Prev)" + Environment.NewLine);
            } while (true);
            var nextHwnd = baseHwnd;
            do
            {
                nextHwnd = GetNextWindow(nextHwnd, GW_HWNDNEXT);
                if (nextHwnd == IntPtr.Zero)
                {
                    break;
                }
                output.AppendLine($"[{handleDic[nextHwnd].Text}] (Next)");
            } while (true);
            MessageBox.Show(output.ToString());
        }
    }
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد علی
تا اینجا TransparentControl را ویرایش کردم و در زیر براتون آپلود میکنم (هنوز بعضی از اعضاش کار نمیکنه و تموم نشد . فعلا از متد سازنده ای که کدش رو میذارم ، لطفا چک کنید) .
دارم این قابلیت را اضافه میکنم که نیازی نباشه که کاربر بخواد کنترل های پشت و کنترل های جلویِ (در سطح کنترل خواهر و برادری) کنترل TransparentControl را بهش بده و این کار را میخوام خود همین کنترل انجام بده .
در متد سازنده ی فرم تون ، این را بنویسید لطفا (بجای مسیر فایل png ، که میدونین هر فایل مورد نظر خودتون که خواستین را بدین . فقط اندازه اش جوری باشه که دو کنترل در کد زیر ، نصف شون یا قسمتی ازشون ، روی همدیگه بیفتن) :


کد:
        private TransparentControl transparentControl;
        private TransparentControl transparentControl_2;


        public Form1()
        {
           Bitmap bitmap = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Close\Close.png");
            TransparentControlBitmap controlBitmap = new TransparentControlBitmap(bitmap, new Bitmap(bitmap.Width, bitmap.Height), new Bitmap(bitmap.Width, bitmap.Height), new Bitmap(bitmap.Width, bitmap.Height));
            controlBitmap.GraphicInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            controlBitmap.SetColor(bitmap, ExportBitmapFor.MouseEnterBitmap, Color.DeepSkyBlue);
            controlBitmap.SetColor(bitmap, ExportBitmapFor.MouseDownBitmap, Color.Blue);
            controlBitmap.SetColor(bitmap, ExportBitmapFor.ControlDisabledBitmap, Color.Yellow);
            this.transparentControl = new TransparentControl(controlBitmap, new Point(200, 10));
            this.transparentControl.Name = "Close";
            this.transparentControl.MouseClick += new MouseEventHandler(this.TransparentControl_MouseClick);

            Bitmap bitmap_2 = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Setting\Setting.png");
            TransparentControlBitmap controlBitmap_2 = new TransparentControlBitmap(bitmap_2);
            controlBitmap_2.MouseEnterBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.DeepSkyBlue);
            controlBitmap_2.MouseDownBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.Blue);
            controlBitmap_2.ControlDisabledBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.Yellow);
            this.transparentControl_2 = new TransparentControl(controlBitmap_2, new Point(210, 20));
            this.transparentControl_2.Name = "Setting";
            this.transparentControl_2.MouseClick += new MouseEventHandler(this.TransparentControl_MouseClick);

            this.Controls.Add(transparentControl);
            this.Controls.Add(transparentControl_2);
        }

نکته ی عجیب برای من اینه که وقتی روی همین کد بالا (مخصوصا در خط this.Controls.Add(transparentControl) ، علامت breakpoint را میذارم و اگه بریک پوینت را با F11 بزنم بره جلو ، پروپرتی BackgroundControls ، در شی transparentControl ، مقدار میگیره (اولین عضو از مقدارش برابر با شی transparentControl_2 میشه) که منم همین رو میخوام و درسته . اما هر دفعه بریک پوینت را با دکمه ی F10 بزنم بره جلو ، با کمال تعجب میبینم که این پروپرتی ، اون مقداری که قبلا گرفت را نداره !!
علاوه بر اینها (اگه در حالت اول که با F11 بزنم هم حتی و مقدار بگیره) ، وقتی موس را روی شی transparentControl میبرم ، این پروپرتی BackgroundControls اش ، null میشه !! چرا ، نمیدونم.
کلا تعجب آورترین مسائل ، این دو موضوع بودن .
چرا این دو اتفاق میافته؟

---------------------------------------------------------------------

روند کلی کنترل TransparentControl رو اینجوری کردم که هر کنترلی در سطح خواهر و برادر کنترل TransparentControl مون (که والد یکسان دارن) ، به کنترل والدش اضافه شد یا تغییر باند داد (بجز کنترلِ جاری TransparentControl) ، به رویداد Parent_ControlAddedAndRemoved و SiblingControls_BoundsChanged متصل شون کردم . توی این رویدادها هم که هر دو یک کار را میکنن ، اول چک میکنم که کنترلی که این رویدادها براشون اتفاق افتاد ، آیا با کنترلِ جاری TransparentControl ، محیط مشترک (همون Rectangle.Intersect) دارن یا نه؟ اگه داشتن ، چک میکنم که آیا این کنترلِ اضافه شده ، یه بار در کلِ کنترل های پشتی اش هست؟ اگه بود ، اون کنترل رو به اعضای آرایه ی (پروپرتی) BackgroundControls اش اضافه میکنم . اگه در کنترل پشتی اش نبود ، در کل کنترل های جلویی اش چک میکنم که وجود داره یا نه و اگه اونجا وجود داشت ، اون کنترل رو به اعضای آرایه ی (پروپرتی) ForegroundControls اش اضافه میکنم .
بعد هم اعضای پروپرتی BackgroundControls رو قبل از Invalidate کردنِ کنترل جاری TransparentControl ام invalidate میکنم (فقط اون بخشی شون را که با کنترل TransparentControl ام مشترک هستند ، invalidate میکنم) (تا قبل از کنترل جاری TransparentControl ام رسم بشن) و همین کار را بعد از invalidate کردنِ کنترل جاری TransparentControl ام برای پروپرتی ForegroundControls انجام میدم (این را هم بخش مشترک شون را invalidate میکنم) ( تا بعد از کنترل جاری TransparentControl ام رسم بشن)

البته این قسمت از کدها فعلا یه مشکلی داره که باید وقتی متد OnParentChanged اجرا میشه هم ، این عملیات را یه بار انجام بدم یعنی رویداد Parent_ControlAddedAndRemoved را اون موقع ، فراخونی کنم.
مشکلات دیگه ای هم شاید داشته باشه (فعلا نمیدونم).
خیلی ممنون استاد علی
 

پیوست ها

  • TransparentControl.rar
    13 کیلوبایت · بازدیدها: 1
آخرین ویرایش:

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
سلامی مجدد
میگم استاد علی ، اگه بریک پوینت را روی کد this.Controls.Add(transparentControl) بذارم و همه ی مراحل را با دکمه ی F11 برم ، حتی اونی که در پست بالا گفته بودم که موس را روی کنترل ببریم ، باز پروپرتی BackgroundControls (مربوط به شی اولی یعنی شی transparentControl در کد پست بالا) نال میشه ؛ در این صورت ، نال نمیشه (اگه همه را با F11 بریم و انگار با مکث بریم) (البته باز 2 تا بریک پویت هم در قسمت get و set پروپرتی BackgroundControls هم گذاشتم .
اما اگه با F10 بریم جلو یا اصلا برنامه را بصورت عادی اجرا کنیم و بریک پوینت ای براش در نظر نگیریم ، پروپرتی BackgroundControls (مربوط به شی اولی یعنی شی transparentControl در کد پست بالا) نال میشه.
چرا؟! اولین باره همچین چیزی میبینم! ظاهرا برای این قسمت از کدها ، مشکل از کدهای من نباید باشه . هست؟ یا مشکب ویژال استودیو هه؟ واسه من نسخه ی 2019 هه.

---------------------------------------------------------------------

بعد اینکه میشه وقتی کسی کنترلی را BringToFront کرد ، ما بتونیم رویدادی ازش بدست بیاریم؟ یعنی رویدادی برای BringToFront ظاهرا وجود نداره . داره؟ اگه روشی برای این کار هست یا کاریش میشه کرد (از طریق api ویندوز و هر روش دیگه ای) ، میگین؟ منظورم کد نیست . در صورت وجود ، لطفارفرنس بدین ، خودم بررسی میکنم.
خیلی ممنون
 

the_king

مدیرکل انجمن
سلامی مجدد
میگم استاد علی ، اگه بریک پوینت را روی کد this.Controls.Add(transparentControl) بذارم و همه ی مراحل را با دکمه ی F11 برم ، حتی اونی که در پست بالا گفته بودم که موس را روی کنترل ببریم ، باز پروپرتی BackgroundControls (مربوط به شی اولی یعنی شی transparentControl در کد پست بالا) نال میشه ؛ در این صورت ، نال نمیشه (اگه همه را با F11 بریم و انگار با مکث بریم) (البته باز 2 تا بریک پویت هم در قسمت get و set پروپرتی BackgroundControls هم گذاشتم .
اما اگه با F10 بریم جلو یا اصلا برنامه را بصورت عادی اجرا کنیم و بریک پوینت ای براش در نظر نگیریم ، پروپرتی BackgroundControls (مربوط به شی اولی یعنی شی transparentControl در کد پست بالا) نال میشه.
چرا؟! اولین باره همچین چیزی میبینم! ظاهرا برای این قسمت از کدها ، مشکل از کدهای من نباید باشه . هست؟ یا مشکب ویژال استودیو هه؟ واسه من نسخه ی 2019 هه.
میتونه دلایل متعددی داشته باشه، از بهم خوردن ترتیب رخداد ها تا عدم امکان Serialize/Deserialize کردن فرم توسط Designer ویژوال استدیو. فرصت بررسی کد شما رو ندارم.
اعمال Break Point برای روالی بی تاثیره که زمان و رخداد ها خارجی در اون دخیل نباشه، فرضا کد به زمان سپری شده وابسته نباشه، رخداد پنجره ها رویش تاثیر نگذاره و ...
وگرنه نمی توانید توقع داشته باشید که ایجاد وقفه در اجرا در نتیجه بی تاثیر باشه.
از طرف دیگه شما نگهداری مقادیر رو به Designer ویژوال استدیو می سپارید که یک مجموعه مستقل از کد شما است با روتین های خاص خودش. مثلا وقتی کنترل شما روی فرم قرار میگیره و در حال طراحی فرم هستید کد کلاس کنترل تون در حال اجرا شدنه، با وجود اینکه خود برنامه تون در حال اجرا نیست. اینجا Designer ئه که داره کار می کنه.
ممکنه با ایجاد تاخیر در اجرا وادارش کنید روالی رو با ترتیب متفاوت یا مستقل از زمان بندی عادی رخداد های کنترل های روی فرم تون انجام بده و نتیجه متفاوتی بگیرید.
بعد اینکه میشه وقتی کسی کنترلی را BringToFront کرد ، ما بتونیم رویدادی ازش بدست بیاریم؟ یعنی رویدادی برای BringToFront ظاهرا وجود نداره . داره؟ اگه روشی برای این کار هست یا کاریش میشه کرد (از طریق api ویندوز و هر روش دیگه ای) ، میگین؟ منظورم کد نیست . در صورت وجود ، لطفارفرنس بدین ، خودم بررسی میکنم.
خیلی ممنون
WM_WINDOWPOSCHANGING message - Windows applications
WM_WINDOWPOSCHANGED message - Windows applications
کلا هر کاری که SetWindowPos انجام میده به این دو رخداد منتهی میشه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
میتونه دلایل متعددی داشته باشه، از بهم خوردن ترتیب رخداد ها تا عدم امکان Serialize/Deserialize کردن فرم توسط Designer ویژوال استدیو. فرصت بررسی کد شما رو ندارم.
اعمال Break Point برای روالی بی تاثیره که زمان و رخداد ها خارجی در اون دخیل نباشه، فرضا کد به زمان سپری شده وابسته نباشه، رخداد پنجره ها رویش تاثیر نگذاره و ...
وگرنه نمی توانید توقع داشته باشید که ایجاد وقفه در اجرا در نتیجه بی تاثیر باشه.
از طرف دیگه شما نگهداری مقادیر رو به Designer ویژوال استدیو می سپارید که یک مجموعه مستقل از کد شما است با روتین های خاص خودش. مثلا وقتی کنترل شما روی فرم قرار میگیره و در حال طراحی فرم هستید کد کلاس کنترل تون در حال اجرا شدنه، با وجود اینکه خود برنامه تون در حال اجرا نیست. اینجا Designer ئه که داره کار می کنه.

خیلی ممنون ولی من از جملات تون ، خیلی چیزی متوجه نشدم.
از Serialize/Deserialize چیزی نمیدونم.
منظورتون ازDesigner ویژوال استودیو ، همون designer.cs فرم هست؟


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

خیلی ممنون :rose:
بله مشکل از همین بود.
کدها (در پست بالا) را از متد سازنده ، به رویداد Load منتقل کردم ، درست شد .
اما هنوز دلیلش را متوجه نشدم !!
الان یعنی نمیتونم یه جوری کد درون کلاس TransparentControl را دستکاری کنم که طرف بتونه توی متد سازنده ی خودش از این کنترلم استفاده کنه اما این مشکل پیش نیاد؟ یعنی باز هم مثل این حالتی که کدها را توی رویداد Load نوشتم (و پروپرتی BackgroundControls در شی transparentControl در کد پست بالا ، مقدار گرفت) ، در حالتی که طرف توی متد سازنده ی فرم اش هم بنویسه هم ، مقدار بگیره؟
نخ اش را باید متوقف کنم؟ اگه شدنی هم باشه ، اصولی نیست . کار دیگه ای باید کنم؟ کلا چی کار میشه کرد؟





بررسی اش میکنم .
باز هم خیلی ممنون
 

the_king

مدیرکل انجمن
خیلی ممنون ولی من از جملات تون ، خیلی چیزی متوجه نشدم.
از Serialize/Deserialize چیزی نمیدونم.
منظورتون ازDesigner ویژوال استودیو ، همون designer.cs فرم هست؟
نه. اون که فایل کد ئه. منظورم Designer ویژوال استدیواست. همون محیطی که طراحی ویژوال رو داخلش انجام میدید، پروپرتی ها رو نشون میده. مقادیر پروپرتی ها رو تغییر میده یا کد خودکار میسازه.
وقتی شما دارید فرم تون رو طراحی میکنید و رنگ کنترلی رو تغییر میدید رنگ کجا ذخیره میشه؟ اینها مربوط به وظایف Designer ئه. اگر Designer نبود مادامی که کد برنامه رو اجرا نکرده بودید هیچ چیزی برای نمایش نداشت.

الان یعنی نمیتونم یه جوری کد درون کلاس TransparentControl را دستکاری کنم که طرف بتونه توی متد سازنده ی خودش از این کنترلم استفاده کنه اما این مشکل پیش نیاد؟ یعنی باز هم مثل این حالتی که کدها را توی رویداد Load نوشتم (و پروپرتی BackgroundControls در شی transparentControl در کد پست بالا ، مقدار گرفت) ، در حالتی که طرف توی متد سازنده ی فرم اش هم بنویسه هم ، مقدار بگیره؟
نخ اش را باید متوقف کنم؟ اگه شدنی هم باشه ، اصولی نیست . کار دیگه ای باید کنم؟ کلا چی کار میشه کرد؟
سردر نمیارم چی میخواهید. دکمه برای قرار گرفتن روی فرم ئه و در محیط ویژوال مشخصاتش تنظیم میشه، نه با کدنویسی در سازنده کلاس. اگر کنترل پیچیده ای مثل DataGridView هم باشه برایش Designer اختصاصی طراحی میشه که فرضا مشخصات ستون ها رو داخلش وارد میکنید. مثل همون چیزی که در DataGridView میبینید. کسی نمیاد داخل متد سازنده فرم برای اینجور چیز ها کد نویسی کنه. بجز کنترل شما مورد دیگه ای دیدید که اینطور استفاده کردنش غیرعادی باشه؟ شمابرای استفاده از کنترل Toolbar/ToolStrip که اونهمه ویژگی ها و زیرمجموعه داره مجبور میشید در متد سازنده فرم کد نویسی کنید؟
وقتی کاری میکنید که با موارد مشابه مطابقت نداره به احتمال زیاد دارید کار اشتباهی انجام میدید. قبلا هم بهتون گفتم. متد سازنده فرم برای کدنویسی شما یا آقا/خانم طرف نیست.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
خیلی ممنون استاد علی
الان همه چیز درست شد جز یه چیز که در زیر میگم.
با اونکه پروپرتی BackgroundControls (شامل تمامی کنترل هایی که زیر کنترل جاری هست) را اول invalidate میکنم و بعد کنترل جاری را invalidate میکنم و بعد پروپرتی ForegroundControls (شامل تمامی کنترل هایی که جلوی کنترل جاری هست) را invalidate میکنم ، ولی برعکس رسم میکنه . یعنی کنترل های BackgroundControls را سر آخر رسم میکنه که باعث میشه جلو بیان (بخشی از کد کلاس TransparentControl که به این قضیه مربوط میشه را در زیر میذارم) :


کد:
        protected override void OnMouseEnter(EventArgs e)
        {
            this.EventOperation(1);

            base.OnMouseEnter(e);
        }


        private void EventOperation(int eventBitmapIndex)
        {
            if (this.Parent == null)
                return;

            // در این متد ، به فلگ TranspControlEventDoingFlag مقدار دادیم چون هر عمل و رویدادی که برای این کنترل ، به موس ختم بشه باعث اجرای این متد میشه . بخاطر اینکه زمان Invalidate شدنِ والد ، فقط همین کنترل را که موس رویش عملیات انجام داد را رسم کنه . توضیح مفصل تر در توضیحات این پروپرتی آمده.
            TransparentControl.TranspControlEventDoingFlag = this;
            // وقتی این خط اجرا بشه ، یعنی کنترلِ والد ، Invalidate بشه ، علاوه بر رسم مجدد اون قسمتِ مشخص شده از کنترل والد ، رویداد AllParents_Invalidated برای Invalidate و رسم این کنتزلِ جاریِ TransparentControl اجرا میشه
            this.Parent.Invalidate(this.Bounds);
            this.eventBitmapIndex = eventBitmapIndex;
        }


        private void AllParents_Invalidated(object sender, InvalidateEventArgs e)
        {
            // در این قسمت ، عمل Invalidate کردن یا همون رسم کردن کنترل TransparentControl را فقط روی اون کنترلی انجام میده که عملیات موس روی اون کنترل انجام گرفته باشه .
            if (this.Equals(TransparentControl.TranspControlEventDoingFlag) == true)
            {
                // اگه کنترلی ، پشت کنترل جاری TransparentControl قرار داشت ؛ یعنی کاربر به پروپرتی InvalidateBackControls مقدار داد ، اون بخش از کنترل های پشتی که کنترل جاری TransparentControl روی اون قرار داره ، قبل از رسم مجدد کنترل جاری TransparentControl در خط بعد از شرط ، کنترل پشتی ، باید رسم بشه .
                this.InvalidateForeOrBackgroundControls(this.BackgroundControls, this.BackgroundControlInvalidateRegiones);

                this.Invalidate();

                this.InvalidateForeOrBackgroundControls(this.ForegroundControls, this.ForeGroundControlInvalidateRegiones);

            }

            // همچنین اگه مکان کنترل جاری مون تغییر کنه ، همون کنترل رسم میشه.
            if (this.IsLocationChangeDoingFlag == true)
            {
                this.IsLocationChangeDoingFlag = false;
                // اگه کنترلی ، پشت کنترل جاری TransparentControl قرار داشت ؛ یعنی کاربر به پروپرتی InvalidateBackControls مقدار داد ، اون بخش از کنترل های پشتی که کنترل جاری TransparentControl روی اون قرار داره ، قبل از رسم مجدد کنترل جاری TransparentControl در خط بعد از شرط ، کنترل پشتی ، باید رسم بشه .
                this.InvalidateForeOrBackgroundControls(this.BackgroundControls, this.BackgroundControlInvalidateRegiones);

                this.Invalidate();

                this.InvalidateForeOrBackgroundControls(this.ForegroundControls, this.ForeGroundControlInvalidateRegiones);
            }
        }


        private void InvalidateForeOrBackgroundControls(Control[] foreOrBackgroundControls, List<Rectangle> InvalidateRegions)
        {
            if (foreOrBackgroundControls != null)
            {
                for (int index = 0; index < foreOrBackgroundControls.Length; index++)
                    foreOrBackgroundControls[index].Invalidate(InvalidateRegions[index]);
            }
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            this.SetGraphicProperties(e.Graphics);

            // اگر آرایه EventBitmap مقدار داشته باشه ، عضو مربوطه ی اون آرایه را در زمان و رویداد مشخص رسم میکنه .
            if (this.TransparentControlBitmap != null)
                e.Graphics.DrawImage(this.TransparentControlBitmap.EventBitmaps[this.eventBitmapIndex], this.TransparentControlBitmap.Bounds);

            base.OnPaint(e);
        }


        protected override void OnPaintBackground(PaintEventArgs e)
        {

        }

در رویداد Load فرم هم :


کد:
            Bitmap bitmap = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Close\Close.png");
            bitmap = TransparentControlBitmap.SetColor(bitmap, Color.Red);
            TransparentControlBitmap controlBitmap = new TransparentControlBitmap(bitmap, new Bitmap(bitmap.Width, bitmap.Height), new Bitmap(bitmap.Width, bitmap.Height), new Bitmap(bitmap.Width, bitmap.Height));
            controlBitmap.GraphicInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            controlBitmap.SetColor(bitmap, ExportBitmapFor.MouseEnterBitmap, Color.DeepSkyBlue);
            controlBitmap.SetColor(bitmap, ExportBitmapFor.MouseDownBitmap, Color.Blue);
            controlBitmap.SetColor(bitmap, ExportBitmapFor.ControlDisabledBitmap, Color.Yellow);
            this.transparentControl = new TransparentControl(controlBitmap, new Point(200, 10));
            this.transparentControl.Text = "Close";
            this.transparentControl.MouseClick += new MouseEventHandler(this.TransparentControl_MouseClick);

            Bitmap bitmap_2 = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Setting\Setting.png");
            TransparentControlBitmap controlBitmap_2 = new TransparentControlBitmap(bitmap_2);
            controlBitmap_2.MouseEnterBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.DeepSkyBlue);
            controlBitmap_2.MouseDownBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.Blue);
            controlBitmap_2.ControlDisabledBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.Yellow);
            this.transparentControl_2 = new TransparentControl(controlBitmap_2, new Point(210, 20));
            this.transparentControl_2.Text = "Setting";
            this.transparentControl_2.MouseClick += new MouseEventHandler(this.TransparentControl_MouseClick);

            this.Controls.Add(transparentControl);
            this.Controls.Add(transparentControl_2);

هسته ی مرکزی کدهای کنترل کلاس TransparentControl که به این بخش مربوط میشه ، رویداد AllParents_Invalidated هست.
چرا این جوری هه؟
من که به ترتیب رسم میکنم ولی این چرا BackgroundControls را سر آخر رسم میکنه؟
منظورم از رسم ، invalidate یا نامعتبر کردن هست (مثل اون موقع نشه :green: ) و چون اینجا کد update ای بکار برده نشد و در صف هم به ترتیب اجرا میشن ، پس به ترتیبی که من invalidate کردم باید رسم بشن اما به ترتیبی که من گفتم رسم نمیشن . چرا؟
 
آخرین ویرایش:

the_king

مدیرکل انجمن
خیلی ممنون استاد علی
الان همه چیز درست شد جز یه چیز که در زیر میگم.
با اونکه پروپرتی BackgroundControls (شامل تمامی کنترل هایی که زیر کنترل جاری هست) را اول invalidate میکنم و بعد کنترل جاری را invalidate میکنم و بعد پروپرتی ForegroundControls (شامل تمامی کنترل هایی که جلوی کنترل جاری هست) را invalidate میکنم ، ولی برعکس رسم میکنه . یعنی کنترل های BackgroundControls را سر آخر رسم میکنه که باعث میشه جلو بیان (بخشی از کد کلاس TransparentControl که به این قضیه مربوط میشه را در زیر میذارم) :


کد:
        protected override void OnMouseEnter(EventArgs e)
        {
            this.EventOperation(1);

            base.OnMouseEnter(e);
        }


        private void EventOperation(int eventBitmapIndex)
        {
            if (this.Parent == null)
                return;

            // در این متد ، به فلگ TranspControlEventDoingFlag مقدار دادیم چون هر عمل و رویدادی که برای این کنترل ، به موس ختم بشه باعث اجرای این متد میشه . بخاطر اینکه زمان Invalidate شدنِ والد ، فقط همین کنترل را که موس رویش عملیات انجام داد را رسم کنه . توضیح مفصل تر در توضیحات این پروپرتی آمده.
            TransparentControl.TranspControlEventDoingFlag = this;
            // وقتی این خط اجرا بشه ، یعنی کنترلِ والد ، Invalidate بشه ، علاوه بر رسم مجدد اون قسمتِ مشخص شده از کنترل والد ، رویداد AllParents_Invalidated برای Invalidate و رسم این کنتزلِ جاریِ TransparentControl اجرا میشه
            this.Parent.Invalidate(this.Bounds);
            this.eventBitmapIndex = eventBitmapIndex;
        }


        private void AllParents_Invalidated(object sender, InvalidateEventArgs e)
        {
            // در این قسمت ، عمل Invalidate کردن یا همون رسم کردن کنترل TransparentControl را فقط روی اون کنترلی انجام میده که عملیات موس روی اون کنترل انجام گرفته باشه .
            if (this.Equals(TransparentControl.TranspControlEventDoingFlag) == true)
            {
                // اگه کنترلی ، پشت کنترل جاری TransparentControl قرار داشت ؛ یعنی کاربر به پروپرتی InvalidateBackControls مقدار داد ، اون بخش از کنترل های پشتی که کنترل جاری TransparentControl روی اون قرار داره ، قبل از رسم مجدد کنترل جاری TransparentControl در خط بعد از شرط ، کنترل پشتی ، باید رسم بشه .
                this.InvalidateForeOrBackgroundControls(this.BackgroundControls, this.BackgroundControlInvalidateRegiones);

                this.Invalidate();

                this.InvalidateForeOrBackgroundControls(this.ForegroundControls, this.ForeGroundControlInvalidateRegiones);

            }

            // همچنین اگه مکان کنترل جاری مون تغییر کنه ، همون کنترل رسم میشه.
            if (this.IsLocationChangeDoingFlag == true)
            {
                this.IsLocationChangeDoingFlag = false;
                // اگه کنترلی ، پشت کنترل جاری TransparentControl قرار داشت ؛ یعنی کاربر به پروپرتی InvalidateBackControls مقدار داد ، اون بخش از کنترل های پشتی که کنترل جاری TransparentControl روی اون قرار داره ، قبل از رسم مجدد کنترل جاری TransparentControl در خط بعد از شرط ، کنترل پشتی ، باید رسم بشه .
                this.InvalidateForeOrBackgroundControls(this.BackgroundControls, this.BackgroundControlInvalidateRegiones);

                this.Invalidate();

                this.InvalidateForeOrBackgroundControls(this.ForegroundControls, this.ForeGroundControlInvalidateRegiones);
            }
        }


        private void InvalidateForeOrBackgroundControls(Control[] foreOrBackgroundControls, List<Rectangle> InvalidateRegions)
        {
            if (foreOrBackgroundControls != null)
            {
                for (int index = 0; index < foreOrBackgroundControls.Length; index++)
                    foreOrBackgroundControls[index].Invalidate(InvalidateRegions[index]);
            }
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            this.SetGraphicProperties(e.Graphics);

            // اگر آرایه EventBitmap مقدار داشته باشه ، عضو مربوطه ی اون آرایه را در زمان و رویداد مشخص رسم میکنه .
            if (this.TransparentControlBitmap != null)
                e.Graphics.DrawImage(this.TransparentControlBitmap.EventBitmaps[this.eventBitmapIndex], this.TransparentControlBitmap.Bounds);

            base.OnPaint(e);
        }


        protected override void OnPaintBackground(PaintEventArgs e)
        {

        }

در رویداد Load فرم هم :


کد:
            Bitmap bitmap = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Close\Close.png");
            bitmap = TransparentControlBitmap.SetColor(bitmap, Color.Red);
            TransparentControlBitmap controlBitmap = new TransparentControlBitmap(bitmap, new Bitmap(bitmap.Width, bitmap.Height), new Bitmap(bitmap.Width, bitmap.Height), new Bitmap(bitmap.Width, bitmap.Height));
            controlBitmap.GraphicInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
            controlBitmap.SetColor(bitmap, ExportBitmapFor.MouseEnterBitmap, Color.DeepSkyBlue);
            controlBitmap.SetColor(bitmap, ExportBitmapFor.MouseDownBitmap, Color.Blue);
            controlBitmap.SetColor(bitmap, ExportBitmapFor.ControlDisabledBitmap, Color.Yellow);
            this.transparentControl = new TransparentControl(controlBitmap, new Point(200, 10));
            this.transparentControl.Text = "Close";
            this.transparentControl.MouseClick += new MouseEventHandler(this.TransparentControl_MouseClick);

            Bitmap bitmap_2 = new Bitmap(@"E:\Project\Visual Studio\C#.Net\Saved Project\0 Important Project\Poshtibangir Tolo\PoshtibangirTolo\bin\Debug\Icon\PanelToolBar\Setting\Setting.png");
            TransparentControlBitmap controlBitmap_2 = new TransparentControlBitmap(bitmap_2);
            controlBitmap_2.MouseEnterBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.DeepSkyBlue);
            controlBitmap_2.MouseDownBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.Blue);
            controlBitmap_2.ControlDisabledBitmap = TransparentControlBitmap.SetColor(bitmap_2, Color.Yellow);
            this.transparentControl_2 = new TransparentControl(controlBitmap_2, new Point(210, 20));
            this.transparentControl_2.Text = "Setting";
            this.transparentControl_2.MouseClick += new MouseEventHandler(this.TransparentControl_MouseClick);

            this.Controls.Add(transparentControl);
            this.Controls.Add(transparentControl_2);

هسته ی مرکزی کدهای کنترل کلاس TransparentControl که به این بخش مربوط میشه ، رویداد AllParents_Invalidated هست.
چرا این جوری هه؟
من که به ترتیب رسم میکنم ولی این چرا BackgroundControls را سر آخر رسم میکنه؟
منظورم از رسم ، invalidate یا نامعتبر کردن هست (مثل اون موقع نشه :green: ) و چون اینجا کد update ای بکار برده نشد و در صف هم به ترتیب اجرا میشن ، پس به ترتیبی که من invalidate کردم باید رسم بشن اما به ترتیبی که من گفتم رسم نمیشن . چرا؟
کنترل شما از controlParent.ControlAdded و controlParent.ControlRemoved استفاده میکنه. اولا با کنترلی که حذف شده چیکار دارید که میخواهید به مجموعه افزوده بشه؟ ثانیا یعنی صرفا کنترل هایی که بعدا اضافه میشن مهم هستند؟ کنترل هایی که قبلا روی controlParent بودند نه جزو BackgroundControls هستند و نه ForegroundControls و رخدادی براشون ندارید. همانطور که transparentControl و transparentControl_2 هر دو ForegroundControls شون خالیه.
 

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
کنترل شما از controlParent.ControlAdded و controlParent.ControlRemoved استفاده میکنه. اولا با کنترلی که حذف شده چیکار دارید که میخواهید به مجموعه افزوده بشه؟ ثانیا یعنی صرفا کنترل هایی که بعدا اضافه میشن مهم هستند.

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

اول ، دومی سئوال تون را جواب بدم. بله. کنترل هایی که اضافه میشه (کنترل هایی که فقط در سطح خواهر و برادر کنترل TransparentControl باشند) ، مهم هستند . چون ممکنه کنترلی که برنامه نویس اضافه میکنه ، مستطیل مشترکی با کنترل TransparentControl داشته باشه یا به عبارتی ، کنترلی که اضافه میکنه ، در پشت یا جلوی کنترل TransparentControl اضافه شده باشه . علاوه بر این ، رویدادهای تغییر جابجایی و تغییر اندازه ی کنترل های خواهر و برادرِ کنترلِ TransparentControl هم مهم هستند چون بعد از جابجایی یا تغییر اندازه ، معلوم نیست کنترل مورد نظر ، در پشت یا جلوی کنترل TransparentControl مون بیافته یا نیفیته.
اینکه با کنترل حذف شده چی کار دارم ، چون کنترلی که حذف شده باشه (و قبل از حذف شدنش در پشت یا جلوی کنترل TransparentControl مون بوده باشه) ، تا جایی که میدونم ، موقع حذفش اون قسمتی که خودش قرار داشت از کنترل والدش را invalidate میکنه تا والدش مجددا اون تیکه اش را رسم کنه (تا رسمِ کنترلِ حذف شده هم ، پاک بشه) بنابراین هم باعث ایجاد اختلال رسم در کنترل TransparentControl میشه و هم اینکه کنترل TransparentControl باید دوباره رسم بشه). البته به تست این قسمت از کنترل های حذف شده نرسیدم . میدونم مشکلاتی ممکنه پیش بیاد توی این قسمت . فعلا این کدها موقتی هستند کلا.


کنترل هایی که قبلا روی controlParent بودند نه جزو BackgroundControls هستند و نه ForegroundControls و رخدادی براشون ندارید. همانطور که transparentControl و transparentControl_2 هر دو ForegroundControls شون خالیه.

بله . در حال تغییر هستم . آخرین تغییرم اینی هست که در زیر میذارم و این مشکل حل شد . البته باز هم اشکالاتی داره که در حال تغییر دادنم.
ولی مهمترین مشکلش الان همین سئوال پست بالایی (پست 1272 هه) که هنوز به جواب نرسیدم. جواب اینو میدید؟
وقتی جلو یا پشتِ یک کنترل TransparentControl ، کنترل معمولی (کنترل دکمه و ... . کلا کنترلی بجز یه کنترلِ دیگه از TransparentControl) باشه ، کد و ترتیب رسم ها ، درست انجام میشه. اما اگه دو کنترل TransparentControl روی هم باشن ، برعکس میشه . یعنی کنترل پشتی ، سر آخر رسم میشه که باعث میشه جلوتر از قبلی رسم بشه.
خیلی ممنون
 

پیوست ها

  • TransparentControl.rar
    13.1 کیلوبایت · بازدیدها: 1
آخرین ویرایش:

the_king

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

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

SajjadKhati

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

سلامی مجدد
منم جواب دادم استاد ها
گفتم توی آخرین نسخه از همون کلاس که در پست قبلی براتون آپلود کردم ، این مشکل را حل کردم.
نیازی هست ، کدش را بذارم یا فایل پیوستی در پست قبلی دانلود میکنید؟
خیلی ممنون
 

the_king

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

SajjadKhati

کاربر فعال <A href="http://forum.majidonline.com/f
مورد جدیدی نیست. رخداد Invalidate مستقل از Paint ئه. کنترلی که زودتر از سایرین Invalidate کردید الزاما زودتر از سایرین Paint نمی کنه. اگه ترتیب وقوع رخداد ها در کدتون رو هم از طریقی مثل ارسال به یک ListBox روی فرم ببینید متوجه میشید که ترتیب Paint برعکس Invalidate ها رخ داده. یعنی شما اول کنترل پشتی رو Invalidate کردید و بعد جلویی رو. اما کنترل جلویی زودتر Paint خودش رو انجام داده. چون پنجره ها مستقل هستند نمیشه انتظار داشت ترتیب مشخصی برای اجرای درخواست هاشون داشته باشند. هر زمان نخ بیکار بود یکی از درخواست ها رو پیگیری میکنه.

خیلی ممنون
من دقیق متوجه نشدم.
شما میگفتین درخواست invalidate ها به ترتیب توی صف میره و در اولین فرصت ، به همون ترتیب رسیدگی میشه.
من الان چی کار باید کنم؟
پس چرا وقتی شی Button پشتش یا جلو ی کنترلم اضافه میکنم ، درست کار میکنه invalidate ها؟
فقط دو تا کنترل TransparentControl روی هم باشن ، ترتیب رسم جلویی و عقبی را قاتی میکنه.
الان به نظرتون چی کار کنم؟ جوری که وقتی button و هر کنترلی که پشت یا جلوی کنترل TransparentControl اضافه میکنم هم براشون مشکلی پیش نیاد چون همونطور که گفتم ، با این کد ، بخوبی کار میکنن.
 

the_king

مدیرکل انجمن
خیلی ممنون
من دقیق متوجه نشدم.
شما میگفتین درخواست invalidate ها به ترتیب توی صف میره و در اولین فرصت ، به همون ترتیب رسیدگی میشه.
بله. اون Invalidate ها با همون ترتیب اجرای کدتون اعمال میشه، یک نخ که بیشتر نیست. با همون ترتیب که درخواست Invalidate شده Invalidate میشن. اما همانطور که قبلا هم گفتم و در توضیحات InvalidateRect هم نوشته، پیام WM_PAINT چیزی نیست که اولا همیشه و با هر Invalidate ای ارسال بشه و ثانیا اگه پیامش در صف اجرا قرار گرفت فورا نوبت اش برسه. هر پنجره ای هم صف پیام های مجزایی داره.
براتون با کد و مثال هم نشون دادم که ارتباط مستقیمی بین ایندو نیست.
من الان چی کار باید کنم؟
چند بار در مورد WS_EX_TRANSPARENT گفتم و گوش نکردید.
#1176
#1137

پس چرا وقتی شی Button پشتش یا جلو ی کنترلم اضافه میکنم ، درست کار میکنه invalidate ها؟
فقط دو تا کنترل TransparentControl روی هم باشن ، ترتیب رسم جلویی و عقبی را قاتی میکنه.
ملاک درستی برای مقایسه قرار ندادید.
شما کنترل خودتون رو Invalidate میکنید و بعد کنترل دیگری رو که از هر نوعی میتونه باشه.
اگر اون کنترل بعدی یک کنترل عادی مثل button باشه که برایش هیچ فرقی نمی کنه که کنترل زیرش شفاف ئه یا نه. مهم نیست که رسم زیرش با تاخیر انجام بشه یا نه. مهم نیست اصلا رسمی زیرش بشه یا نه. پس اینکه روی کنترل تون button قرار میدید و درست عمل میکنه نشونه این نیست که کنترل شما رسمش درسته و با رسم روی خودش مشکلی نداره. دلیلش صرفا اینه که هر پنجره عادی که روی کنترل شما قرار بگیره درست دیده میشه. دکمه ای که پنجره اش بالاتر ازدکمه شما است که هیچوقت زیر پنجره کنترل شما نمیره. کنترل های زیرین هم بهشون درخواست Invalidate میدید. صف پیام هاشون هم خالیه و به موقع رسم میکنند. میمونه کنترل خودتون که رسمش مشکل داره.

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

الان به نظرتون چی کار کنم؟ جوری که وقتی button و هر کنترلی که پشت یا جلوی کنترل TransparentControl اضافه میکنم هم براشون مشکلی پیش نیاد چون همونطور که گفتم ، با این کد ، بخوبی کار میکنن.
به خوبی که احتمالا هیچوقت نمیشه ولی من جای شما باشم در AllParents_Invalidated صرفا تا Invalidate کنترل خودتون پیش میرم و اون بخش رسم کنترل های جلویی رو از اونجا Cut میکنم و برمیدارم و منتقل میکنم به انتهای OnPaint، یعنی وقتی کنترل های جلویی رو Invalidate میکنید که کنترل خودتون Paint شده، نه وقتی که تازه درخواست Paint کردید.
 

SajjadKhati

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

چند بار در مورد WS_EX_TRANSPARENT گفتم و گوش نکردید.
#1176
#1137


ملاک درستی برای مقایسه قرار ندادید.
شما کنترل خودتون رو Invalidate میکنید و بعد کنترل دیگری رو که از هر نوعی میتونه باشه.
اگر اون کنترل بعدی یک کنترل عادی مثل button باشه که برایش هیچ فرقی نمی کنه که کنترل زیرش شفاف ئه یا نه. مهم نیست که رسم زیرش با تاخیر انجام بشه یا نه. مهم نیست اصلا رسمی زیرش بشه یا نه. پس اینکه روی کنترل تون button قرار میدید و درست عمل میکنه نشونه این نیست که کنترل شما رسمش درسته و با رسم روی خودش مشکلی نداره. دلیلش صرفا اینه که هر پنجره عادی که روی کنترل شما قرار بگیره درست دیده میشه. دکمه ای که پنجره اش بالاتر ازدکمه شما است که هیچوقت زیر پنجره کنترل شما نمیره. کنترل های زیرین هم بهشون درخواست Invalidate میدید. صف پیام هاشون هم خالیه و به موقع رسم میکنند. میمونه کنترل خودتون که رسمش مشکل داره.

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


به خوبی که احتمالا هیچوقت نمیشه ولی من جای شما باشم در AllParents_Invalidated صرفا تا Invalidate کنترل خودتون پیش میرم و اون بخش رسم کنترل های جلویی رو از اونجا Cut میکنم و برمیدارم و منتقل میکنم به انتهای OnPaint، یعنی وقتی کنترل های جلویی رو Invalidate میکنید که کنترل خودتون Paint شده، نه وقتی که تازه درخواست Paint کردید.

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

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

بالا