C# transparent PNG for buttons, panels...how? - c#

I have being searching a lot, seen a few examples but they don't work at least for me. This is what I need: in my application I need to use transparent PNG icons for the toolbars and also for draggable visual objects representations, ie, 72x72 "page" icon which can be dragged around and possibly over all elements in the client area. For the first I was thinking about using a button, set its BackImage to the transparent PNG and put BackColor as "transparent": it won't work, the button always show a solid color behind. As for the panel, the same problem: I can put a transparent PNG as background image but the control never looks "transparent" where the PNG has transparent areas. I think the same with a picturebox and any other control allowing image backgrounds. So I guess, it is really about making a control's background transparent...Any ideas?
I don't care if I need to create some sort of custom "image button" or "image panel" --whatever-- to have truely PNG transparent buttons, panels, etc! Also, please note, it is about PNG transparency, using the alpha channel, not transparent pixels, which at this ages, sucks IMHO for decent GUIs.
Cheers
litium

Ok I found the following code whith works not only for panels but also for buttons and I guess other controls --except PictureBox:
public class TransparentPanel : Panel <==change to Button for instance, and works
{
Timer Wriggler = new Timer();
public TransparentPanel()
{
Wriggler.Tick += new EventHandler(TickHandler);
this.Wriggler.Interval = 500;
this.Wriggler.Enabled = true;
}
protected void TickHandler(object sender, EventArgs e)
{
this.InvalidateEx();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
protected void InvalidateEx()
{
if (Parent == null)
{
return;
}
Rectangle rc = new Rectangle(this.Location, this.Size);
Parent.Invalidate(rc, true);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// Do not allow the background to be painted
}
}
Works for me 100%! Doesn't seems to work for PictureBoxes.

Related

Winforms Transparent Panel Control - Hover, Click Through and Redraw Issues

I have followed a number of posts here and on other sites for creating a Transparent Panel control for WinForms that has "real" transparency (i.e. it does not just inherit the background color of the container it is in).
Here is my derived panel class so you can see how I did it:
namespace TransparencyPOC
{
public partial class TransPictureBox : Panel
{
public TransPictureBox()
{
InitializeComponent();
}
public TransPictureBox(IContainer container)
{
container.Add(this);
InitializeComponent();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//do nothing
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20; //WS_EX_TRANSPARENT
return cp;
}
}
private Image m_Image;
public Image Image
{
get
{
return m_Image;
}
set
{
m_Image = value;
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
Bitmap bmp = new Bitmap(m_Image);
bmp.MakeTransparent();
g.DrawImage(bmp, 0, 0, 100, 100);
g.Dispose();
}
}
}
I am using this panel control to hold a PNG with a transparent background, and need to be able to position it above other controls, such as other transparent panels, buttons, etc.
Two issues:
If I position this panel partially over a button control, I can only click the button in the areas where the panel doesn't overlap the control. Is there any way that I can make the hover and click events pass through the transparent panel so that when I hover or click anywhere over the button, even parts of the button that are obscured by the PNG that the button receives those clicks? Assume that this needs to be dynamic, i.e. I won't know what control the image is positioned above, just want it to be able to pass the hover and clicks through to whatever is beneath it.
When I do hover over part of the button that is not covered by the panel, the button repaints itself above the transparent panel (see image below for before and after)
Before Hovering:
After Hovering:
Questions:
Can I allow the button to be hoverable/clickable through the transparent panel? Ideally, I would want any visible portion of the underlying button to be hoverable/clickable, but if that's not doable, then I'd want it to be clickable/hoverable as if there was nothing above it.
Can I prevent the button from being redrawn over the panel when I do hover over it, and/or trigger a repaint of the panel when this happens?
Thank you in advance!

WinForm: How to implement button with correct background colors

I'm developing winform app with C#. And I created custom button inherent from UserControl as shown below:
public partial class UserButton : UserControl
{
public UserButton(string UserID)
{
this.Size = new Size(32, 50);
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
Img = WaseelaMonitoring.Properties.Resources.T;
g.DrawImage(Img, 0, 0, this.Size.Width, this.Size.Height);
}
}
Note: this is button png image (Click here)
Now, I want to show some buttons on picture box using this code:
UserButton TagButton1 = new UserButton("Button1");
TagButton1.Location = Points[0];
UserButton TagButton2 = new UserButton("Button2");
TagButton2.Location = Points[1];
UserButton TagButton3 = new UserButton("Button3");
TagButton1.Location = Points[2];
Picturebox1.Controls.Add(TagButton1);
Picturebox1.Controls.Add(TagButton2);
Picturebox1.Controls.Add(TagButton2);
Picturebox1.Invalidate();
Okay, when show only one button on the picture box, the background button is transparent(as I want) like this:
But if I want to show two or more buttons beside together the background button is white not transparent like this:
I'm using invalidate picture box and trying invalidate button also, but is not solve that problem.
WinForms does not support true Z-ordering of components; windowed controls (such as Button and UserControl) cannot have true alpha-channel support, and the this.Background - Color.Transparent trick is actually a special-case where the control will re-paint its parent's Background image or color to itself first.
If you are after a more flexible user-experience, I suggest switching to WPF, or doing all of your painting within a single WinForms Control.
I solved this problem by added this line to initializing constructor:
SetStyle(ControlStyles.Opaque, true);
And overridden this function:
protected override CreateParams CreateParams
{
get
{
const int WS_EX_TRANSPARENT = 0x00000020;
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}

Flickering with transparent panel

I've created a simple program and now i'm in the stages of doing my designing. I've got a multiple Panels which i make visible / invisible to switch between "tabs" (EG. 1 panel for the login screen and 1 panel for the create account screen). Now i've made these panels invisible because i want them just as containers to be able to quickly move around controls and create buttons in.
My problem is that i've set my forms background image to a image i made in photoshop and whenever i switch between panels it flickers, whenever i just use a system color (white,black) this doesn't happen.
Is there any way for me to remove the flickering?
i've tried :
Setting double buffer to true
protected overrideing OnPaint, CreateBackground, and Createparam
my code is extremely basic :
private void btnNewAcc_Click(object sender, EventArgs e)
{
PanelNewAccount.Visible = true;
PanelLogin.Visible = false;
}
Try to setting the form property DoubleBuffered to true, in winforms the flickering usually happens because the GDI+ is trying to draw the control(s) a lot of times so DoubleBuffering you graphics should help in such cases
form.DoubleBuffered = true;
Thanks to Patrick i've solved my problem,
instead of using panels i'm using a TabControl and i assigned the same background to each tab.
Just as easy to add dynamic buttons as well.
Same features as panels but without the flickering.
#region .. Double Buffered function ..
public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
return;
System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
aProp.SetValue(c, true, null);
}
#endregion
#region .. code for Flucuring ..
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
#endregion
Even though i am late but if somebody else is also suffering from the same problem then this code fixed the flickering for me even though i dont know how it works.
I found it here.
Add the above code snippet in your program and in the contructor of your app add this line:
SetDoubleBuffered(YourPanelName);
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
code copy from codeproject solved my problem.

Customizing default inputs?

I wonder if it's possible to customize my C# application (winforms) to get a better design, I made a PSD (photoshop document) so I can generate png jpeg... pictures if I need them.
Example of a form like the one I want :
Indeed as it was pointed out in the comments, it is easy to use WPF (indows Presentation Foundation) to achieve that result, but if you really need that it must be made in windows forms I can help you with that...
ControlBox and Border
It seens that your form does not have a control box (minimize, maximize and close buttons)
to achieve that you can set
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
I'm not sure if that galaxy behind your form is part of the application so i'll be considering that it is not
To achieve that irregular shape of the form we have to do a workaround here
Irregular Shape of the Form
we are going to set a Color to TransparentKey, so everything in the form in that specific color will be transparent, like it does not exists (if you click in that part it will go into de desktop or whatever application you have behind in your form)
So let's use a specific color which we will probably dont use in the form
form.TransparencyKey = Color.FromArgb(111, 111, 111); //You can do it by the editor
So in order to make that white part we are going to use an Panel and a PictureBox outsite of the Panel trying to copy the shape of your image
Stylized Inputs
To make it easier and reusable I'm going to make a userControl in this one
the usercontrol will have
a Panel called HighLightPanel, its dock property will be set to Fill
a Panel called BackColorPanel, it will be inside the HighLightPanel
a PictureBox called InputPicture, its dock property will be set to Left, it will be inside BackColorPanel and its acessor will be public
a TextBox called TextBox, its dock property wil be set to fill, it will be inside BackColorPanel, the BorderStyle Property set to None, you should set the size and font you most desize in this one, I'm going to use Segoe UI; 15,75pt and its acessor will be public
Now we have to make some properties in our UserControl to make it work without work in other controls
First in the SizeChanged event of the HighLightPanel we will make the BackColorPanel be exacly two points smaller in every direction and its position to 1;1 so we can see the HighLightPanel
private void HighlightPanel_SizeChanged(object sender, EventArgs e)
{
this.BackColorPanel.Size = new Size(
HighlightPanel.Width - 2,
HighlightPanel.Height - 2);
}
Now we will create two propertys to handle the Highlight Color
public Color HighlightBorderColor { get; set; }
public Color NonHighlightBorderColor { get; set; }
And in the Enter and Leave Property of our TextBox we are going to change the HighlightPanel
private void TextBox_Enter(object sender, EventArgs e)
{
HighlightPanel.BackColor = HighlightBorderColor;
}
private void TextBox_Leave(object sender, EventArgs e)
{
HighlightPanel.BackColor = NonHighlightBorderColor;
}
So now every time the user enter the Input it will appear that the Input has an Border in the specified Color
Now to enhance its usability to developers we will make some wrappers in its controls to be easier change property of child controls in the editor
public Image InputImage
{
get { return InputPicture.Image; }
set { InputPicture.Image = value; }
}
public PictureBoxSizeMode InputImageLayout
{
get { return InputPicture.SizeMode; }
set { InputPicture.SizeMode = value; }
}
public char PasswordCharacter
{
get { return TextBox.PasswordChar; }
set { TextBox.PasswordChar = value; }
}
public bool ShowInputImage
{
get { return InputPicture.Visible; }
set { InputPicture.Visible = value; }
}
In the InputImage set the picture you want for the User and the Key
Insert the two controls in the position you like
Position of the Form
if you want your form to be moveable without the border you will have to use this snippet, it is more easy in WPF
#region MoveForm
Point LastPoint;
bool ShouldMove;
private void form_MouseDown(object sender, MouseEventArgs e)
{
LastPoint = e.Location;
ShouldMove = true;
this.TransparencyKey = Color.FromArgb(111, 111, 111);
}
private void form_MouseUp(object sender, MouseEventArgs e)
{
ShouldMove = false;
}
private void form_MouseMove(object sender, MouseEventArgs e)
{
if (ShouldMove)
{
this.Location = new Point(
this.Location.X - LastPoint.X + e.X,
this.Location.Y - LastPoint.Y + e.Y);
}
}
#endregion
If you need a lot of special graphics effects learning WPF will indeed be a sound investement.
If all you want is that login screen, it is trivial in Winforms and doesn't take any horrible hacks as you've been told..
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = System.Drawing.Color.LavenderBlush;
this.TransparencyKey = System.Drawing.Color.LavenderBlush;
this.ControlBox = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Text= "";
These seven lines are all it takes for a form to be transparent. I copied them from the Designer code; you can simply set the 7 Properties in the property grid.
Now add a panel, dock it to the bottom and give it the right color; add a picturebox and your other controls and you are set.
To create the two input groups you also need just a few regular controls and only a few simple lines of code:
You place one Panel, BorderStyle = FixedSingle; and add a Label and a TextBox to it. The Label has AutoSize = False; and both ImageAlign and TextAlign are set to MiddleLeft. You assign an image to the Label's Image and prefix the Text with enough blanks to not overlap. Obviously you should define a PasswordChar for the 2nd TextBox. Now all you need is to script the Enter and Leave events to change the BackColor of the respective Panels between, say SystemColors.Control and SystemColors.MenuHighlight. Size the Labels to almost fill the Panels and you are done. Less code than the WPF version, I'd bet.
If you need such input an controls again and again, simply create Usercontrols for each type you need!
Here is an example of the limits you will hit: Wouldn't it be nice to add a dropshadow effect to the image? It is doable in Winforms. But it would involve painting that effect; this would take at least 15 or 20 lines of involved code instead of simply turning the effect on with (estimated) 1-3 simple lines.
Do you need any nice hover effects? Not easy, to say the least..
These limits will be all over the place, so it really depends on how fancy your requirements will get.
Maybe you should use this example as a starter to compare the two techniques and to warm you up to WPF?

display image on mouseover in windows form?

I am working on a project in c# using windows forms.
me and the group I am in want to make it so that when the user hovers their mouse over an image, in our case a card, that a larger image of that card appears next to the mouse arrow, much in the same way a tool tip would work.
I don't think you can use a tool tip to do this i have tried looking everywhere,
any advice or examples would be great thank you very much
You may want to look at this Code Project Article
It shows you how to create an OwnerDrawn ToolTip with an Image.
Thanks for the responses I got everything figured out.
What I wanted to do was that when I moused over a certain area a different image for that area would popup in the same way that a tool tip did. So after some research I figured out how to create my own tool tip class.
here's an example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CustomToolTip tip = new CustomToolTip();
tip.SetToolTip(button1, "text");
tip.SetToolTip(button2, "writing");
button1.Tag = Properties.Resources.pelican; // pull image from the resources file
button2.Tag = Properties.Resources.pelican2;
}
}
class CustomToolTip : ToolTip
{
public CustomToolTip()
{
this.OwnerDraw = true;
this.Popup += new PopupEventHandler(this.OnPopup);
this.Draw +=new DrawToolTipEventHandler(this.OnDraw);
}
private void OnPopup(object sender, PopupEventArgs e) // use this event to set the size of the tool tip
{
e.ToolTipSize = new Size(600, 1000);
}
private void OnDraw(object sender, DrawToolTipEventArgs e) // use this to customzie the tool tip
{
Graphics g = e.Graphics;
// to set the tag for each button or object
Control parent = e.AssociatedControl;
Image pelican = parent.Tag as Image;
//create your own custom brush to fill the background with the image
TextureBrush b = new TextureBrush(new Bitmap(pelican));// get the image from Tag
g.FillRectangle(b, e.Bounds);
b.Dispose();
}
}
}
A simple way to do is to hide/show a picture box at specified location. Another method is to load & draw (paint) an image using GDI API.

Categories