简体   繁体   English

使用 C# WinForms 的透明图像

[英]Transparent images with C# WinForms

I am working on a Windows Forms application in VS 2008, and I want to display one image over the top of another, with the top image being a gif or something with transparent parts.我正在 VS 2008 中处理 Windows 窗体应用程序,我想在另一个图像的顶部显示一个图像,顶部图像是 gif 或带有透明部分的东西。

Basically I have a big image and I want to put a little image on top if it, so that they kinda appear as one image to the user.基本上我有一个大图像,我想在它上面放一个小图像,这样它们就可以作为一个图像呈现给用户。

I've been trying to use a picturebox, but this doesn't seem to have worked, any suggestions?我一直在尝试使用图片框,但这似乎不起作用,有什么建议吗?

I was in a similar situation a couple of days ago.几天前我也处于类似的情况。 You can create a transparent control to host your image.您可以创建一个透明控件来托管您的图像。

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();
        }
    }
}

PictureBox 有 2 层图像:BackgroundImage 和 Image,您可以独立使用它们,包括绘制和清除。

Put the big/bottom image on a PictureBox , then add a handler to the OnPaint event and use one of the e.Graphics.DrawImage() overloads.将大/底部图像放在PictureBox ,然后将处理程序添加到OnPaint事件并使用e.Graphics.DrawImage()重载之一。 You can load the image using Image.FromFile() .您可以使用Image.FromFile()加载图像。

The small/top image will have to have an alpha channel and be transparent in the background for the overlay to work.小/顶部图像必须有一个 alpha 通道并且在背景中是透明的,这样叠加层才能工作。 You should be able to ensure this pretty easily in Photoshop or something similar.你应该能够在 Photoshop 或类似的东西中很容易地确保这一点。 Make sure you save in a format that supports the alpha channel, such as PNG.确保以支持 Alpha 通道的格式保存,例如 PNG。

The vb.net code (All credits to Leon Tayson): vb.net 代码(全部归功于 Leon Tayson):

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

A list of similar posts is referenced at the bottom of this reply.此回复底部引用了类似帖子的列表。

This reply addresses pictureBoxes and Winforms (in the other posts below, several reiterate that WPF solves this well already)这个回复解决了pictureBoxes和Winforms(在下面的其他帖子中,有几个重申WPF已经很好地解决了这个问题)

  1. Create Winform创建 Winform
  2. Create x2 pictureBoxes创建 x2 个图片框
    • foreground_pictureBox // picture box 'in front' of 'background' foreground_pictureBox // '背景'之前的图片框
    • background_pictureBox // picture box 'behind' the 'foreground' background_pictureBox // '前景'后面的图片框
  3. Add the 'paint' event for each pictureBox为每个图片框添加 'paint' 事件
    • select object in the 'designer'在“设计器”中选择对象
    • choose the 'properties' tab (or right-click and choose from popup menu)选择“属性”选项卡(或右键单击并从弹出菜单中选择)
    • select the events button (small lightning bolt)选择事件按钮(小闪电)
    • double-click in the empty field to the right of the 'paint' event双击“paint”事件右侧的空白字段
  4. Add the following code to the main form's 'load' function (if not already added, use the approach in step 3 and select 'on load' rather than 'paint')将以下代码添加到主窗体的“加载”函数中(如果尚未添加,请使用步骤 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 . 5 . In the 'paint' call for the 'background_pictureBox':在“background_pictureBox”的“paint”调用中:

= =

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

6 . 6 . Within the 'foreground_pictureBox_Paint' call, add in whatever graphics calls you want to be displayed in the foreground.在“foreground_pictureBox_Paint”调用中,添加您希望在前台显示的任何图形调用。

This topic repeats itself in several posts it seems:这个话题似乎在几篇文章中重复出现:

how-to-make-picturebox-transparent 如何制作图片框透明

c-sharp-picturebox-transparent-background-doesnt-seem-to-work c-sharp-picturebox-transparent-background-doesnt-seek-to-work

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

a-picturebox-problem 图片框问题

I've always found that I've had to composite the images myself, using a single picturebox or control.我总是发现我必须自己合成图像,使用单个图片框或控件。 Having two pictureboxes with transparent parts has never worked for me.有两个带有透明部分的图片框对我来说从来没有用过。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM