Switching Images in Windows Forms - c#

I have 3 pictures, each one has a colored circle in it. The 3 pictures are red, green and yellow.
I'm putting it in a PictureBox in a windows form. I want to switch these images from green to yelow to red or otherwise.
Is there anything I can make them fade to each other instead of switching them the normal way?
I know this could be done using flash/j-query easily, but I was wondering how far I can achieve .
Something similar in windows forms using normal windows forms functionality.
Note: I'm using .net framework 4 and windows forms.

See Transition of images in Windows Forms Picture box. There is a solution that transitions the images using a timer on this page.
Code from site:
public class BlendPanel : Panel
{
private Image mImg1;
private Image mImg2;
private float mBlend;
public BlendPanel()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer, true);
}
public Image Image1
{
get { return mImg1; }
set { mImg1 = value; Invalidate(); }
}
public Image Image2
{
get { return mImg2; }
set { mImg2 = value; Invalidate(); }
}
public float Blend
{
get { return mBlend; }
set { mBlend = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
if (mImg1 == null || mImg2 == null)
{
e.Graphics.FillRectangle(new SolidBrush(this.BackColor),
new Rectangle(0, 0, this.Width, this.Height));
}
else
{
Rectangle rc = new Rectangle(0, 0, this.Width, this.Height);
ColorMatrix cm = new ColorMatrix();
ImageAttributes ia = new ImageAttributes();
cm.Matrix33 = mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg2, rc, 0, 0, mImg2.Width,
mImg2.Height, GraphicsUnit.Pixel, ia);
cm.Matrix33 = 1F - mBlend;
ia.SetColorMatrix(cm);
e.Graphics.DrawImage(mImg1, rc, 0, 0, mImg1.Width,
mImg1.Height, GraphicsUnit.Pixel, ia);
}
base.OnPaint(e);
}
}
Build your project. You can now drop a BlendPanel from the top of the toolbox onto your form. Here's a sample program that uses it:
namespace WindowsApplication1
{
public partial class Form1 : Form
{
private float mBlend;
private int mDir = 1;
public Form1()
{
InitializeComponent();
timer1.Interval = 30;
timer1.Tick += BlendTick;
blendPanel1.Image1 = Bitmap.FromFile(#"c:\temp\test1.bmp");
blendPanel1.Image2 = Bitmap.FromFile(#"c:\temp\test2.bmp");
timer1.Enabled = true;
}
private void BlendTick(object sender, EventArgs e)
{
mBlend += mDir * 0.02F;
if (mBlend < 0) { mBlend = 0; mDir = 1; }
if (mBlend > 1) { mBlend = 1; mDir = -1; }
blendPanel1.Blend = mBlend;
}
}
}
You'll need to modify the Bitmap.FromFile() calls. Build and run. You should see the displayed image smoothly morph from your first image to your second image without any flickering. Lots of ways to tweak the code, have fun.

I don't know if it is a good idea, but i would go for 2 image boxes, one to fade in, other to fade out, and change alpha when time passes.

Like what #Igoris suggested, You need to use two controls overlap each other, and you should define a timer so when you want to fade in or out, start the timer and in its tick decrease the Transparent of the first control and increase it on the second one... , the problem is that the ordinary controls does not support transparent by default. so you have to inherit it and apply transparent here is a custom TransparentPictureBox that inherited from PictureBox:
public class TransparentPictureBox : System.Windows.Forms.PictureBox
{
/// <summary>
/// Initialize new instance of this class.
/// </summary>
public TransparentPictureBox()
: base()
{
DoubleBuffered = true;
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.BackColor = Color.Transparent;
}
}

Related

How to pass parameters in C# GDI+ Windows Desktop

I'm interested in learning about C# GDI+ and have googled many tutorials. I'm attempting to create a simple windows form that has two textbox controls and a button. I simply want to put a length dimension in one textbox and a height dimension in the other, click the button and have the app draw the rectangle on the window using those two entered dimensions. To date, all I have been able to do is locate tutorials where the rectangle parameters are hardcoded into the Form_Load and Form_Paint. How would I take the user input from the textboxes and pass them to make the app refresh and draw the rectangles on the button click?
Please let me know if more info is needed.
Thanks in advance for your knowledge!
public partial class Form1 : Form
{
Bitmap drwBitmap;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics graphicObj;
drwBitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
graphicObj = Graphics.FromImage(drwBitmap);
graphicObj.Clear(Color.White);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
Rectangle rectObj;
rectObj = new Rectangle(10, 10, 100, 200);
graphicObj.DrawEllipse(myPen, rectObj);
graphicObj.Dispose();
}
private void Form1_Paint(object sender, PaintEventArgs e, Graphics graphicsObj)
{
Graphics graphicsObj1 = graphicsObj;
graphicsObj1.DrawImage(drwBitmap, 0, 0, drwBitmap.Width, drwBitmap.Height);
graphicsObj.Dispose();
}
The current approach is quite strange as it draws directly to the form. It's difficult to modify as a bitmap is created early on and then must somehow be changed. Furthermore, there is no need for a bitmap.
A better approach is to create a custom control:
public class EllipseControl : Control
{
private float m_ellipseWidth = 200;
private float m_ellipseHeight = 120;
public float EllipseWidth
{
get { return m_ellipseWidth; }
set
{
m_ellipseWidth = value;
Invalidate();
}
}
public float EllipseHeight
{
get { return m_ellipseHeight; }
set
{
m_ellipseHeight = value;
Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var graphics = e.Graphics;
using Pen pen = new Pen(System.Drawing.Color.Red, 3);
graphics.DrawEllipse(pen, 0, 0, EllipseWidth, EllipseHeight);
}
}
This control can then be placed on the form. It has two properties: EllipseWidth and EllipseHeight.
In the event handler for the button click, you can take the values from the text fields and set them on the ellipse control.

Trying to add user control to form crashes Visual Studio

I created a UserControl called Switch.
I built my project and this UC successfully shown in my toolbox.
So I tried to add it to my frmMain by dragging it to the form. But at this moment, Visual Studio always shows an error message:
A new guard page for the stack cannot be created.
After clicking OK, devenv.exe crashes.
I have to mention, that I have another user control in the same namespace and folder as Switch. This UC works fine.
This is the code of my Switch user control:
public partial class Switch : UserControl
{
private Rectangle switchRectangle;
private int xOn = 0; // switchRectangle x position, when switch is on
private int xOff = 0; // switchRectangle x position, when switch is off
private Color SwitchColor = Color.Black;
private Color OuterRectangleColor = Color.DarkGray;
private Color InnerRectangleColor
{
get { return this.On ? Color.DodgerBlue : InnerRectangleColor; }
}
public bool On { get; set; }
public Switch()
{
InitializeComponent();
ReloadSwitchRectangle();
xOn = this.Width - switchRectangle.Width;
}
private void Switch_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(this.BackColor);
// Create inner rectangle, on every side by 2px smaller than ClientRectangle
const int amountToDecrease = 2;
Rectangle innerRectangle = new Rectangle(this.ClientRectangle.X + amountToDecrease, this.ClientRectangle.Y + amountToDecrease,
this.ClientRectangle.Width - amountToDecrease * 2, this.ClientRectangle.Height - amountToDecrease * 2);
ReloadSwitchRectangle();
e.Graphics.DrawRectangle(new Pen(OuterRectangleColor), this.ClientRectangle); // Draw outer rectangle
e.Graphics.FillRectangle(new SolidBrush(InnerRectangleColor), innerRectangle); // Fill inner rectangle
e.Graphics.FillRectangle(new SolidBrush(SwitchColor), switchRectangle);
}
private void ReloadSwitchRectangle()
{
int x = this.On ? xOn : xOff;
switchRectangle = new Rectangle(x, 0, this.Width / 5, this.Height);
}
}
This is the problem:
private Color InnerRectangleColor
{
get { return this.On ? Color.DodgerBlue : InnerRectangleColor; }
}
You have infinite recursion here when this.On is set to false.
Thanks to Sriram Sakthivel, I solved my problem like this:
private Color InnerRectangleColor
{
get { return this.On ? Color.DodgerBlue : OuterRectangleColor; }
}

Custom control in a UserControl does not render correctly

In this picture...
... you can see next to each "Line Color" label there is a colored circle.
The colored circle is, in my project, a Swatch. Here is the entire code file for Swatch:
public class Swatch : System.Windows.Forms.Panel
{
/*private int _Radius = 20;
[System.ComponentModel.Category("Layout")]
public int Radius
{
get { return _Radius; }
set { _Radius = value; }
} */
private System.Drawing.Color _BorderColor = System.Drawing.Color.Transparent;
[System.ComponentModel.Category("Appearance")]
public System.Drawing.Color BorderColor
{
get { return _BorderColor; }
set { _BorderColor = value; }
}
private System.Drawing.Color _FillColor = System.Drawing.Color.Blue;
[System.ComponentModel.Category("Appearance")]
public System.Drawing.Color FillColor
{
get { return _FillColor; }
set { _FillColor = value; }
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
base.OnPaint(e);
System.Drawing.Rectangle RealRect = new System.Drawing.Rectangle(e.ClipRectangle.Location, e.ClipRectangle.Size);
RealRect.Inflate(-1, -1);
int Radius = Math.Min(RealRect.Size.Height, RealRect.Size.Width);
System.Drawing.Rectangle SqRect = new System.Drawing.Rectangle();
SqRect.Location = RealRect.Location;
SqRect.Size = new System.Drawing.Size(Radius, Radius);
System.Drawing.Drawing2D.CompositingQuality PrevQual = e.Graphics.CompositingQuality;
using (System.Drawing.SolidBrush Back = new System.Drawing.SolidBrush(this.FillColor))
{
using (System.Drawing.Pen Pen = new System.Drawing.Pen(new System.Drawing.SolidBrush(this.BorderColor)))
{
//e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
e.Graphics.FillEllipse(Back, SqRect);
e.Graphics.DrawEllipse(Pen, SqRect);
}
}
e.Graphics.CompositingQuality = PrevQual;
}
public Swatch()
{
this.SetStyle(System.Windows.Forms.ControlStyles.UserPaint, true);
this.SetStyle(System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(System.Windows.Forms.ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(System.Windows.Forms.ControlStyles.ResizeRedraw, true);
this.SetStyle(System.Windows.Forms.ControlStyles.SupportsTransparentBackColor, true);
this.DoubleBuffered = true;
}
}
Each row is a UserControl which consists of a TableLayoutPanel, labels, a Swatch control, and a NumericUpDown box.
There about 10 rows and they are placed in TableLayoutPanel, which sits inside a TabPage on a tab control. The tab page has AutoScroll set to true so that overflow causes the tab page to scroll.
The problem is that whenever I run the application and scroll up and down, the Swatches (the colored circles) tear and show all sorts of artifacts, as seen in the picture above. I'd like to have clean scrolling with no rendering artifacts.
I've tried using SetStyle (as suggested here Painting problem in windows form) but it has had no effect.
The UserControl (each row) has DoubleBuffered set to true, and that too has had no effect either.
I fear I am missing something rather obvious.
The problem is that you calculate the radius of the circle based on the clipping rectangle. So when the line is only partially visible a bad value is resulted.
You should calculate it based on the real rectangle, the one provided by the base class, and let it being clipped normally.

Making a control transparent

I am currently developing a simple image editing tool using Winforms and .NET 3.5 (work environment).
I have a requirement that when the user clicks a select tool button, a square (rectangle in C#) will appear that they can scale between 100x100 and 400x400. I have this bit fixed - the issue comes with making the background of the rectangle transparent.
I'm a little unclear on if transparency is supported in .NET 3.5, I've tried the following:
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
pnlSelectArea.BackColor = Color.Transparent;
pnlSelectArea.ForeColor = Color.Transparent;
selectArea1.BackColor = Color.Transparent;
selectArea1.ForeColor = Color.Transparent;
But this has no effect - any advice would be appreciated.
This is my special Control which contains an opacity property, it 100% works:
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
public class TranspCtrl : Control
{
public bool drag = false;
public bool enab = false;
private int m_opacity = 100;
private int alpha;
public TranspCtrl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Opaque, true);
this.BackColor = Color.Transparent;
}
public int Opacity
{
get
{
if (m_opacity > 100)
{
m_opacity = 100;
}
else if (m_opacity < 1)
{
m_opacity = 1;
}
return this.m_opacity;
}
set
{
this.m_opacity = value;
if (this.Parent != null)
{
Parent.Invalidate(this.Bounds, true);
}
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | 0x20;
return cp;
}
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle bounds = new Rectangle(0, 0, this.Width - 1, this.Height - 1);
Color frmColor = this.Parent.BackColor;
Brush bckColor = default(Brush);
alpha = (m_opacity * 255) / 100;
if (drag)
{
Color dragBckColor = default(Color);
if (BackColor != Color.Transparent)
{
int Rb = BackColor.R * alpha / 255 + frmColor.R * (255 - alpha) / 255;
int Gb = BackColor.G * alpha / 255 + frmColor.G * (255 - alpha) / 255;
int Bb = BackColor.B * alpha / 255 + frmColor.B * (255 - alpha) / 255;
dragBckColor = Color.FromArgb(Rb, Gb, Bb);
}
else
{
dragBckColor = frmColor;
}
alpha = 255;
bckColor = new SolidBrush(Color.FromArgb(alpha, dragBckColor));
}
else
{
bckColor = new SolidBrush(Color.FromArgb(alpha, this.BackColor));
}
if (this.BackColor != Color.Transparent | drag)
{
g.FillRectangle(bckColor, bounds);
}
bckColor.Dispose();
g.Dispose();
base.OnPaint(e);
}
protected override void OnBackColorChanged(EventArgs e)
{
if (this.Parent != null)
{
Parent.Invalidate(this.Bounds, true);
}
base.OnBackColorChanged(e);
}
protected override void OnParentBackColorChanged(EventArgs e)
{
this.Invalidate();
base.OnParentBackColorChanged(e);
}
}
You will need to use Opacity property and set it to zero to make form invisible.
If you want to make a control Transparent, as you have tried in your example, See this article
How to: Give Your Control a Transparent Background
It say the code you have written, must be in constructor of the control. Hence, I guess, you will need to create a custom control derived from your pnlSelectArea 's type most probaably a button. In in that custom control's constructor you can write code to set its style and color.
Here is what worked for me with because the other solutions did not work.
This is with transparent UserControl added to ListView/TreeView Control Collection
I know it says ButtonRenderer but it should work for any controls.
In the UserControl:
protected override void OnPaint(PaintEventArgs e)
{
ButtonRenderer.DrawParentBackground(e.Graphics, this.ClientRectangle, this);
}
in the Parent control:
protected override void WndProc(ref Message m)
{
if(m.Msg == 0xF)
foreach(Control c in this.Controls) { c.Invalidate(); c.Update(); }
base.WndProc(ref m);
}
great!!
I finally managed to draw transparent shapes.
I've added a virtual method
Draw(g);
right before
bckColor.Dispose();
g.Dispose();
base.OnPaint(e);
and at the end the declaration of the virtual method
protected virtual void Draw(Graphics g){ }
Now I can continue creating my own Transparent shapes, graphics etc ...
There is one simple workaround for this. You can create an image with a transparent background (PNG) and add it for the Image property of the icon. This works fine as information does not have much flexibility in styling. Sometime this might not be suitable for everyone. Remember this is only a workaround.
PS:
Add where ever the text on the image and keep blank for the text property.

Stuck trying to get my c# text scroller to run smoothly

I'm doing a small project where my vc# application needs to include a text scroller / news ticker. Application will be running on 30+ screens showing off internal ad production at my workplace.
I've been googling and testing for a couple of months now but has yet to find / create a good solution where the movement is smooth and not choppy.
So my question is: is it possible to create perfect smooth scroll motion in c# or do I need to go about it some other way?
The code I'm using at the moment, part of a sample I edited, is running almost smooth except it seems to lag every 100 ms or so.
Here is the code I'm using:
namespace ScrollDemo1
{
public partial class NewsTicker : Panel
{
private Timer mScroller;
private int mOffset;
private string mText;
private Size mPixels;
private Bitmap mBuffer;
public NewsTicker()
{
mScroller = new Timer();
mScroller.Interval = 1;
mScroller.Enabled = false;
mScroller.Tick += DoScroll;
}
[Browsable(true)]
public override string Text
{
get { return mText; }
set
{
mText = value;
mScroller.Enabled = mText.Length > 0;
mPixels = TextRenderer.MeasureText(mText, this.Font);
mOffset = this.Width;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
private void DoScroll(object sender, EventArgs e)
{
mOffset -= 1;
if (mOffset < -mPixels.Width) mOffset = this.Width;
Invalidate();
Update();
}
protected override void OnPaint(PaintEventArgs e)
{
if (mBuffer == null || mBuffer.Width != this.Width || mBuffer.Height != this.Height)
mBuffer = new Bitmap(this.Width, this.Height);
Graphics gr = Graphics.FromImage(mBuffer);
Brush bbr = new SolidBrush(this.BackColor);
Brush fbr = new SolidBrush(this.ForeColor);
Bitmap bmp = global::ScrollDemo1.Properties.Resources.text_bg1;
TextureBrush tb = new TextureBrush(bmp);
int iLoc = (this.Height / 2) - (mPixels.Height / 2);
//Console.WriteLine(iLoc.ToString());
//gr.FillRectangle(bbr, new Rectangle(0, 0, this.Width, this.Height));
gr.FillRectangle(tb, new Rectangle(0, 0, this.Width, this.Height));
gr.DrawString(mText, this.Font, fbr, mOffset, iLoc);
e.Graphics.DrawImage(mBuffer, 0, 0);
bbr.Dispose();
fbr.Dispose();
gr.Dispose();
}
}
}
I'd suggest you go with WPF. It has rich and easy to use support for animations and tends to be be very smooth since it is Direct3D based.

Categories