2012-06-30 4 views
7

Я пытался отобразить изображение с прозрачной рамкой в ​​качестве фона для элемента управления.Управление чертежом с прозрачным фоном

К сожалению, прозрачная область создает отверстие в родительской форме следующим образом:

В изображении выше, форма имеет красный фон, который я надеялся увидеть за моим контролем в прозрачные области.

Код я использовал следующим образом:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 
    { 
     if (this.Image != null) 
     { 
      Graphics g = Graphics.FromImage(this.Image); 

      ImageAttributes attr = new ImageAttributes(); 

      //set the transparency based on the top left pixel 
      attr.SetColorKey((this.Image as Bitmap).GetPixel(0, 0), (this.Image as Bitmap).GetPixel(0, 0)); 

      //draw the image using the image attributes. 
      Rectangle dstRect = new Rectangle(0, 0, this.Image.Width, this.Image.Height); 

      e.Graphics.DrawImage(this.Image, dstRect, 0, 0, this.Image.Width, this.Image.Height, 
       GraphicsUnit.Pixel, attr); 
     } 
     else 
     { 
      base.OnPaint(e); 
     } 
    } 

    protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e) 
    { 
     //base.OnPaintBackground(e); 
    } 

Этот класс наследуется от PictureBox, потому что мне нужен был контроль, который реализует OnMouseMove и OnMouseUp событий.

Я изучаю большую часть дня без успеха, проверяя различные идеи, но, к сожалению, большинство из них работают только на полной основе, а не на .Net CF.

Любые идеи были бы высоко оценены.

ответ

6

А радости прозрачности CF. Я мог бы продолжать и продолжать (и есть in my blog и Project Resistance code Я много лет назад).

Суть в том, что это. Детский элемент управления должен рисовать его области, но сначала он должен вернуться к родительскому элементу (форма в вашем случае) и сказать ему перерисовать его фоновое изображение всюду, кроме области отсечения для ребенка, а затем нарисовать себя поверх этого , Если это звучит немного запутанно, это потому, что это так.

Например, если вы посмотрите на Project Resistance, вид (который является просто элементом управления) рисует резистор и полосы. Он находится в форме, которая имеет фоновое изображение, а фон должен «показать через» прозрачные области резистора:

enter image description here

Таким образом, в чертежной код резистора он делает это:

protected override void OnPaint(PaintEventArgs e) 
{ 
    base.OnPaint(e); 

    try 
    { 
     RECT rect = new RECT(this.Bounds); 

     // draw the blank 
     Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_blankImage, Bounds, 
       new Rectangle(0, 0, m_blankImage.Width, m_blankImage.Height)); 

     if (m_bandsImage != null) 
     { 
      // draw the bands 
      Infrastructure.GraphicTools.DrawTransparentBitmap(e.Graphics, m_bandsImage, Bounds, 
       new Rectangle(0, 0, m_bandsImage.Width, m_bandsImage.Height)); 
     } 
    } 
    finally 
    { 
    } 

    if (!Controller.TouchMode) 
    { 
     // TODO: draw in the selection arrow 
     // Controller.SelectedBand 
    } 
} 

Это достаточно просто. Ключ в том, что она требует, чтобы это основание OnPaint, который делает это:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) 
{ 
    // this assumes we're in a workspace, on MainForm (the whole Parent.Parent thing) 
    IBackgroundPaintProvider bgPaintProvider = Parent.Parent as IBackgroundPaintProvider; 
    if (bgPaintProvider != null) 
    { 
     Rectangle rcPaint = e.ClipRectangle; 
     // use the parent, since it's the workspace position in the Form we want, 
     // not our position in the workspace 
     rcPaint.Offset(Parent.Left, Parent.Top); 
     bgPaintProvider.PaintBackground(e.Graphics, e.ClipRectangle, rcPaint); 
    } 
} 

Вы можете видеть, что это звонит PaintBackground из вмещающей формы (это parent.parent в этом случае becuse Контроль на самом деле в контейнере называется Рабочее пространство - вам не нужно будет дважды подниматься в вашем случае). Это рисует фоновое изображение в области, которую вы сейчас видите как «отверстие»

public void PaintBackground(Graphics g, Rectangle targetRect, Rectangle sourceRect) 
{ 
    g.DrawImage(m_bmBuffer, targetRect, sourceRect, GraphicsUnit.Pixel); 
} 
+0

Вау, спасибо за это. Очень полезное и подробное объяснение. Вы, конечно, потратили некоторое время на эту тему. –

+0

@ctacke Я придумал решение Transparency, которое очень близко к вашему, и оно работает как в дизайнере, так и во время выполнения. Недавно я понял, что мое решение не будет работать, когда вложенные элементы управления контейнерами, потому что вещь «Parent.Parent» не работает. Я попытался переключить «Parent.Parent» на this.TopLevelControl, который работает во время выполнения, но не во время разработки. Где вы когда-либо могли получить решение для вложения прозрачных элементов управления внутри элементов управления контейнерами и все еще иметь конструктор, который делает ваш контроль прозрачным? –

+0

Я отказался даже от попыток получить дизайнерскую поддержку для своих элементов управления несколько лет назад. Это просто никогда не чувствовало, что это важно для меня и всегда было хрупким.Иногда это срабатывало, иногда это было не так, и я обнаружил, что сжигаю дни, фактически не делая ничего производительного, поэтому я просто никогда не беспокоюсь о том, чтобы дизайнер больше не укладывал прямоугольники, где будут проходить элементы управления. – ctacke

Смежные вопросы