Прозрачные изображения с C# WinForms

Я работаю над приложением Windows Forms в VS 2008 и хочу отображать одно изображение поверх другого, причем верхнее изображение представляет собой gif или что-то с прозрачными частями.

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

Я пытался использовать picturebox, но, похоже, это не сработало, какие-либо предложения?


person Fiona    schedule 27.12.2008    source источник
comment
Ответ на повторяющийся вопрос здесь (то же самое относится и к С#) - each-other#394478" title="как vbnet обрабатывает прозрачность изображений с изображениями, расположенными друг над другом%23394478"> stackoverflow.com/questions/394426/ stackoverflow.com/questions/392257/   -  person user21826    schedule 28.12.2008
comment
Ссылка на дубликат ответа не работает   -  person Christian Gibbs    schedule 05.12.2019


Ответы (6)


Я был в похожей ситуации пару дней назад. Вы можете создать прозрачный элемент управления для размещения вашего изображения.

using System;
using System.Windows.Forms;
using System.Drawing;

public class TransparentControl : Control
{
    private readonly Timer refresher;
    private Image _image;

    public TransparentControl()
    {
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        BackColor = Color.Transparent;
        refresher = new Timer();
        refresher.Tick += TimerOnTick;
        refresher.Interval = 50;
        refresher.Enabled = true;
        refresher.Start();
    }

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

    protected override void OnMove(EventArgs e)
    {
        RecreateHandle();
    }


    protected override void OnPaint(PaintEventArgs e)
    {
        if (_image != null)
        {
            e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
        }
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
       //Do not paint background
    }

    //Hack
    public void Redraw()
    {
        RecreateHandle();
    }

    private void TimerOnTick(object source, EventArgs e)
    {
        RecreateHandle();
        refresher.Stop();
    }

    public Image Image
    {
        get
        {
            return _image;
        }
        set
        {
            _image = value;
            RecreateHandle();
        }
    }
}
person Leon Tayson    schedule 12.01.2009
comment
Для чего нужен хак? Я не вижу внутреннего вызова Redraw. Когда его нужно вызвать? - person Greg Dean; 28.02.2009
comment
как видите, это Public. IIRC, я столкнулся с ошибкой при изменении размера формы закрепленного TransparentControl. Я думаю, что он исчезает из формы, поэтому я поставил этот метод Redraw вызываться из изменения размера формы. - person Leon Tayson; 01.03.2009
comment
работает отлично. Единственная проблема, с которой я столкнулся, заключается в том, что, в отличие от PictureBox, я не мог настроить автоматическое изменение размера или растяжение. Кроме этого, это работает как шарм. Спасибо Леон! - person GR7; 24.02.2010
comment
Для чего нужен таймер/обновление? - person Cheeso; 16.04.2010
comment
Установите ControlFlags.ResizeRedraw. - person SLaks; 08.06.2010
comment
Хак Redraw() был именно тем, что мне было нужно! - person simon.d; 26.01.2012
comment
@Slaks Я думаю, вы имеете в виду: SetStyle(ControlStyles.ResizeRedraw, true); - person BillW; 05.02.2014
comment
Этот код TransparentControl был для меня катастрофой, он даже не рисовал изображение, которое я установил, он рисовал какую-то другую часть пользовательского интерфейса случайным образом. Возможно, потому что мой пользовательский интерфейс скрыт при перерисовке... не уверен. Но непригодный для меня - person PandaWood; 15.12.2014
comment
Отлично! Но, к сожалению, когда элемент управления обновляется под изображением, часть изображения, которая находится непосредственно над ним, исчезает (здесь речь идет об оси Z). - person Hellon; 27.11.2018
comment
Обычно вы должны использовать Invalidate() для перерисовки изображения. RecreateHandle() — это излишество. - person Elmue; 06.10.2020

PictureBox имеет 2 слоя изображений: BackgroundImage и Image, которые вы можете использовать независимо друг от друга, включая рисование и очистку.

person Nav    schedule 14.10.2011

Поместите большое/нижнее изображение в PictureBox, затем добавьте обработчик к событию OnPaint и используйте одну из перегрузок e.Graphics.DrawImage(). Вы можете загрузить изображение, используя Image.FromFile().

Маленькое/верхнее изображение должно иметь альфа-канал и быть прозрачным в фоновом режиме, чтобы наложение работало. Вы должны легко убедиться в этом в Photoshop или чем-то подобном. Убедитесь, что вы сохраняете в формате, который поддерживает альфа-канал, например PNG.

person Jon Grant    schedule 27.12.2008

Код vb.net (Все кредиты Леону Тайсону):

Imports System
Imports System.Windows.Forms
Imports System.Drawing

Public Class TransparentControl
    Inherits Control

    Private ReadOnly Local_Timer As Timer
    Private Local_Image As Image

    Public Sub New()
        SetStyle(ControlStyles.SupportsTransparentBackColor, True)
        BackColor = Color.Transparent
        Local_Timer = New Timer
        With Local_Timer
            .Interval = 50
            .Enabled = True
            .Start()
        End With

        AddHandler Local_Timer.Tick, AddressOf TimerOnClick

    End Sub

    Protected Overrides ReadOnly Property CreateParams() As System.Windows.Forms.CreateParams
        Get
            Dim cp As CreateParams
            cp = MyBase.CreateParams
            cp.ExStyle = &H20
            Return cp
        End Get
    End Property

    Protected Overrides Sub OnMove(ByVal e As System.EventArgs)
        MyBase.OnMove(e)
        RecreateHandle()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)

        If Local_Image IsNot Nothing Then _
            e.Graphics.DrawImage(Local_Image, New Rectangle(0, 0, (Width / 2) - (Local_Image.Width / 2), (Height / 2) - (Local_Image.Height / 2)))

    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
        ' DO NOT PAINT BACKGROUND
    End Sub

    ''' <summary>
    ''' Hack
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub ReDraw()
        RecreateHandle()
    End Sub

    Private Sub TimerOnClick(ByVal sender As Object, ByVal e As System.EventArgs)
        RecreateHandle()
        Local_Timer.Stop()

    End Sub

    Public Property Image As Image
        Get
            Return Local_Image
        End Get
        Set(ByVal value As Image)
            Local_Image = value
            RecreateHandle()
        End Set
    End Property
