I have a custom control, a Hover button, that simply shows borders whenever a mouse moves over it or got focus.
Everything is fine but I am having problem handling a situation where I click the button and it shows another form (ShowDialog) or in case of (MessageBox), and then return back to the parent form of the control.
This is the control code:
namespace CustomControlTutorial
{
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public partial class HoverButton : Button
{
byte eventPaintMode = 0;
//Color borderClr = Color.Transparent;
public HoverButton()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
//base.OnPaint(pe);
// render background
Color clr = this.Parent.BackColor;
Brush b = new SolidBrush(clr);
pe.Graphics.FillRectangle(b, ClientRectangle);
// Draw borders depending on event case
Point p00 = new Point(0, 0);
Point p01 = new Point(0, ClientSize.Height - 1);
Point p10 = new Point(ClientSize.Width - 1, 0);
Point p11 = new Point(ClientSize.Width - 1, ClientSize.Height - 1);
Pen pen1;
Pen pen2;
switch (eventPaintMode)
{
case 1:
{
// draw borders (using pen)
pen1 = new Pen(new SolidBrush(Color.DimGray), 1);
pen2 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
break;
}
case 2:
{
pen2 = new Pen(new SolidBrush(Color.DimGray), 1);
pen1 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
break;
}
case 3:
{
// draw borders (using pen)
pen1 = new Pen(new SolidBrush(Color.DimGray), 1);
pen2 = new Pen(new SolidBrush(Color.White), 1);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen2, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen2, p00, p01);
// draw focus lines
pen1 = new Pen(new SolidBrush(Color.Black), 1);
pen1.DashCap = DashCap.Round;
pen1.DashPattern = new float[] { 1, 1, 1, 1 };
p00 = new Point(5, 5);
p01 = new Point(5, ClientSize.Height - 6);
p10 = new Point(ClientSize.Width - 6, 5);
p11 = new Point(ClientSize.Width - 6, ClientSize.Height - 6);
pe.Graphics.DrawLine(pen1, p10, p11);
pe.Graphics.DrawLine(pen1, p00, p10);
pe.Graphics.DrawLine(pen1, p01, p11);
pe.Graphics.DrawLine(pen1, p00, p01);
pe.Graphics.SmoothingMode = SmoothingMode.None;
break;
}
default:
break;
}
// render text
String drawString = this.Text;
SizeF size = pe.Graphics.MeasureString(drawString, this.Font);
float pointX = ((float)ClientSize.Width - size.Width) / 2;
float pointY = ((float)ClientSize.Height - size.Height) / 2;
pe.Graphics.DrawString(Text, Font, new SolidBrush(ForeColor), (int)pointX, (int)pointY);
b.Dispose();
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
eventPaintMode = 1;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
eventPaintMode = 0;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
eventPaintMode = 2;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
if (e.Button == MouseButtons.Left)
{
eventPaintMode = 1;
Invalidate();
}
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
eventPaintMode = 3;
Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus(e);
eventPaintMode = 0;
Invalidate();
}
}
}
And this is where I show a test message box:
private void hoverButton1_Click(object sender, EventArgs e)
{
MessageBox.Show("Test");
}
I can't find an event like, OnParentLostFocus or something like that.
The problem is that when I set the button to show a message, the button's parent (Form) can't be accessed until the message is closed. So there is no connection between the 2 forms that I can use to make any changes to the button..
This is how it works. The parent From and its children won't receive the windows paint messages to redraw themselves as long as the modal dialog is shown.
Your code creates:
As you can see, the button draws two different effects on tab stops. A hover and focus effects. While it draws the hover effect and ignores the focus one on the MouseEnter even if the control is currently has the focus. Another thing is, the button doesn't show or draw the normal/default state when the modal dialog is closed.
IMHO, the two things shouldn't combine, interact with the mouse events to draw the hover and down effects, and draw the focus rectangle whenever the control gains the focus and the mouse effects are not applied. Just like how the default System.Windows.Forms.Button works.
For example:
// Your namespace...
public enum MouseState : int
{
None, Over, Down
}
[DesignerCategory("Code")]
public class HoverButton : Button
{
private MouseState state = MouseState.None;
public HoverButton() : base()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.ResizeRedraw, true);
UpdateStyles();
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = ClientRectangle;
g.Clear(Parent.BackColor);
var p00 = new Point(0, 0);
var p01 = new Point(0, r.Height - 1);
var p10 = new Point(r.Width - 1, 0);
var p11 = new Point(r.Width - 1, r.Height - 1);
switch (state)
{
case MouseState.Over:
if (r.Contains(PointToClient(MousePosition)))
{
g.DrawLine(Pens.DimGray, p10, p11);
g.DrawLine(Pens.White, p00, p10);
g.DrawLine(Pens.DimGray, p01, p11);
g.DrawLine(Pens.White, p00, p01);
}
break;
case MouseState.Down:
g.DrawLine(Pens.White, p10, p11);
g.DrawLine(Pens.DimGray, p00, p10);
g.DrawLine(Pens.White, p01, p11);
g.DrawLine(Pens.DimGray, p00, p01);
break;
default:
break;
}
TextRenderer.DrawText(g, Text, Font, r, ForeColor,
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
if (Focused && MouseButtons == MouseButtons.None &&
!r.Contains(PointToClient(MousePosition)))
{
r.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(g, r);
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
state = MouseState.Over;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
state = MouseState.None;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
state = MouseState.Down;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
state = MouseState.Over;
Invalidate();
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
state = MouseState.None;
Invalidate();
}
protected override void OnLeave(EventArgs e)
{
base.OnLeave(e);
state = MouseState.None;
Invalidate();
}
}
Which creates:
Side Notes
Call the e.Graphics.Clear(..) method to clear the drawing canvas with the desired color.
Use the predefined Brushes and Pens whenever it's possible instead of creating new graphics objects.
The TextRenderer is better choice to draw strings over controls, while the e.Graphics.DrawString(..) is better one to draw over images.
To center the text in the control, draw it in a rectangle and use an overload where you can pass the TextFormatFlags (or the StringFormat with the Graphics.DrawString(..) method) to dictate that along with the other text layout information.
Don't forget to dispose the graphics objects (pen1 and pen2 in your code).
Related
I am working on a project wherein I need to add a Control with the shape of a Circle with some text in the middle.
My problem is the circle is too small, when I resize it, it overlaps other controls. I want to draw the circle same width as the square.
Otherwise. how can I make the Control's background transparent?
I am using the code below:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.Clear(this.BackColor);
using (SolidBrush brush = new SolidBrush(this._FillColor))
{
graphics.FillEllipse(brush, 0x18 - 6, 0x18 - 6, (this.Width - 0x30) + 12, (this.Height - 0x30) + 12);
}
Brush FontColor = new SolidBrush(this.ForeColor);
SizeF MS = graphics.MeasureString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font);
graphics.DrawString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font, FontColor, Convert.ToInt32((Width / 2 - MS.Width / 2) + 2), Convert.ToInt32((Height / 2 - MS.Height / 2) + 3));
bitmap.MakeTransparent(this.BackColor);
e.Graphics.DrawImage(bitmap, 0, 0);
graphics.Dispose();
bitmap.Dispose();
}
}
}
This is a Custom Control derived from Control, which can be made translucent.
The interface is a colored circle which can contain a couple of numbers.
The Control exposes these custom properties:
Opacity: The level of opacity of the control BackGround [0, 255]
InnerPadding: The distance between the inner rectangle, which defines the circle bounds and the control bounds.
FontPadding: The distance between the Text and the Inner rectangle.
Transparency is obtained overriding CreateParams, then setting ExStyle |= WS_EX_TRANSPARENT;
The Control.SetStyle() method is used to modify the control behavior, adding these ControlStyles:
▶ ControlStyles.Opaque: prevents the painting of a Control's BackGround, so it's not managed by the System. Combined with CreateParams to set the Control's Extended Style to WS_EX_TRANSPARENT, the Control becomes completely transparent.
▶ ControlStyles.SupportsTransparentBackColor the control accepts Alpha values for it's BackGround color. Without also setting ControlStyles.UserPaint it won't be used to simulate transparency. We're doing that ourselves with other means.
To see it at work, create a new Class file, substitute all the code inside with this code preserving the NameSpace and build the Project/Solution.
The new Custom Control will appear in the ToolBox. Drop it on a Form. Modify its custom properties as needed.
A visual representation of the control:
Note and disclaimer:
This is a prototype Control, the custom Designer is missing (cannot post that here, too much code, also connected to a framework).
As presented here, it can be used to completely overlap other Controls in a Form or other containers. Partial overlapping is not handled in this simplified implementation.
The Font is hard-coded to Segoe UI, since this Font has a base-line that simplifies the position of the text in the middle of the circular area.
Other Fonts have a different base-line, which requires more complex handling.
See: TextBox with dotted lines for typing for the base math.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
[DesignerCategory("Code")]
public class RoundCenterLabel : Label, INotifyPropertyChanged, ISupportInitialize
{
private const int WS_EX_TRANSPARENT = 0x00000020;
private bool IsInitializing = false;
private Point MouseDownLocation = Point.Empty;
private readonly int fontPadding = 4;
private Font m_CustomFont = null;
private Color m_BackGroundColor;
private int m_InnerPadding = 0;
private int m_FontPadding = 25;
private int m_Opacity = 128;
public event PropertyChangedEventHandler PropertyChanged;
public RoundCenterLabel() => InitializeComponent();
private void InitializeComponent()
{
SetStyle(ControlStyles.Opaque |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
m_CustomFont = new Font("Segoe UI", 50, FontStyle.Regular, GraphicsUnit.Pixel);
BackColor = Color.LimeGreen;
ForeColor = Color.White;
}
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
public new Font Font
{
get => m_CustomFont;
set {
m_CustomFont = value;
if (IsInitializing) return;
FontAdapter(value, DeviceDpi);
NotifyPropertyChanged();
}
}
public override string Text {
get => base.Text;
set { base.Text = value;
NotifyPropertyChanged();
}
}
public int InnerPadding {
get => m_InnerPadding;
set {
if (IsInitializing) return;
m_InnerPadding = ValidateRange(value, 0, ClientRectangle.Height - 10);
NotifyPropertyChanged(); }
}
public int FontPadding {
get => m_FontPadding;
set {
if (IsInitializing) return;
m_FontPadding = ValidateRange(value, 0, ClientRectangle.Height - 10);
NotifyPropertyChanged();
}
}
public int Opacity {
get => m_Opacity;
set { m_Opacity = ValidateRange(value, 0, 255);
UpdateBackColor(m_BackGroundColor);
NotifyPropertyChanged();
}
}
public override Color BackColor {
get => m_BackGroundColor;
set { UpdateBackColor(value);
NotifyPropertyChanged();
}
}
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
base.AutoSize = false;
}
private void NotifyPropertyChanged([CallerMemberName] string PropertyName = null)
{
InvalidateParent();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
MouseDownLocation = e.Location;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left) {
var loc = new Point(Left + (e.X - MouseDownLocation.X), Top + (e.Y - MouseDownLocation.Y));
InvalidateParent();
BeginInvoke(new Action(() => Location = loc));
}
}
private void InvalidateParent()
{
Parent?.Invalidate(Bounds, true);
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
using (var format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoWrap, CultureInfo.CurrentUICulture.LCID))
{
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
using (var circleBrush = new SolidBrush(m_BackGroundColor))
using (var foreBrush = new SolidBrush(ForeColor))
{
FontAdapter(m_CustomFont, e.Graphics.DpiY);
RectangleF rect = InnerRectangle();
e.Graphics.FillEllipse(circleBrush, rect);
e.Graphics.DrawString(Text, m_CustomFont, foreBrush, rect, format);
};
};
}
public void BeginInit() => IsInitializing = true;
public void EndInit()
{
IsInitializing = false;
Font = new Font("Segoe UI", 50, FontStyle.Regular, GraphicsUnit.Pixel);
FontPadding = m_FontPadding;
InnerPadding = m_InnerPadding;
}
private RectangleF InnerRectangle()
{
(float Min, _) = GetMinMax(ClientRectangle.Height, ClientRectangle.Width);
var size = new SizeF(Min - (m_InnerPadding / 2), Min - (m_InnerPadding / 2));
var position = new PointF((ClientRectangle.Width - size.Width) / 2,
(ClientRectangle.Height - size.Height) / 2);
return new RectangleF(position, size);
}
private void FontAdapter(Font font, float dpi)
{
RectangleF rect = InnerRectangle();
float fontSize = ValidateRange(
(int)(rect.Height - m_FontPadding), 6,
(int)(rect.Height - m_FontPadding)) / (dpi / 72.0F) - fontPadding;
m_CustomFont.Dispose();
m_CustomFont = new Font(font.FontFamily, fontSize, font.Style, GraphicsUnit.Pixel);
}
private void UpdateBackColor(Color color)
{
m_BackGroundColor = Color.FromArgb(m_Opacity, Color.FromArgb(color.R, color.G, color.B));
base.BackColor = m_BackGroundColor;
}
private int ValidateRange(int Value, int Min, int Max)
=> Math.Max(Math.Min(Value, Max), Min); // (Value < Min) ? Min : ((Value > Max) ? Max : Value);
private (float, float) GetMinMax(float Value1, float Value2)
=> (Math.Min(Value1, Value2), Math.Max(Value1, Value2));
}
I create a code give that allow me to resize a circle and move it
first mouse click give me the center for the circle.
the circle radius will change with the cursor movement (closer to the center smaller radius farther from the center bigger radius).
click second time the radius will not be changed and the circle will be finalized.
This is an image similar to what I want to do:
http://lh6.ggpht.com/_wQH6U92SY04/S_6lAJI7E-I/AAAAAAAAKwE/i-Jkq-nI5Ss/GoogleMapCircle%5B11%5D.gif?imgmax=800
The problems are :
the center is not exactly where I click the mouse first time.
the cursor should be exactly at the circle border when I move it.
the biggest problem is after clicking second time the circle is move farther from the center .
PLEASE HELP
using System;
using System.Drawing;
using System.Windows.Forms;
namespace project
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
int clikno = 0;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(this.Width, this.Height);
rectangleObj = new Rectangle(10, 10, 100, 100);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
rectangleObj.X = e.X;
rectangleObj.Y = e.Y;
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
return background;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
int radius = Convert.ToInt32(oradius);
if (clikno == 1)
{
rectangleObj.Height = radius;
rectangleObj.Width = radius;
rectangleObj.X = clickPrev.X;
rectangleObj.Y = clickPrev.Y;
Refresh();
}
if (clikno == 2)
clikno = 0;
Refresh();
}
}
}
I figured it out
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace Project
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
Rectangle center;
int clikno = 0;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(this.Width, this.Height);//, this.Width,this.Height);
rectangleObj = new Rectangle(10, 10, 100, 100);
center = new Rectangle(10, 10, 3, 3);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
if (clickPrev == Point.Empty) return;
Refresh();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
// scG.DrawRectangle(myPen, rectangleObj);
scG.DrawEllipse(myPen, center);
return background;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
int radius = Convert.ToInt32(oradius);
if (clikno == 1)
{
rectangleObj.Height = radius;
rectangleObj.Width = radius;
rectangleObj.X = clickPrev.X- rectangleObj.Height /2;// +radius;
rectangleObj.Y = clickPrev.Y - rectangleObj.Width / 2;// +radius;
center.X = clickPrev.X - center.Height / 2;// +radius;
center.Y = clickPrev.Y - center.Width / 2;// +radius;
Refresh();
}
if (clikno == 2)
clikno = 0;
Refresh();
}
string myString = 5.ToString();
}
}
I have a RichTextBox in my project which is for Jabber chatroom where i get all chat of users and maself.
I want to embed smileys in my project.i want a panel containing all smileys.and when click any smiley it must be sent.
like :) displays smile face
:# is angry face
They must be shown in richtextbox also in form of smiley not symbols like :)
How can i do this in c#.
I had found this code on stack overflow.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SuspendLayout();
List<Bitmap> Smiles = new List<Bitmap>(); //Add images
ToolStripSplitButton _toolStripSplitButton = new ToolStripSplitButton();
_toolStripSplitButton.Size = new Size(23, 23);
//_toolStripSplitButton.Image = myImage; //Add the image of the stripSplitButton
ToolStrip _toolStrip = new ToolStrip();
_toolStrip.Size = new Size(ClientSize.Width, 10);
_toolStrip.Location = new Point(0, this.ClientSize.Height - _toolStrip.Height);
_toolStrip.BackColor = Color.LightGray;
_toolStrip.Dock = DockStyle.Bottom;
_toolStrip.Items.AddRange(new ToolStripItem[] { _toolStripSplitButton });
SmileBox smilebox = new SmileBox(new Point(_toolStripSplitButton.Bounds.Location.X, _toolStrip.Location.Y - 18), 6);
smilebox.Visible = false;
Controls.Add(smilebox);
foreach (Bitmap bmp in Smiles)
smilebox.AddItem(bmp);
_toolStripSplitButton.Click += new EventHandler(delegate(object sender, EventArgs e)
{
smilebox.Visible = true;
});
Click += new EventHandler(delegate(object sender, EventArgs e)
{
smilebox.Visible = false;
});
this.Controls.Add(_toolStrip);
this.ResumeLayout();
}
void Form1_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
class SmileBox : Panel
{
public List<Item> Items
{
get;
set;
}
Size _ItemSpace = new Size(20, 20);
Point _ItemLocation;
int _rowelements = 0;
public SmileBox(Point Location, int RowElements)
{
BackColor = Color.LightGray;
Height = _ItemSpace.Height;
Width = _ItemSpace.Width * RowElements;
this.Location = new Point(Location.X, Location.Y - Height);
_ItemLocation = new Point(0, 0);
_rowelements = RowElements;
}
int count = 1;
public void AddItem(Bitmap Image)
{
Item item = new Item(_ItemSpace, _ItemLocation, Image);
if (_ItemLocation.X + _ItemSpace.Width >= Width)
_ItemLocation = new Point(0, _ItemLocation.Y);
else
_ItemLocation = new Point(_ItemLocation.X + _ItemSpace.Width, _ItemLocation.Y);
if (count == _rowelements)
{
_ItemLocation = new Point(_ItemLocation.X, _ItemLocation.Y + _ItemSpace.Height);
Height += _ItemSpace.Height;
Location = new Point(Location.X, Location.Y - _ItemSpace.Height);
count = 0;
}
count++;
Controls.Add(item);
}
}
class Item : PictureBox
{
int _BorderSpace = 2;
public Item(Size Size, Point Location, Bitmap Image)
{
this.Size = new Size(Size.Width - 2 * _BorderSpace, Size.Height - 2 * _BorderSpace);
this.Location = new Point(Location.X + _BorderSpace, Location.Y + _BorderSpace);
this.Image = new Bitmap(Image, this.ClientSize);
Click += new EventHandler(delegate(object sender, EventArgs e)
{
//Here what do you want to do when the user click on the smile
});
MouseEnter += new EventHandler(delegate(object sender, EventArgs e)
{
Focus();
Invalidate();
});
}
protected override void OnMouseDown(MouseEventArgs e)
{
this.Focus();
base.OnMouseDown(e);
}
protected override void OnEnter(EventArgs e)
{
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e)
{
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (this.Focused)
{
ClientRectangle.Inflate(-1, -1);
Rectangle rect = ClientRectangle;
ControlPaint.DrawFocusRectangle(pe.Graphics, rect);
}
}
}
The above code is not working for me as its too messy to understand.
Thanks in advance.
Try this code - this guy has written exactly the same:
http://www.codeproject.com/Articles/4544/Insert-Plain-Text-and-Images-into-RichTextBox-at-R
A menu tool strip is used in WinForm application. On checking menu option, it opens sub menus. When mouse enters in the boundary of sub menu the back color is change to green. Now, I want to change this color to red, when mouse leave the boundary of sub-menu.
Any suggestions ?
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
SolidBrush brush;
Rectangle r = new Rectangle(this.Bounds.Width - 20, 2, 16, 17);
// If click on Del(Close Icon)
if (bOnDel)
{
brush = new SolidBrush(Color.LightBlue);
e.Graphics.FillRectangle(brush, r);
brush.Color = Color.Blue;
e.Graphics.DrawRectangle(new Pen(brush, 1), r);
}
// If didn't click on Del(Close Icone)
if (!bOnDel)
{
brush = new SolidBrush(Color.FromKnownColor(KnownColor.Transparent));
e.Graphics.FillRectangle(brush, r);
brush.Color = Color.FromKnownColor(KnownColor.Transparent);
e.Graphics.DrawRectangle(new Pen(brush, 1), r);
}
//Code for Drawing Cross Lines
brush = new SolidBrush(Color.Gray);
Rectangle rCross = new Rectangle(this.Bounds.Width - 15, 8, 6, 6);
e.Graphics.DrawLine(new Pen(brush, 2), new Point(rCross.Right, rCross.Top), new Point(rCross.Left, rCross.Bottom));
e.Graphics.DrawLine(new Pen(brush, 2), new Point(rCross.Left, rCross.Top), new Point(rCross.Right, rCross.Bottom));
}
Use the MouseLeave event for the ToolStripMenuItem to change the BackColor Property:
private void yourToolStripMenuItem_MouseLeave(object sender, EventArgs e)
{
((ToolStripMenuItem)sender).BackColor = Color.Red;
}
You can look into using the MouseMove Event, make sure that your rectangle is declared outside of the Paint Event and Invalidate the Control using the Rectangle as the region. Here is an example base on your code, I declared a boolean entered and rectangle r in the beginning of the Class. You would put any highlight changes in your paint event. This is more like what I think you want.
public partial class CustomControl1 : ToolStripMenuItem
{
Rectangle r;
bool entered;
public CustomControl1()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
SolidBrush brush;
r = new Rectangle(this.Bounds.Width - 20, 2, 16, 17);
// If MouseEnter Del(Close Icon)
if (entered)
{
brush = new SolidBrush(Color.LightBlue);
e.Graphics.FillRectangle(brush, r);
brush.Color = Color.Blue;
e.Graphics.DrawRectangle(new Pen(brush, 1), r);
}
// If Mouse Not Entered Del(Close Icone)
if (!entered)
{
brush = new SolidBrush(Color.FromKnownColor(KnownColor.Transparent));
e.Graphics.FillRectangle(brush, r);
brush.Color = Color.FromKnownColor(KnownColor.Transparent);
e.Graphics.DrawRectangle(new Pen(brush, 1), r);
}
//Code for Drawing Cross Lines
brush = new SolidBrush(Color.Gray);
Rectangle rCross = new Rectangle(this.Bounds.Width - 15, 8, 6, 6);
e.Graphics.DrawLine(new Pen(brush, 2), new Point(rCross.Right, rCross.Top), new Point(rCross.Left, rCross.Bottom));
e.Graphics.DrawLine(new Pen(brush, 2), new Point(rCross.Left, rCross.Top), new Point(rCross.Right, rCross.Bottom));
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (r.Contains(e.X, e.Y) && !entered)
{
entered = true;
Invalidate(r);
}
else if (!r.Contains(e.X, e.Y) && entered)
{
entered = false;
Invalidate(r);
}
}
}
I would like to create a control the floats (potentially) outside the bounds of it's containing form. Is this possible? How may I do it?
This would function much like Context Menu's only I need to be able to add other controls to it such as buttons and images.
You want a Form with it's FormBorderStyle set to None, if you want it to behave like a context menu then you'll need to tie showing it to the appropriate event handler in your main form. Simple example below of setting the location and calling show from a mouse click event handler.
MyForm form = new MyForm();
form.Location = PointToScreen(new Point(e.X, e.Y));
form.Show();
It is possible, the TopLevel property controls this. However, the designer doesn't support them well, hard to keep control over controls that are also top-level windows at design time.
Beyond components like ToolTip and ContextMenuStrip, there is exactly one class that is top-level by design, the Form class. Set its FormBorderStyle to None and ControlBox to False to create a basic top-level window that you can use and populate with other controls.
Take a look at the DockPanel Suite source and adopt the technique.
here is u can made for all Control floating Style
private void Panel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Panel.Left += e.X - PanelMouseDownLocation.X;
Panel.Top += e.Y - PanelMouseDownLocation.Y;
}
}
private void Panel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) PanelMouseDownLocation = e.Location;
}
public Point PanelMouseDownLocation { get; set; }
It would need to be a separate window (much like a context menu actually is) -- you could wrap it as a control, that displays a modeless form (which would even give you the option for non rectangular windows if you really wanted to). As you could create the window from a non-visible control from the parent form, you can maintain a reference to the child for handling inter-form communication.
Have your UserControl override CreateParams. For example:
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
public static extern IntPtr GetDesktopWindow();
protected override CreateParams CreateParams
{
get
{
var cp = base.CreateParams;
cp.ExStyle &= 0x00080000; // WS_EX_LAYERED
cp.Style = 0x40000000 | 0x4000000; // WS_CHILD | WS_CLIPSIBLINGS
cp.Parent = GetDesktopWindow();
return cp;
}
}
This may have unintended effects (including not working well with Designer). I am choosing to follow one of the above patterns, but I thought it was worth mentioning here. Lookup CreateParams to see its purpose. (This option was gleaned from this page.)
This worked for me
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using LollipopUIControls.UIManagers;
namespace Gamasis.Apps.Controls
{
public class FloatingButton : Button
{
public FloatingButton()
{
SetStyle((ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint), true);
DoubleBuffered = true;
Size = new Size(50, 50);
BackColor = Color.Transparent;
SF.Alignment = StringAlignment.Center;
SF.LineAlignment = StringAlignment.Center;
AnimationTimer.Tick += new EventHandler(AnimationTick);
}
#region Variables
Timer AnimationTimer = new Timer { Interval = 1 };
FontManager font = new FontManager();
StringFormat SF = new StringFormat();
Rectangle StringRectangle;
bool Focus = false;
int margintop = 0, marginleft = 0, marginright = 0, marginBottom = 0;
int xx;
int yy;
float SizeAnimation = 0;
float SizeIncNum;
string fontcolor = "#FAFAFA";
string Backcolor = "#039BE5";
Color EnabledBGColor;
Color EnabledBorderColor;
Color StringColor;
Color DisabledBGColor = ColorTranslator.FromHtml("#B0BEC5");
Color DisabledStringColor = ColorTranslator.FromHtml("#FAFAFA");
Color NonColor = ColorTranslator.FromHtml("#e3e5e7");
Image bGImage = null;
#endregion
#region Properties
[Category("Custom")]
public string BGColor
{
get { return Backcolor; }
set
{
Backcolor = value;
Invalidate();
}
}
[Category("Custom")]
public string FontColor
{
get { return fontcolor; }
set
{
fontcolor = value;
Invalidate();
}
}
[Browsable(false)]
public Font Font
{
get { return base.Font; }
set { base.Font = value; }
}
[Browsable(false)]
public Color ForeColor
{
get { return base.ForeColor; }
set { base.ForeColor = value; }
}
[Category("Custom")]
public Image BGImage
{
get { return bGImage; }
set { bGImage = value; }
}
ImageSizeLevel bGimgSize = ImageSizeLevel.peque2;
public ImageSizeLevel BGimgSize
{
get { return bGimgSize; }
set { bGimgSize = value; }
}
#endregion
#region Events
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
EnabledBGColor = Color.FromArgb(30, ColorTranslator.FromHtml(BGColor));//StringColor);
EnabledBorderColor = Color.FromArgb(20, ColorTranslator.FromHtml(BGColor));//StringColor);
Refresh();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
EnabledBGColor = ColorTranslator.FromHtml(BGColor);
EnabledBorderColor = ColorTranslator.FromHtml(BGColor);
Refresh();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
EnabledBGColor = Color.FromArgb(30, StringColor);
Refresh();
xx = e.X;
yy = e.Y;
Focus = true;
AnimationTimer.Start();
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
Focus = false;
AnimationTimer.Start();
Invalidate();
}
protected override void OnTextChanged(System.EventArgs e)
{
base.OnTextChanged(e);
Invalidate();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
//StringRectangle = new Rectangle(3, 0, Width - 6, Height - 6);
}
#endregion
protected override void OnResize(System.EventArgs e)
{
base.OnResize(e);
//SizeIncNum = Width / 34;
SizeIncNum = Width / 10;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var G = e.Graphics;
#region Default rectangle
//G.SmoothingMode = SmoothingMode.HighQuality | SmoothingMode.AntiAlias;
//G.Clear(Parent.BackColor);
//StringColor = ColorTranslator.FromHtml(fontcolor);
//var BG = DrawHelper.CreateRoundRect(1, 1, Width - 3, Height - 3, 1);
//Region region = new Region(BG);
//G.FillPath(new SolidBrush(Enabled ? EnabledBGColor : Color.White), BG);
//G.DrawPath(new Pen(Enabled ? EnabledBorderColor : Color.White), BG);
//G.SetClip(region, CombineMode.Replace);
////The Ripple Effect
//G.FillEllipse(new SolidBrush(Color.FromArgb(30, StringColor)), xx - (SizeAnimation / 2), yy - (SizeAnimation / 2), SizeAnimation, SizeAnimation);
//G.DrawString(Text, font.Roboto_Medium10, new SolidBrush(Enabled ? StringColor : DisabledStringColor), R, SF);
#endregion
#region Circle
//G.SmoothingMode = SmoothingMode.AntiAlias;
//G.Clear(BackColor);
//GraphicsPath bgbtn = new GraphicsPath();
//bgbtn.AddEllipse(0, 0, Width - 5, Height - 5);
//GraphicsPath bgShadow = new GraphicsPath();
//bgShadow.AddEllipse(0, 0, Width - 2, Height - 2);
//G.FillPath(new SolidBrush(NonColor), bgShadow);
//G.DrawPath(new Pen(NonColor), bgShadow);
//G.FillPath(new SolidBrush(Color.DeepSkyBlue), bgbtn);
//G.DrawPath(new Pen(Color.DeepSkyBlue), bgbtn);
#endregion
///----------------------------
G.SmoothingMode = SmoothingMode.AntiAlias;
G.Clear(Parent.BackColor);
StringColor = ColorTranslator.FromHtml(fontcolor);
//var BG = DrawHelper.CreateRoundRect(1, 1, Width - 3, Height - 3, 1);
//Círculo principal
GraphicsPath bgbtn = new GraphicsPath();
bgbtn.AddEllipse(2, 0, Width - 6, Height - 6);
//Círculo para la sombra
GraphicsPath bgShadow = new GraphicsPath();
bgShadow.AddEllipse(2, 4, Width - 6, Height - 6);
// se dibuja la sombra
G.FillPath(new SolidBrush(NonColor), bgShadow);
G.DrawPath(new Pen(NonColor), bgShadow);
//sedibuja el círculo principal sobre la sombra
G.FillPath(new SolidBrush(Enabled ? ColorTranslator.FromHtml(BGColor) : DisabledBGColor), bgbtn);
G.DrawPath(new Pen(Enabled ? ColorTranslator.FromHtml(BGColor) : DisabledBGColor), bgbtn);
// Se da a la región forma de círculo/elipse
Region region = new Region(bgbtn);//BG);
G.SetClip(region, CombineMode.Replace);
//The Ripple Effect
if (Enabled)
G.FillEllipse(new SolidBrush(Color.FromArgb(30, EnabledBGColor)), xx - (SizeAnimation / 2), yy - (SizeAnimation / 2), SizeAnimation, SizeAnimation);
StringRectangle = new Rectangle((int)bgbtn.GetBounds().Location.X, (int)bgbtn.GetBounds().Location.Y,
(int)bgbtn.GetBounds().Size.Width, (int)bgbtn.GetBounds().Size.Height);
G.DrawString(Text, font.Roboto_Medium15, new SolidBrush(Enabled ? StringColor : DisabledStringColor), StringRectangle, SF);
if (bGImage != null)
{
float imgX = 0, imgY = 0;
imgY = (bgbtn.GetBounds().Size.Height - (int)bGimgSize) / 2;
imgX = ((bgbtn.GetBounds().Size.Width - (int)bGimgSize) + 2) / 2;
G.DrawImage(bGImage, imgX, imgY, (float)bGimgSize, (float)bGimgSize);
}
}
protected void AnimationTick(object sender, EventArgs e)
{
if (Focus)
{
if (SizeAnimation < Width + 250)
{
SizeAnimation += SizeIncNum;
this.Invalidate();
}
}
else
{
if (SizeAnimation > 0)
{
SizeAnimation = 0;
this.Invalidate();
}
}
}
public enum ImageSizeLevel
{
peque = 12, peque1 = 24, peque2 = 32,
maso = 48, maso1 = 56, maso2 = 64,
grande = 72, grande1 = 86, grande2 = 96,
monstruo = 128, monstruo1 = 256, monstruo2 = 512
}
}
}