使用 C# WinForms 的透明图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/395256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Transparent images with C# WinForms
提问by Fiona
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?
我一直在尝试使用图片框,但这似乎不起作用,有什么建议吗?
采纳答案by Leon Tayson
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();
}
}
}
回答by Jon Grant
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. You can load the image using Image.FromFile()
.
将大/底部图像放在 a 上PictureBox
,然后向OnPaint
事件添加处理程序并使用e.Graphics.DrawImage()
重载之一。您可以使用 加载图像Image.FromFile()
。
The small/top image will have to have an alpha channel and be transparent in the background for the overlay to work. You should be able to ensure this pretty easily in Photoshop or something similar. Make sure you save in a format that supports the alpha channel, such as PNG.
小/顶部图像必须有一个 alpha 通道并且在背景中是透明的,以便覆盖层工作。你应该能够在 Photoshop 或类似的东西中很容易地确保这一点。确保以支持 Alpha 通道的格式保存,例如 PNG。
回答by Charlie Salts
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.
我总是发现我必须自己合成图像,使用单个图片框或控件。有两个带有透明部分的图片框对我来说从来没有用过。
回答by Nav
PictureBox has 2 layers of images: BackgroundImage and Image, that you can use independently of each other including drawing and clearing.
PictureBox 有 2 层图像:BackgroundImage 和 Image,您可以独立使用它们,包括绘制和清除。
回答by MiBol
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
回答by S. Arseneau
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已经很好地解决了这个问题)
- Create Winform
- Create x2 pictureBoxes
- foreground_pictureBox // picture box 'in front' of 'background'
- background_pictureBox // picture box 'behind' the 'foreground'
- Add the 'paint' event for each pictureBox
- 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
- 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')
- 创建 Winform
- 创建 x2 个图片框
- foreground_pictureBox // '背景'之前的图片框
- background_pictureBox // '前景'后面的图片框
- 为每个图片框添加 'paint' 事件
- 在“设计器”中选择对象
- 选择“属性”选项卡(或右键单击并从弹出菜单中选择)
- 选择事件按钮(小闪电)
- 双击“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 . In the 'paint' call for the 'background_pictureBox':
5 . 在“background_pictureBox”的“paint”调用中:
=
=
private void background_pictureBox_Paint(object sender, PaintEventArgs e)
{
...foreground_pictureBox_Paint(sender, e);
}
6 . Within the 'foreground_pictureBox_Paint' call, add in whatever graphics calls you want to be displayed in the foreground.
6 . 在“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