كيفية إنشاء عنصر تحكم شفاف يعمل عند أعلى عناصر التحكم الأخرى؟

StackOverflow https://stackoverflow.com/questions/592538

سؤال

لدي عنصر تحكم (مشتق من System.windows.forms.control) الذي يجب أن يكون شفافا في بعض المناطق. لقد قمت بتنفيذ هذا باستخدام SetStyle ():

public TransparentControl()
{
    SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    this.BackColor = Color.Transparent.
}

الآن، يعمل هذا إذا لم تكن هناك عناصر تحكم بين النموذج والتحكم الشفاف. ومع ذلك، إذا حدث هناك عنصر تحكم آخر أسفل عنصر التحكم الشفاف (وهو حالة الاستخدام هنا)، فهذا لا يعمل. لا يتم رسم السيطرة الوسيطة، ولكن النموذج أدناه يظهر من خلال. يمكنني الحصول على التأثير الذي أحتاجه عن طريق تجاوز العقلق وإعداد FLASG WS_EX_TRANSPART مثل ذلك:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
        return cp;
    }
}

المشكلة هنا هي أنه حقا يبطئ لوحة التحكم. التحكم بالفعل مزدوج مؤقتا، لذلك لا شيء للقيام به هناك. ضرب الأداء سيء للغاية أنه غير مقبول. هل واجه أحدا آخر هذه المشكلة؟ جميع الموارد التي يمكنني العثور عليها تشير إلى اقتراح باستخدام الطريقة رقم 1، ولكن مرة أخرى، لا يعمل هذا في حالتي.

تحرير: يجب أن أشير إلى أن لدي حلوة. يمكن للضوابط الفردية (الشفافة) أن ترسم نفسها ببساطة على كائن الرسومات الأصل، لكنها غير فعالة حقا ولا أحب الحل على الإطلاق (على الرغم من أنه قد يكون كل ما لدي).

Edit2: لذا، بعد النصيحة التي حصلت عليها حول كيفية عمل الشفافية في .NET، قمت بتنفيذ واجهة IContainer في عنصر تحكم المستخدم الخاص بي والتي تحتوي على عناصر تحكم شفافة. لقد قمت بإنشاء فئة تقوم بتنفيذ ISITE، وأضيف عناصر تحكم طفلي إلى مجموعة المكونات من UserControl، وهي خطوط خاصية الحاويات بشكل صحيح في المصحح، لكن ما زلت لا أحصل على تأثير شفافية. هل لدى أي شخص أي أفكار؟

هل كانت مفيدة؟

المحلول 5

قررت ببساطة طلاء الوالد تحت ضوابط طفلي يدويا. هنا مقال جيد.

نصائح أخرى

هذا مجرد شيء بسيط طهيه .. المشكلة الوحيدة التي وجدتها هي أنه لا يتم تحديثه عند تحديث عناصر التحكم بين التقاطع ..

إنه يعمل عن طريق رسم عنصر تحكم وراءه / يتقاطع مع التحكم الحالي إلى صورة نقطية، ثم رسم صورة نقطية للتحكم الحالي ..

protected override void OnPaint(PaintEventArgs e)
{
    if (Parent != null)
    {
        Bitmap behind = new Bitmap(Parent.Width, Parent.Height);
        foreach (Control c in Parent.Controls)
            if (c.Bounds.IntersectsWith(this.Bounds) & c != this)
                c.DrawToBitmap(behind, c.Bounds);
        e.Graphics.DrawImage(behind, -Left, -Top);
        behind.Dispose();
    }
}

يتم تنفيذ الضوابط الشفافة في dotnet من خلال وجود التحكم الشفاف حاوية ارسم نفسها في نافذة التحكم الشفاف ثم امتلاك السيطرة الشفافة تعادل نفسها. هذه العملية لا تأخذ في الاعتبار إمكانية عناصر التحكم المتداخلة. لذلك سوف تحتاج إلى استخدام نوع من العمل لجعله يعمل.

في بعض الحالات، كان لدي نجاحا مع تعشش معقد، لكن هذا في الغالب جيد فقط لطبقات سريعة وقذرة من الصور النقطية، ولا يحل أي مشاكل مع عناصر تحكم متداخلة جزئيا.

اكتشفت أن التعديلات أدناه تجعل الأمور أسرع قليلا:

if((this.BackColor == Color.Transparent) && (Parent != null)) {
    Bitmap behind = new Bitmap(Parent.Width, Parent.Height);
    foreach(Control c in Parent.Controls) {
        if(c != this && c.Bounds.IntersectsWith(this.Bounds)) {
            c.DrawToBitmap(behind, c.Bounds);
        }
    }
    e.Graphics.DrawImage(behind, -Left, -Top);
    behind.Dispose();
}

أعتقد أيضا أن استخدام this.Width / this.Height بدلا من Parent.Width / Parent.Height سيكون أسرع، لكنني لم يكن لدي وقت للعبث به.

رسم الأشقاء تحت السيطرة ممكن، لكنه قبيح. يعمل الكود أدناه بشكل معقول بالنسبة لي، إنه يتوسع على التعليمات البرمجية الواردة في الرابط إد س إجابه.

المقاتل المحتمل:

  • DrawToBitmap تم تقديمه مع .NET 2.0، لذلك لا تتوقع أن تعمل مع أي شيء أكبر سنا من ذلك. ولكن حتى ذلك الحين قد يكون هناك شيء من هذا القبيل من خلال إرسال WM_Print إلى التحكم في الأخوة؛ afaik هذا ما يفعله drawtobitmap داخليا.
  • قد يكون لديك أيضا مشاكل إذا كان لديك أدوات تحكم تحت سيطرتك التي تستفيد منها WS_EX_TRANSPARENT منذ ذلك الحين MSDN. هذه feddles نمط النافذة مع ترتيب اللوحة. ليس لدي أي عناصر تحكم تستخدم هذا النمط حتى لا أستطيع أن أقول.
  • أنا أقوم بتشغيل XP SP3 مع VS2010، لذلك قد يكون لهذا النهج مشاكل إضافية في نظام التشغيل Vista أو W7.

إليك الرمز:

if (Parent != null)
{
    float
        tx = -Left,
        ty = -Top;

    // make adjustments to tx and ty here if your control
    // has a non-client area, borders or similar

    e.Graphics.TranslateTransform(tx, ty);

    using (PaintEventArgs pea = new PaintEventArgs(e.Graphics,e.ClipRectangle))
    {
        InvokePaintBackground(Parent, pea);
        InvokePaint(Parent, pea);
    }

    e.Graphics.TranslateTransform(-tx, -ty);

    // loop through children of parent which are under ourselves
    int start = Parent.Controls.GetChildIndex(this);
    Rectangle rect = new Rectangle(Left, Top, Width, Height);
    for (int i = Parent.Controls.Count - 1; i > start; i--)
    {
        Control c = Parent.Controls[i];

        // skip ...
        // ... invisible controls
        // ... or controls that have zero width/height (Autosize Labels without content!)
        // ... or controls that don't intersect with ourselves
        if (!c.Visible || c.Width == 0 || c.Height == 0 || !rect.IntersectsWith(new Rectangle(c.Left, c.Top, c.Width, c.Height)))
            continue;

        using (Bitmap b = new Bitmap(c.Width, c.Height, e.Graphics))
        {
            c.DrawToBitmap(b, new Rectangle(0, 0, c.Width, c.Height));

            tx = c.Left - Left;
            ty = c.Top - Top;

            // make adjustments to tx and ty here if your control
            // has a non-client area, borders or similar

            e.Graphics.TranslateTransform(tx, ty);
            e.Graphics.DrawImageUnscaled(b, new Point(0, 0));
            e.Graphics.TranslateTransform(-tx, -ty);
        }
}

بعض الاقتراحات (الاعتذار عن رمز VB).

حاول تجنب اللوحة الخلفية:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If m.Msg = &H14 Then
        Return
    End If
    MyBase.WndProc(m)
End Sub

Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
    Return
End Sub

لا تسمي طريقة الطلاء قاعدة الضوابط:

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    'MyBase.OnPaint(e) - comment out - do not call
End Sub

هذا يفعل الخدعة، على الأقل لديها بالنسبة لي:

protected override void OnPaintBackground(PaintEventArgs e)
{
    //base.OnPaintBackground(e);
    this.CreateGraphics().DrawRectangle(new Pen(Color.Transparent, 1), new Rectangle(0, 0, this.Size.Width, this.Size.Height));
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top