There's some really great code for a glass button here: http://www.lukesw.net/articles/GlassButton.aspx
The only trouble I have with this button is that if I apply a gradient to my forms it affects the color of the button so that it's not quite what I chose at design time. I don't know whether it's the code I'm using to apply the form gradient that's causing this or if the button is not totally opaque or what. I tried fooling around with the button code a bit but didn't get anywhere. You can get the code for the button at the link I posted above. Below is the code I'm using for my form gradient which is located in the form itself right now:
private Color _Color1 = Color.Gainsboro;
private Color _Color2 = Color.Blue;
private float _ColorAngle = 60f;
public Color Color1
{
get { return _Color1; }
set {
_Color1 = value;
this.Invalidate(); // Tell the Form to repaint itself
}
}
public Color Color2
{
get { return _Color2; }
set {
_Color2 = value;
this.Invalidate(); // Tell the Form to repaint itself
}
}
public float ColorAngle
{
get { return _ColorAngle; }
set {
_ColorAngle = value;
this.Invalidate(); // Tell the Form to repaint itself
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
Graphics g = pevent.Graphics;
Rectangle rBackground = new Rectangle(0, 0, this.Width, this.Height);
System.Drawing.Drawing2D.LinearGradientBrush bBackground
= new System.Drawing.Drawing2D.LinearGradientBrush(rBackground,
_Color1, _Color2, _ColorAngle);
g.FillRectangle(bBackground, rBackground);
bBackground.Dispose();
}
Any pointers on how I can get this button to display the same at runtime as it does at design time would be greatly appreciated!
In the DrawButtonBackground method in GlowButton.cs, just change the opacity to fully opaque (255):
#region " content "
using (GraphicsPath bb = CreateRoundRectangle(rect, 2))
{
//int opacity = pressed ? 0xcc : 0x7f;
int opacity = 255;
using (Brush br = new SolidBrush(Color.FromArgb(opacity, backColor)))
{
g.FillPath(br, bb);
}
}
#endregion
Related
I have WPF app with ContentControl where the content is WindowsFormsHost with a Child having custom panel, which renders SDL stream. Now I have added button to disable/enable audio of the stream. Everything works fine, but I cannot make the button icon transparent. How can I do that? Is it possible at all?
AudioButton = new System.Windows.Forms.Button()
{
Enabled = AudioButtonEnabled,
BackColor = Color.Transparent,
Image = Image.FromFile(#".\Images\audioDisabled.png"),
Width = 30,
Height = 30,
FlatStyle = System.Windows.Forms.FlatStyle.Flat
};
AudioButton.FlatAppearance.BorderSize = 0;
AudioButton.Click += (object sender, EventArgs e) =>
{
};
SDLRenderer.AddButton(AudioButton);
The image (icon) is transparent as well.
The workaround can be to create custom WinForms button, override OnPaint event and make the specified color transparent for bitmap by calling Bitmap.MakeTransparent()
public class CustomButton : Button
{
private Color TransparentColor;
public CustomButton() : base()
{
TransparentColor = Color.FromArgb(192, 192, 192);
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.Image != null)
{
Bitmap bmp = ((Bitmap)this.Image);
bmp.MakeTransparent(TransparentColor);
int x = (this.Width - bmp.Width) / 2;
int y = (this.Height - bmp.Height) / 2;
e.Graphics.DrawImage(bmp, x, y);
}
base.OnPaint(e);
}
}
I am having a problem witth visual studio. I created a menustrip with different menus and some contain separators. I want the theme of the program to be dark so I changed the color of all buttons to black background and white text.
however I cannot change the separators' colors. They are white background and black line. I tried from properties - not working. I tried with code - also not working. Can anyone help me?
Also I want to ask how to change the color of the outline of the buttons? it's currently white.
There's no need to create a new separator , just create a color table :
public class MyCustomColors: ProfessionalColorTable
{
public override Color SeparatorLight
{
get { return Color.FromArgb(100, 100, 100); }
}
public override Color SeparatorDark
{
get { return Color.FromArgb(100, 100, 100); }
}
}
}
then use it like :
menu_control.Renderer = new ToolStripProfessionalRenderer(new MyCustomColors());
The default toolstrip renderer ignores the BackColor property and uses hard-coded colors.
so write a custom class as below:
public class CustomToolStripSeparator : ToolStripSeparator
{
public CustomToolStripSeparator()
{
Paint += CustomToolStripSeparator_Paint;
}
private void CustomToolStripSeparator_Paint(object sender, PaintEventArgs e)
{
// Get the separator's width and height.
ToolStripSeparator toolStripSeparator = (ToolStripSeparator)sender;
int width = toolStripSeparator.Width;
int height = toolStripSeparator.Height;
//Color foreColor = Color.Blue;
Color backColor = Color.Yellow;
// Fill the background.
e.Graphics.FillRectangle(new SolidBrush(backColor), 0, 0, width, height);
// Draw the line.
//e.Graphics.DrawLine(new Pen(foreColor), 4, height / 2, width - 4, height / 2);
}
}
and inside your form_load method apply your custom toolstripseparator:
private void Form1_Load(object sender, EventArgs e)
{
ToolStripSeparator toolStripSeparator1 = new CustomToolStripSeparator();
ToolStripSeparator toolStripSeparator2 = new CustomToolStripSeparator();
ToolStripSeparator toolStripSeparator3 = new CustomToolStripSeparator();
this.fileToolStripMenuItem.DropDownItems.Add("Save Project");
this.fileToolStripMenuItem.DropDownItems.Add(toolStripSeparator1);
this.fileToolStripMenuItem.DropDownItems.Add("Reload Project");
this.fileToolStripMenuItem.DropDownItems.Add(toolStripSeparator2);
this.fileToolStripMenuItem.DropDownItems.Add("Close Project");
this.fileToolStripMenuItem.DropDownItems.Add(toolStripSeparator3);
this.fileToolStripMenuItem.DropDownItems.Add("New Window");
}
I'm trying to create a custom RichTextBox with border color, but i have a problem...
My border color not showing
Here's my code :
public partial class AlXRichTextBox : RichTextBox
{
private RichTextBox textBox;
private Color borderColor;
public AlXRichTextBox()
{
InitializeComponent();
}
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen p = new Pen(borderColor);
Graphics g = e.Graphics;
int variance = 3;
//g.DrawRectangle(p, new Rectangle(base.Location.X - variance, base.Location.Y - variance, base.Width + variance, base.Height + variance));
ControlPaint.DrawBorder(e.Graphics, base.ClientRectangle, borderColor, ButtonBorderStyle.Solid);
}
private void InitializeComponent()
{
this.textBox = new System.Windows.Forms.RichTextBox();
this.SuspendLayout();
//
// richTextBox1
//
this.textBox.Location = new System.Drawing.Point(0, 0);
this.textBox.Name = "richTextBox1";
this.textBox.Size = new System.Drawing.Size(100, 96);
this.textBox.TabIndex = 0;
this.textBox.Text = "";
this.textBox.Multiline = true;
this.textBox.BorderStyle = BorderStyle.None;
//
// AlXRichTextBox
//
this.Size = new System.Drawing.Size(278, 123);
this.ResumeLayout(false);
}
}
What's problem with this ?
Referring to MSDN article :
Overriding OnPaint will not allow you to modify the appearance of all controls. Those controls that have all of their painting done by Windows (for example, TextBox) never call their OnPaint method, and thus will never use the custom code. Refer to the Help documentation for the particular control you want to modify to see if the OnPaint method is available. For a list of all the Windows Form Controls, see Controls to Use on Windows Forms. If a control does not have OnPaint listed as a member method, you cannot alter its appearance by overriding this method. For more information about custom painting, see Custom Control Painting and Rendering.
However there is a "hack", You can achieve calling the Paint method by calling following code:
private const int WM_PAINT = 15;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT && !inhibitPaint)
{
// raise the paint event
using (Graphics graphic = base.CreateGraphics())
OnPaint(new PaintEventArgs(graphic,
base.ClientRectangle));
}
}
private bool inhibitPaint = false;
public bool InhibitPaint
{
set { inhibitPaint = value; }
}
Src: RichTextBox and UserPaint
Other point is that You cannot draw outside of the Rectangle (which is total size of Your RichTB component. So You actually want to provide him with different Coords (smaller inner ones) and You will draw to the outside.
Your class will look like:
public partial class AlXRichTextBox : RichTextBox
{
private Color borderColor = Color.Red;
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
int variance = 3;
e = new PaintEventArgs(e.Graphics, new Rectangle(e.ClipRectangle.X + variance, e.ClipRectangle.Y + variance, e.ClipRectangle.Width - variance, e.ClipRectangle.Height - variance));
base.OnPaint(e);
Pen p = new Pen(borderColor, variance);
Graphics g = e.Graphics;
g.DrawRectangle(p, new Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height));
}
private const int WM_PAINT = 15;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT && !inhibitPaint)
{
// raise the paint event
using (Graphics graphic = base.CreateGraphics())
OnPaint(new PaintEventArgs(graphic,
base.ClientRectangle));
}
}
private bool inhibitPaint = false;
public bool InhibitPaint
{
set { inhibitPaint = value; }
}
}
IMPORTANT
As it is not expected for this control to be changed by Paint, You will get "not nice" behavior in regards to the drawing changes like border, new elements etc.. If You would like to use such element, consider using WPF - Windows Presentation Foundation. They are much more nicer to templating the items and modifying design.
A little late answer, but I was on same path as you these days and It got me to this solution, It works for me:
using System;
using System.Drawing;
using System.Windows.Forms;
public class MyRichTextBox : RichTextBox
{
private const UInt32 WM_PAINT = 0x000F;
private const UInt32 WM_USER = 0x0400;
private const UInt32 EM_SETBKGNDCOLOR = (WM_USER + 67);
private const UInt32 WM_KILLFOCUS = 0x0008;
public MyRichTextBox()
{
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
Graphics g = Graphics.FromHwnd(Handle);
Rectangle bounds = new Rectangle(0, 0, Width - 1, Height - 1);
Pen p = new Pen(SystemColors.Highlight, 3);
if (m.Msg == WM_PAINT)
{
if (this.Enabled == true)
{
if (this.Focused)
{
g.DrawRectangle(p, bounds);
}
else
{
g.DrawRectangle(SystemPens.ControlDark, bounds);
}
}
else
{
g.FillRectangle(Brushes.White, bounds);
g.DrawRectangle(SystemPens.Control, bounds);
}
}
if (m.Msg == EM_SETBKGNDCOLOR) //color disabled background
{
Invalidate();
}
if (m.Msg == WM_KILLFOCUS) //set border back to normal on lost focus
{
Invalidate();
}
}
}
This Rich Textbox changes 3 border colors - enabled, focused and disabled with disabled background. As you see the code is simple and short. The only trick is to overide KILL_FOCUS and EM_SETBKGNDCOLOR messages (this one is for changing disabled background), and RichTextbox should be BorderStyle=None. Cheers !
I've got a custom control with two PictureBox controls that are animated and a label control over them.
The child indexes are set so that label is always on top but the picture boxes are interchanging so when animated they display different images each time.
As I understand, label needs to have a parent control on top of which it can support a semi transparent color (Argb). Since the label has active picture box as its parent it will also be animated with which is not what I want at all.
Is there a way to fix a child position relative to parents parent?
To have a transparent label control, you can override the OnPaint method and draw all controls that intersects with label, at last draw the background and text of the label.
Also when moving your picture boxes, don't forget to call the Invalidate() method of the transparent label.
Screenshot
Sample Implementation
public class TransparentLabel : Label
{
public TransparentLabel()
{
this.transparentBackColor = Color.Blue;
this.opacity = 50;
this.BackColor = Color.Transparent;
}
protected override void OnPaint(PaintEventArgs e)
{
if (Parent != null)
{
using (var bmp = new Bitmap(Parent.Width, Parent.Height))
{
Parent.Controls.Cast<Control>()
.Where(c => Parent.Controls.GetChildIndex(c) > Parent.Controls.GetChildIndex(this))
.Where(c => c.Bounds.IntersectsWith(this.Bounds))
.OrderByDescending(c => Parent.Controls.GetChildIndex(c))
.ToList()
.ForEach(c => c.DrawToBitmap(bmp, c.Bounds));
e.Graphics.DrawImage(bmp, -Left, -Top);
using (var b = new SolidBrush(Color.FromArgb(this.Opacity, this.TransparentBackColor)))
{
e.Graphics.FillRectangle(b, this.ClientRectangle);
}
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
TextRenderer.DrawText(e.Graphics, this.Text, this.Font, this.ClientRectangle, this.ForeColor, Color.Transparent);
}
}
}
private int opacity;
public int Opacity
{
get { return opacity; }
set
{
if (value >= 0 && value <= 255)
opacity = value;
this.Invalidate();
}
}
public Color transparentBackColor;
public Color TransparentBackColor
{
get { return transparentBackColor; }
set
{
transparentBackColor = value;
this.Invalidate();
}
}
[Browsable(false)]
public override Color BackColor
{
get
{
return Color.Transparent;
}
set
{
base.BackColor = Color.Transparent;
}
}
}
I'm trying to place an image that has no definitive shape (a hat for example) on top of a different image control.
The thing is, since the control has a definitive shape, it leaves the default background color to cover up the space left blank. The image control is the exact same size of the image.
I tried using control.BackColor = Color.Transparent; but it doesn't seem to work.
Any other suggestions?
You can use Control.Region for this purpose
GraphicsPath path = new GraphicsPath();
path.AddEllipse(control.ClientRectangle);
control.Region = new Region(path);
try this, you can create any shape using GraphicsPath and set it to Region for instance I created ellipse.
Edit
If you just want to set BackColor = Color.Transparent. for some reason some controls doesn't allow this. in such cases you can do the following
public class CustomControl1 : Control
{
public CustomControl1()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
}
Create a descendant of your control and set this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); that should do the trick
If your Image Control (like a PictureBox) is not moved (by holding mouse down and dragging) by user at runtime, you can use this technique which allows you to display images on top of each other. The images should have transparent background:
public class ImageControl : Control {
public ImageControl(){
SetStyle(ControlStyles.Opaque, true);
}
public Image Image {get;set;}
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
protected override void OnPaint(PaintEventArgs e){
if(Image != null) e.Graphics.DrawImage(Image, Point.Empty);
}
}
You can use the control above instead of a PictureBox. Moving this control by dragging at runtime causes flicker much. So if you want so I think there is only 1 solution which uses Region. In this approach, you have to turn your Bitmap to a Region and assign this Region for your Control.Region property. The link given by Chris Dunaway is very helpful for you to do this. However I have to say that the Region has not a smooth border as you may expect. That's a shortage of this approach. For your convenience, I'll post the code with a little modification here, this code uses LockBits which will outperform the original code:
public class Util {
//invert will toggle backColor to foreColor (in fact, I mean foreColor here is the Solid Color which makes your image distinct from the background).
public static Region RegionFromBitmap(Bitmap bm, Color backColor, bool invert)
{
Region rgn = new Region();
rgn.MakeEmpty();//This is very important
int argbBack = backColor.ToArgb();
BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
int[] bits = new int[bm.Width * bm.Height];
Marshal.Copy(data.Scan0, bits, 0, bits.Length);
//
Rectangle line = Rectangle.Empty;
line.Height = 1;
bool inImage = false;
for (int i = 0; i < bm.Height; i++)
{
for (int j = 0; j < bm.Width; j++)
{
int c = bits[j + i * bm.Width];
if (!inImage)
{
if (invert ? c == argbBack : c != argbBack)
{
inImage = true;
line.X = j;
line.Y = i;
}
}
else if(invert ? c != argbBack : c == argbBack)
{
inImage = false;
line.Width = j - line.X;
rgn.Union(line);
}
}
}
bm.UnlockBits(data);
return rgn;
}
}
//Use the code
//if your Bitmap is a PNG with transparent background, you can get the Region from it like this:
Region rgn = Util.RegionFromBitmap(yourPng, Color.FromArgb(0), false);
//if your Bitmap has a figure with solid color of Black, you can get the Region like this:
Region rgn = Util.RegionFromBitmap(yourPng, Color.Black, true);