End Class
person MiBol    schedule 20.08.2012
comment
как я это использую? - person RanJS; 01.10.2019

Список похожих сообщений указан внизу этого ответа.

Этот ответ касается pictureBoxes и Winforms (в других сообщениях ниже некоторые повторяют, что WPF уже хорошо решает эту проблему)

  1. Создать Винформ
  2. Create x2 pictureBoxes
    • foreground_pictureBox // picture box 'in front' of 'background'
    • background_pictureBox // поле изображения «позади» «переднего плана»
  3. Add the 'paint' event for each pictureBox
    • select object in the 'designer'
    • выберите вкладку «Свойства» (или щелкните правой кнопкой мыши и выберите из всплывающего меню)
    • выберите кнопку событий (маленькая молния)
    • дважды щелкните в пустом поле справа от события 'paint'
  4. Добавьте следующий код в функцию «загрузки» основной формы (если он еще не добавлен, используйте подход, описанный в шаге 3, и выберите «при загрузке», а не «рисовать»)

=

private void cFeedback_Form_Load(object sender, EventArgs e)
{
    ...
    // Ensure that it is setup with transparent background
    foreground_pictureBox.BackColor = Color.Transparent;

    // Assign it's 'background'
    foreground_pictureBox.Parent = background_pictureBox;
    ...
}

5 . В вызове «краска» для «background_pictureBox»:

=

private void background_pictureBox_Paint(object sender, PaintEventArgs e)
{
    ...foreground_pictureBox_Paint(sender, e);
}

6 . В вызове foreground_pictureBox_Paint добавьте любые графические вызовы, которые вы хотите отображать на переднем плане.

Эта тема повторяется в нескольких сообщениях, кажется:

как сделать-picturebox-прозрачным

c-sharp-picturebox-transparent-background-doesnt-see- на работу

make-overlapping-picturebox-transparent-in-c-net

проблема-picturebox

person S. Arseneau    schedule 26.02.2014

Я всегда обнаруживал, что мне приходилось самому компоновать изображения, используя одно изображение или элемент управления. Наличие двух ящиков для изображений с прозрачными частями никогда не работало для меня.

person Charlie Salts    schedule 28.12.2008